From cc61c64bd2758e54a4d0fc98531e4bf001d62c58 Mon Sep 17 00:00:00 2001 From: Ximin Luo Date: Wed, 21 Jun 2017 00:27:43 +0200 Subject: [PATCH] New upstream version 1.18.0+dfsg1 --- CONTRIBUTING.md | 8 +- README.md | 11 +- RELEASES.md | 411 +- configure | 2 + man/rustc.1 | 2 +- rls/.travis.yml | 17 + rls/COPYRIGHT | 40 + rls/Cargo.lock | 1349 ++ rls/Cargo.toml | 28 + rls/LICENSE-APACHE | 201 + rls/LICENSE-MIT | 25 + rls/README.md | 123 + rls/appveyor.yml | 41 + rls/contributing.md | 300 + rls/goto_def.sh | 5 + rls/ls.sh | 6 + rls/src/actions/compiler_message_parsing.rs | 126 + rls/src/actions/lsp_extensions.rs | 62 + rls/src/actions/mod.rs | 532 + rls/src/build.rs | 726 + rls/src/config.rs | 199 + rls/src/lsp_data.rs | 179 + rls/src/main.rs | 60 + rls/src/server.rs | 515 + rls/src/test/mod.rs | 567 + rls/src/test/types.rs | 92 + rls/test_data/borrow_error/Cargo.lock | 4 + rls/test_data/borrow_error/Cargo.toml | 6 + rls/test_data/borrow_error/src/main.rs | 5 + rls/test_data/completion/Cargo.lock | 4 + rls/test_data/completion/Cargo.toml | 6 + rls/test_data/completion/src/main.rs | 26 + rls/test_data/find_all_refs/Cargo.lock | 4 + rls/test_data/find_all_refs/Cargo.toml | 6 + rls/test_data/find_all_refs/src/main.rs | 26 + .../find_all_refs_no_cfg_test/Cargo.lock | 4 + .../find_all_refs_no_cfg_test/Cargo.toml | 6 + .../find_all_refs_no_cfg_test/rls.toml | 1 + .../find_all_refs_no_cfg_test/src/main.rs | 26 + rls/test_data/goto_def/Cargo.lock | 4 + rls/test_data/goto_def/Cargo.toml | 6 + rls/test_data/goto_def/src/main.rs | 26 + rls/test_data/highlight/Cargo.lock | 4 + rls/test_data/highlight/Cargo.toml | 6 + rls/test_data/highlight/src/main.rs | 26 + rls/test_data/hover/Cargo.lock | 4 + rls/test_data/hover/Cargo.toml | 6 + rls/test_data/hover/src/main.rs | 26 + rls/test_data/rename/Cargo.lock | 4 + rls/test_data/rename/Cargo.toml | 6 + rls/test_data/rename/rls.toml | 1 + rls/test_data/rename/src/main.rs | 26 + src/Cargo.lock | 195 +- src/bootstrap/README.md | 4 - src/bootstrap/bin/rustc.rs | 9 +- src/bootstrap/bin/rustdoc.rs | 8 + src/bootstrap/bootstrap.py | 47 +- src/bootstrap/channel.rs | 4 +- src/bootstrap/check.rs | 14 +- src/bootstrap/clean.rs | 52 +- src/bootstrap/compile.rs | 36 +- src/bootstrap/config.rs | 12 +- src/bootstrap/config.toml.example | 4 +- src/bootstrap/dist.rs | 80 +- src/bootstrap/doc.rs | 76 + src/bootstrap/flags.rs | 286 +- src/bootstrap/install.rs | 8 +- src/bootstrap/lib.rs | 43 +- src/bootstrap/native.rs | 28 +- src/bootstrap/sanity.rs | 4 +- src/bootstrap/step.rs | 210 +- src/ci/docker/README.md | 7 +- src/ci/docker/arm-android/Dockerfile | 2 +- src/ci/docker/arm-android/start-emulator.sh | 8 +- src/ci/docker/cross/Dockerfile | 1 + .../Dockerfile | 20 +- .../aarch64-linux-gnu.config | 0 .../dist-aarch64-linux/build-toolchains.sh | 37 + src/ci/docker/dist-android/Dockerfile | 7 +- src/ci/docker/dist-android/install-ndk.sh | 8 +- src/ci/docker/dist-arm-linux/Dockerfile | 17 +- .../docker/dist-arm-linux/build-toolchains.sh | 8 - src/ci/docker/dist-armhf-linux/Dockerfile | 77 + .../arm-linux-gnueabihf.config | 0 .../dist-armhf-linux/build-toolchains.sh | 37 + src/ci/docker/dist-armv7-linux/Dockerfile | 77 + .../armv7-linux-gnueabihf.config | 0 .../build-toolchains.sh | 8 - src/ci/docker/dist-fuchsia/Dockerfile | 2 +- .../docker/dist-i586-gnu-i686-musl/Dockerfile | 3 +- .../dist-i586-gnu-i686-musl/build-musl.sh | 9 +- .../Dockerfile | 7 +- .../build-toolchain.sh | 0 .../Dockerfile | 2 +- .../build-binutils.sh | 0 .../build-cmake.sh | 0 .../build-curl.sh | 0 .../build-gcc.sh | 12 +- .../build-git.sh | 0 .../build-headers.sh | 0 .../build-openssl.sh | 5 +- .../build-python.sh | 0 .../shared.sh | 0 src/ci/docker/dist-mips-linux/Dockerfile | 2 - src/ci/docker/dist-mips64-linux/Dockerfile | 2 - src/ci/docker/dist-mips64el-linux/Dockerfile | 31 + src/ci/docker/dist-mipsel-linux/Dockerfile | 31 + src/ci/docker/dist-powerpc-linux/Dockerfile | 8 +- .../powerpc-linux-gnu.config | 8 +- src/ci/docker/dist-powerpc64-linux/Dockerfile | 18 +- .../docker/dist-powerpc64le-linux/Dockerfile | 77 + .../build-powerpc64le-toolchain.sh | 0 .../docker/dist-powerpc64le-linux/shared.sh | 25 + .../build-netbsd-toolchain.sh | 120 - .../Dockerfile | 15 +- .../build-s390x-toolchain.sh | 0 ...prevent-AS-from-complaining-about-z9.patch | 0 .../s390x-linux-gnu.config | 0 src/ci/docker/dist-x86_64-freebsd/Dockerfile | 39 + .../dist-x86_64-freebsd/build-toolchain.sh | 112 + src/ci/docker/dist-x86_64-linux/Dockerfile | 101 + .../dist-x86_64-linux/build-binutils.sh | 26 + .../docker/dist-x86_64-linux/build-cmake.sh | 25 + src/ci/docker/dist-x86_64-linux/build-curl.sh | 43 + src/ci/docker/dist-x86_64-linux/build-gcc.sh | 33 + src/ci/docker/dist-x86_64-linux/build-git.sh | 24 + .../docker/dist-x86_64-linux/build-headers.sh | 25 + .../docker/dist-x86_64-linux/build-openssl.sh | 28 + .../docker/dist-x86_64-linux/build-python.sh | 30 + src/ci/docker/dist-x86_64-linux/shared.sh | 25 + src/ci/docker/dist-x86_64-musl/Dockerfile | 3 +- src/ci/docker/dist-x86_64-musl/build-musl.sh | 2 +- src/ci/docker/dist-x86_64-netbsd/Dockerfile | 78 + .../build-netbsd-toolchain.sh | 83 + src/ci/docker/run.sh | 3 +- src/ci/init_repo.sh | 86 + src/ci/run.sh | 1 - src/ci/shared.sh | 9 +- src/compiler-rt/lib/builtins/int_lib.h | 2 +- src/doc/book/.github/ISSUE_TEMPLATE.md | 26 + src/doc/book/.github/PULL_REQUEST_TEMPLATE.md | 24 + src/doc/book/.travis.yml | 22 + src/doc/book/CONTRIBUTING.md | 96 + src/doc/book/COPYRIGHT | 290 + src/doc/book/LICENSE-APACHE | 201 + src/doc/book/LICENSE-MIT | 25 + src/doc/book/README.md | 127 + src/doc/book/ci/build.sh | 29 + src/doc/book/ci/deploy.sh | 50 + src/doc/book/ci/stable-check/Cargo.lock | 4 + src/doc/book/ci/stable-check/Cargo.toml | 6 + src/doc/book/ci/stable-check/src/main.rs | 53 + src/doc/book/first-edition/book.toml | 2 + .../book/{ => first-edition}/src/README.md | 0 .../book/{ => first-edition}/src/SUMMARY.md | 0 .../src/associated-types.md | 0 .../{ => first-edition}/src/attributes.md | 2 +- .../{ => first-edition}/src/bibliography.md | 1 + .../src/borrow-and-asref.md | 8 +- .../src/casting-between-types.md | 0 .../book/{ => first-edition}/src/chapter_1.md | 0 .../src/choosing-your-guarantees.md | 18 +- .../book/{ => first-edition}/src/closures.md | 23 +- .../book/{ => first-edition}/src/comments.md | 0 .../{ => first-edition}/src/concurrency.md | 10 +- .../src/conditional-compilation.md | 0 .../src/const-and-static.md | 0 .../src/crates-and-modules.md | 27 +- .../src/deref-coercions.md | 2 +- .../{ => first-edition}/src/documentation.md | 23 +- src/doc/book/{ => first-edition}/src/drop.md | 4 +- .../{ => first-edition}/src/effective-rust.md | 0 src/doc/book/{ => first-edition}/src/enums.md | 0 .../{ => first-edition}/src/error-handling.md | 116 +- src/doc/book/{ => first-edition}/src/ffi.md | 43 +- .../book/{ => first-edition}/src/functions.md | 0 .../book/{ => first-edition}/src/generics.md | 4 +- .../src/getting-started.md | 0 .../book/{ => first-edition}/src/glossary.md | 2 +- .../{ => first-edition}/src/guessing-game.md | 22 +- .../book/{ => first-edition}/src/if-let.md | 0 src/doc/book/{ => first-edition}/src/if.md | 0 .../book/{ => first-edition}/src/iterators.md | 7 +- .../book/{ => first-edition}/src/lifetimes.md | 0 src/doc/book/{ => first-edition}/src/loops.md | 18 +- .../book/{ => first-edition}/src/macros.md | 9 +- src/doc/book/{ => first-edition}/src/match.md | 0 .../{ => first-edition}/src/method-syntax.md | 0 .../{ => first-edition}/src/mutability.md | 6 +- .../src/operators-and-overloading.md | 4 +- .../book/{ => first-edition}/src/ownership.md | 0 .../book/{ => first-edition}/src/patterns.md | 0 .../src/primitive-types.md | 36 +- .../src/procedural-macros.md | 2 +- .../{ => first-edition}/src/raw-pointers.md | 2 +- .../src/references-and-borrowing.md | 0 .../src/release-channels.md | 0 .../book/{ => first-edition}/src/strings.md | 2 +- .../book/{ => first-edition}/src/structs.md | 0 .../src/syntax-and-semantics.md | 0 .../{ => first-edition}/src/syntax-index.md | 8 +- .../book/{ => first-edition}/src/testing.md | 2 +- .../src/the-stack-and-the-heap.md | 2 +- .../{ => first-edition}/src/trait-objects.md | 2 +- .../book/{ => first-edition}/src/traits.md | 26 +- .../{ => first-edition}/src/type-aliases.md | 2 +- src/doc/book/{ => first-edition}/src/ufcs.md | 0 .../book/{ => first-edition}/src/unsafe.md | 2 +- .../{ => first-edition}/src/unsized-types.md | 0 ...using-rust-without-the-standard-library.md | 8 +- .../src/variable-bindings.md | 2 +- .../book/{ => first-edition}/src/vectors.md | 8 +- src/doc/book/index.md | 11 + src/doc/book/redirects/README.md | 13 + src/doc/book/redirects/SUMMARY.md | 13 + src/doc/book/redirects/associated-types.md | 13 + src/doc/book/redirects/attributes.md | 13 + src/doc/book/redirects/bibliography.md | 13 + src/doc/book/redirects/borrow-and-asref.md | 13 + .../book/redirects/casting-between-types.md | 13 + .../redirects/choosing-your-guarantees.md | 13 + src/doc/book/redirects/closures.md | 13 + src/doc/book/redirects/comments.md | 13 + src/doc/book/redirects/compiler-plugins.md | 6 + src/doc/book/redirects/concurrency.md | 13 + .../book/redirects/conditional-compilation.md | 13 + src/doc/book/redirects/const-and-static.md | 13 + src/doc/book/redirects/crates-and-modules.md | 13 + src/doc/book/redirects/deref-coercions.md | 13 + src/doc/book/redirects/documentation.md | 13 + src/doc/book/redirects/drop.md | 13 + src/doc/book/redirects/effective-rust.md | 13 + src/doc/book/redirects/enums.md | 13 + src/doc/book/redirects/error-handling.md | 13 + src/doc/book/redirects/ffi.md | 13 + src/doc/book/redirects/functions.md | 13 + src/doc/book/redirects/generics.md | 13 + src/doc/book/redirects/getting-started.md | 13 + src/doc/book/redirects/glossary.md | 13 + src/doc/book/redirects/guessing-game.md | 13 + src/doc/book/redirects/if-let.md | 13 + src/doc/book/redirects/if.md | 13 + src/doc/book/redirects/iterators.md | 13 + src/doc/book/redirects/lifetimes.md | 13 + src/doc/book/redirects/loops.md | 13 + src/doc/book/redirects/macros.md | 13 + src/doc/book/redirects/match.md | 13 + src/doc/book/redirects/method-syntax.md | 13 + src/doc/book/redirects/mutability.md | 13 + .../redirects/operators-and-overloading.md | 13 + src/doc/book/redirects/ownership.md | 13 + src/doc/book/redirects/patterns.md | 13 + src/doc/book/redirects/primitive-types.md | 13 + src/doc/book/redirects/procedural-macros.md | 13 + src/doc/book/redirects/raw-pointers.md | 13 + .../redirects/references-and-borrowing.md | 13 + src/doc/book/redirects/release-channels.md | 13 + src/doc/book/redirects/strings.md | 13 + src/doc/book/redirects/structs.md | 13 + .../book/redirects/syntax-and-semantics.md | 13 + src/doc/book/redirects/syntax-index.md | 13 + src/doc/book/redirects/testing.md | 13 + .../book/redirects/the-stack-and-the-heap.md | 13 + src/doc/book/redirects/trait-objects.md | 13 + src/doc/book/redirects/traits.md | 13 + src/doc/book/redirects/type-aliases.md | 13 + src/doc/book/redirects/ufcs.md | 13 + src/doc/book/redirects/unsafe.md | 13 + src/doc/book/redirects/unsized-types.md | 13 + ...using-rust-without-the-standard-library.md | 13 + src/doc/book/redirects/variable-bindings.md | 13 + src/doc/book/redirects/vectors.md | 13 + src/doc/book/second-edition/Cargo.lock | 142 + src/doc/book/second-edition/Cargo.toml | 32 + src/doc/book/second-edition/LICENSE-APACHE | 201 + src/doc/book/second-edition/LICENSE-MIT | 25 + src/doc/book/second-edition/book.toml | 2 + src/doc/book/second-edition/dictionary.txt | 358 + src/doc/book/second-edition/doc-to-md.sh | 29 + src/doc/book/second-edition/dot/trpl04-01.dot | 25 + src/doc/book/second-edition/dot/trpl04-02.dot | 34 + src/doc/book/second-edition/dot/trpl04-03.dot | 43 + src/doc/book/second-edition/dot/trpl04-04.dot | 34 + src/doc/book/second-edition/dot/trpl04-05.dot | 31 + src/doc/book/second-edition/dot/trpl04-06.dot | 40 + src/doc/book/second-edition/dot/trpl15-01.dot | 23 + src/doc/book/second-edition/dot/trpl15-02.dot | 17 + src/doc/book/second-edition/dot/trpl15-03.dot | 50 + src/doc/book/second-edition/nostarch.sh | 33 + .../book/second-edition/nostarch/appendix.md | 63 + .../book/second-edition/nostarch/chapter01.md | 516 + .../book/second-edition/nostarch/chapter02.md | 1048 ++ .../book/second-edition/nostarch/chapter03.md | 1469 ++ .../book/second-edition/nostarch/chapter04.md | 1244 ++ .../book/second-edition/nostarch/chapter05.md | 615 + .../book/second-edition/nostarch/chapter06.md | 772 + .../book/second-edition/nostarch/chapter07.md | 1098 ++ .../book/second-edition/nostarch/chapter08.md | 932 + .../book/second-edition/nostarch/chapter09.md | 935 + .../book/second-edition/nostarch/chapter10.md | 1879 ++ .../book/second-edition/nostarch/chapter11.md | 1500 ++ .../book/second-edition/nostarch/chapter12.md | 1979 +++ .../book/second-edition/nostarch/chapter13.md | 799 + .../book/second-edition/nostarch/chapter14.md | 727 + .../book/second-edition/nostarch/chapter15.md | 1384 ++ .../book/second-edition/nostarch/chapter16.md | 1253 ++ .../book/second-edition/nostarch/chapter17.md | 1298 ++ .../book/second-edition/nostarch/chapter18.md | 1054 ++ .../second-edition/nostarch/odt/chapter02.doc | Bin 0 -> 218624 bytes .../nostarch/odt/chapter03.docx | Bin 0 -> 71651 bytes .../nostarch/odt/chapter04.docx | Bin 0 -> 325348 bytes .../second-edition/nostarch/odt/chapter05.odt | Bin 0 -> 49310 bytes .../nostarch/odt/chapter06.docx | Bin 0 -> 49580 bytes .../nostarch/odt/chapter07.docx | Bin 0 -> 38686 bytes .../nostarch/odt/chapter08.docx | Bin 0 -> 41633 bytes .../nostarch/odt/chapter09.docx | Bin 0 -> 47156 bytes src/doc/book/second-edition/spellcheck.sh | 101 + src/doc/book/second-edition/src/SUMMARY.md | 123 + .../book/second-edition/src/appendix-00.md | 4 + .../src/appendix-01-keywords.md | 70 + .../src/appendix-02-operators.md | 195 + .../src/appendix-06-translation.md | 11 + .../src/appendix-07-newest-features.md | 35 + .../src/ch01-00-introduction.md | 35 + .../src/ch01-01-installation.md | 107 + .../second-edition/src/ch01-02-hello-world.md | 405 + .../src/ch02-00-guessing-game-tutorial.md | 1064 ++ .../ch03-00-common-programming-concepts.md | 20 + .../src/ch03-01-variables-and-mutability.md | 224 + .../second-edition/src/ch03-02-data-types.md | 367 + .../src/ch03-03-how-functions-work.md | 343 + .../second-edition/src/ch03-04-comments.md | 46 + .../src/ch03-05-control-flow.md | 450 + .../src/ch04-00-understanding-ownership.md | 7 + .../src/ch04-01-what-is-ownership.md | 548 + .../src/ch04-02-references-and-borrowing.md | 316 + .../book/second-edition/src/ch04-03-slices.md | 379 + .../second-edition/src/ch05-00-structs.md | 393 + .../src/ch05-01-method-syntax.md | 253 + .../book/second-edition/src/ch06-00-enums.md | 15 + .../src/ch06-01-defining-an-enum.md | 400 + .../book/second-edition/src/ch06-02-match.md | 299 + .../book/second-edition/src/ch06-03-if-let.md | 118 + .../second-edition/src/ch07-00-modules.md | 24 + .../src/ch07-01-mod-and-the-filesystem.md | 464 + ...ch07-02-controlling-visibility-with-pub.md | 296 + .../src/ch07-03-importing-names-with-use.md | 272 + .../src/ch08-00-common-collections.md | 25 + .../second-edition/src/ch08-01-vectors.md | 225 + .../second-edition/src/ch08-02-strings.md | 413 + .../second-edition/src/ch08-03-hash-maps.md | 272 + .../src/ch09-00-error-handling.md | 23 + ...ch09-01-unrecoverable-errors-with-panic.md | 179 + .../ch09-02-recoverable-errors-with-result.md | 452 + .../src/ch09-03-to-panic-or-not-to-panic.md | 246 + .../second-edition/src/ch10-00-generics.md | 188 + .../book/second-edition/src/ch10-01-syntax.md | 448 + .../book/second-edition/src/ch10-02-traits.md | 474 + .../src/ch10-03-lifetime-syntax.md | 798 + .../second-edition/src/ch11-00-testing.md | 34 + .../src/ch11-01-writing-tests.md | 804 + .../src/ch11-02-running-tests.md | 329 + .../src/ch11-03-test-organization.md | 338 + .../src/ch12-00-an-io-project.md | 63 + ...h12-01-accepting-command-line-arguments.md | 180 + .../src/ch12-02-reading-a-file.md | 113 + ...improving-error-handling-and-modularity.md | 802 + ...2-04-testing-the-librarys-functionality.md | 365 + ...2-05-working-with-environment-variables.md | 343 + ...-06-writing-to-stderr-instead-of-stdout.md | 152 + .../src/ch13-00-functional-features.md | 21 + .../second-edition/src/ch13-01-closures.md | 233 + .../second-edition/src/ch13-02-iterators.md | 268 + .../src/ch13-03-improving-our-io-project.md | 190 + .../second-edition/src/ch13-04-performance.md | 85 + .../src/ch14-00-more-about-cargo.md | 15 + .../src/ch14-01-release-profiles.md | 57 + .../src/ch14-02-publishing-to-crates-io.md | 372 + .../src/ch14-03-cargo-workspaces.md | 207 + .../src/ch14-04-installing-binaries.md | 29 + .../src/ch14-05-extending-cargo.md | 16 + .../src/ch15-00-smart-pointers.md | 41 + .../book/second-edition/src/ch15-01-box.md | 207 + .../book/second-edition/src/ch15-02-deref.md | 193 + .../book/second-edition/src/ch15-03-drop.md | 140 + src/doc/book/second-edition/src/ch15-04-rc.md | 187 + .../src/ch15-05-interior-mutability.md | 256 + .../src/ch15-06-reference-cycles.md | 401 + .../second-edition/src/ch16-00-concurrency.md | 46 + .../second-edition/src/ch16-01-threads.md | 362 + .../src/ch16-02-message-passing.md | 331 + .../src/ch16-03-shared-state.md | 440 + ...04-extensible-concurrency-sync-and-send.md | 88 + .../book/second-edition/src/ch17-00-oop.md | 8 + .../second-edition/src/ch17-01-what-is-oo.md | 191 + .../src/ch17-02-trait-objects.md | 477 + .../src/ch17-03-oo-design-patterns.md | 693 + .../second-edition/src/ch18-00-patterns.md | 19 + .../ch18-01-all-the-places-for-patterns.md | 249 + .../src/ch18-02-refutability.md | 98 + .../src/ch18-03-pattern-syntax.md | 697 + .../src/ch19-00-advanced-features.md | 23 + .../second-edition/src/ch19-01-unsafe-rust.md | 490 + .../src/ch19-02-advanced-lifetimes.md | 406 + .../src/ch19-03-advanced-traits.md | 592 + .../src/ch19-04-advanced-types.md | 343 + ...ch19-05-advanced-functions-and-closures.md | 135 + .../src/ch20-00-final-project-a-web-server.md | 3 + .../book/second-edition/src/img/trpl04-01.svg | 65 + .../book/second-edition/src/img/trpl04-02.svg | 90 + .../book/second-edition/src/img/trpl04-03.svg | 117 + .../book/second-edition/src/img/trpl04-04.svg | 91 + .../book/second-edition/src/img/trpl04-05.svg | 82 + .../book/second-edition/src/img/trpl04-06.svg | 110 + .../book/second-edition/src/img/trpl15-01.svg | 42 + .../book/second-edition/src/img/trpl15-02.svg | 25 + .../book/second-edition/src/img/trpl15-03.svg | 94 + .../book/second-edition/src/img/trpl15-04.svg | 55 + src/doc/book/second-edition/style-guide.md | 34 + src/doc/book/second-edition/theme/index.hbs | 159 + .../book/second-edition/tools/docx-to-md.xsl | 188 + .../tools/src/bin/concat_chapters.rs | 114 + .../book/second-edition/tools/src/bin/lfp.rs | 261 + .../tools/src/bin/link2print.rs | 419 + .../tools/src/bin/remove_links.rs | 55 + .../tools/src/bin/remove_markup.rs | 61 + src/doc/book/src/compiler-plugins.md | 253 - src/doc/grammar.md | 12 +- src/doc/guide-plugins.md | 2 +- src/doc/index.md | 6 +- src/doc/nomicon/.travis.yml | 11 + src/doc/nomicon/README.md | 70 + src/doc/reference/.travis.yml | 11 + src/doc/reference/book.toml | 2 + src/doc/reference/src/SUMMARY.md | 4 +- src/doc/reference/src/attributes.md | 198 +- src/doc/reference/src/expressions.md | 80 +- src/doc/reference/src/introduction.md | 5 + src/doc/reference/src/items.md | 9 +- src/doc/reference/src/linkage.md | 80 + src/doc/reference/src/macros.md | 2 +- src/doc/reference/src/paths.md | 2 +- src/doc/reference/src/subtyping.md | 2 +- src/doc/reference/src/tokens.md | 8 +- src/doc/reference/src/types.md | 18 +- src/doc/reference/src/undocumented.md | 36 + src/doc/reference/src/variables.md | 2 +- .../reference/src/visibility-and-privacy.md | 72 +- src/doc/reference/stable-check/Cargo.lock | 4 + src/doc/reference/stable-check/Cargo.toml | 6 + src/doc/reference/stable-check/src/main.rs | 55 + src/doc/rust.md | 2 +- src/doc/unstable-book/src/SUMMARY.md | 306 +- .../unstable-book/src/abi-msp430-interrupt.md | 7 - src/doc/unstable-book/src/abi-ptx.md | 5 - .../unstable-book/src/compiler-builtins.md | 6 - src/doc/unstable-book/src/compiler-flags.md | 1 + .../src/compiler-flags/linker-flavor.md | 61 + .../src/conservative-impl-trait.md | 10 - src/doc/unstable-book/src/const-fn.md | 10 - src/doc/unstable-book/src/const-indexing.md | 10 - .../unstable-book/src/field-init-shorthand.md | 10 - .../unstable-book/src/language-features.md | 1 + .../language-features/abi-msp430-interrupt.md | 42 + .../src/language-features/abi-ptx.md | 60 + .../src/{ => language-features}/abi-sysv64.md | 0 .../{ => language-features}/abi-unadjusted.md | 0 .../{ => language-features}/abi-vectorcall.md | 0 .../abi-x86-interrupt.md | 0 .../advanced-slice-patterns.md | 0 .../src/{ => language-features}/allocator.md | 5 + .../allow-internal-unstable.md | 0 .../src/{ => language-features}/asm.md | 2 + .../associated-consts.md | 0 .../associated-type-defaults.md | 0 .../{ => language-features}/attr-literals.md | 0 .../{ => language-features}/box-patterns.md | 0 .../src/{ => language-features}/box-syntax.md | 0 .../src/language-features/catch-expr.md | 7 + .../cfg-target-feature.md | 0 .../cfg-target-has-atomic.md | 0 .../cfg-target-thread-local.md | 0 .../cfg-target-vendor.md | 0 .../closure-to-fn-coercion.md | 7 + .../language-features/compiler-builtins.md | 5 + .../src/language-features/concat-idents.md | 22 + .../conservative-impl-trait.md | 66 + .../src/language-features/const-fn.md | 29 + .../src/language-features/const-indexing.md | 19 + .../custom-attribute.md | 0 .../{ => language-features}/custom-derive.md | 0 .../default-type-parameter-fallback.md | 0 .../drop-types-in-const.md | 0 .../dropck-eyepatch.md | 0 .../dropck-parametricity.md | 0 .../exclusive-range-pattern.md | 0 .../{ => language-features}/fundamental.md | 0 .../generic-param-attrs.md | 0 .../src/language-features/global_asm.md | 78 + .../src/language-features/i128-type.md | 25 + .../inclusive-range-syntax.md | 20 + .../src/{ => language-features}/intrinsics.md | 0 .../src/{ => language-features}/lang-items.md | 0 .../src/{ => language-features}/link-args.md | 0 .../src/{ => language-features}/link-cfg.md | 0 .../link-llvm-intrinsics.md | 0 .../src/{ => language-features}/linkage.md | 0 .../src/{ => language-features}/log-syntax.md | 0 .../loop-break-value.md | 0 .../{ => language-features}/macro-reexport.md | 0 .../language-features/macro-vis-matcher.md | 14 + .../src/{ => language-features}/main.md | 0 .../naked-functions.md | 0 .../needs-allocator.md | 0 .../needs-panic-runtime.md | 0 .../src/{ => language-features}/never-type.md | 0 .../src/{ => language-features}/no-core.md | 0 .../src/{ => language-features}/no-debug.md | 0 .../src/language-features/non-ascii-idents.md | 18 + .../omit-gdb-pretty-printer-section.md | 0 .../on-unimplemented.md | 0 .../optin-builtin-traits.md | 0 .../overlapping-marker-traits.md | 7 + .../{ => language-features}/panic-runtime.md | 0 .../placement-in-syntax.md | 0 .../platform-intrinsics.md | 0 .../plugin-registrar.md | 0 .../src/{ => language-features}/plugin.md | 2 +- .../{ => language-features}/prelude-import.md | 0 .../src/{ => language-features}/proc-macro.md | 0 .../src/{ => language-features}/quote.md | 0 .../{ => language-features}/relaxed-adts.md | 0 .../src/language-features/repr-align.md | 11 + .../src/{ => language-features}/repr-simd.md | 0 .../{ => language-features}/rustc-attrs.md | 0 .../rustc-diagnostic-macros.md | 0 .../rvalue-static-promotion.md | 23 + .../sanitizer-runtime.md | 0 .../src/{ => language-features}/simd-ffi.md | 0 .../src/{ => language-features}/simd.md | 0 .../{ => language-features}/slice-patterns.md | 0 .../{ => language-features}/specialization.md | 2 + .../src/{ => language-features}/staged-api.md | 0 .../src/{ => language-features}/start.md | 0 .../static-nobundle.md | 0 .../stmt-expr-attributes.md | 0 .../struct-field-attributes.md | 0 .../structural-match.md | 0 .../{ => language-features}/target-feature.md | 0 .../{ => language-features}/thread-local.md | 0 .../{ => language-features}/trace-macros.md | 0 .../type-ascription.md | 0 .../unboxed-closures.md | 0 .../untagged-unions.md | 0 .../unwind-attributes.md | 0 .../use-extern-macros.md | 0 .../src/language-features/used.md | 153 + src/doc/unstable-book/src/library-features.md | 1 + .../{ => library-features}/alloc-jemalloc.md | 0 .../{ => library-features}/alloc-system.md | 0 .../src/library-features/alloc.md | 7 + .../src/library-features/as-c-str.md | 8 + .../src/library-features/ascii-ctype.md | 5 + .../src/library-features/box-heap.md | 7 + .../src/library-features/c-void-variant.md | 5 + .../src/library-features/char-escape-debug.md | 7 + .../src/library-features/coerce-unsized.md | 7 + .../library-features/collection-placement.md | 7 + .../src/library-features/collections-range.md | 7 + .../src/library-features/collections.md | 5 + .../src/library-features/command-envs.md | 7 + .../library-features/compiler-builtins-lib.md | 35 + .../src/library-features/compiler-fences.md | 106 + .../concat-idents-macro.md} | 5 +- .../src/library-features/core-char-ext.md | 7 + .../src/library-features/core-float.md | 7 + .../src/library-features/core-intrinsics.md | 5 + .../src/library-features/core-panic.md | 5 + .../library-features/core-private-bignum.md | 5 + .../core-private-diy-float.md | 5 + .../src/library-features/core-slice-ext.md | 7 + .../src/library-features/core-str-ext.md | 7 + .../src/library-features/dec2flt.md | 5 + .../src/library-features/decode-utf8.md | 7 + .../src/library-features/derive-clone-copy.md | 5 + .../src/library-features/derive-eq.md | 5 + .../library-features/discriminant-value.md | 7 + .../src/library-features/error-type-id.md | 7 + .../library-features/exact-size-is-empty.md | 7 + .../src/library-features/fd-read.md | 5 + .../unstable-book/src/library-features/fd.md | 5 + .../src/library-features/fixed-size-array.md | 7 + .../src/library-features/float-bits-conv.md | 7 + .../src/library-features/flt2dec.md | 5 + .../src/library-features/fmt-flags-align.md | 7 + .../src/library-features/fmt-internals.md | 5 + .../src/library-features/fn-traits.md | 7 + .../src/library-features/fnbox.md | 7 + .../from_utf8_error_as_bytes.md | 7 + .../src/library-features/fused.md | 7 + .../future-atomic-orderings.md | 5 + .../src/library-features/get-type-id.md | 7 + .../src/library-features/heap-api.md | 7 + .../i128.md} | 5 +- .../inclusive-range.md} | 5 +- .../library-features/int-error-internals.md | 5 + .../src/library-features/integer-atomics.md | 7 + .../src/library-features/into-boxed-c-str.md | 7 + .../src/library-features/into-boxed-os-str.md | 7 + .../src/library-features/into-boxed-path.md | 7 + .../library-features/io-error-internals.md | 5 + .../unstable-book/src/library-features/io.md | 7 + .../unstable-book/src/library-features/ip.md | 7 + .../src/library-features/iter-rfind.md | 7 + .../library-features/libstd-io-internals.md | 5 + .../library-features/libstd-sys-internals.md | 5 + .../libstd-thread-internals.md | 5 + .../library-features/linked-list-extras.md | 7 + .../src/library-features/lookup-host.md | 7 + .../src/library-features/manually-drop.md} | 0 .../src/library-features/mpsc-select.md | 5 + .../unstable-book/src/library-features/n16.md | 5 + .../src/library-features/never-type-impls.md | 7 + .../src/library-features/nonzero.md | 7 + .../src/library-features/offset-to.md | 7 + .../src/library-features/once-poison.md | 7 + .../unstable-book/src/library-features/oom.md | 7 + .../src/library-features/option-entry.md | 7 + .../osstring-shrink-to-fit.md | 7 + .../src/library-features/panic-abort.md | 7 + .../src/library-features/panic-unwind.md | 7 + .../src/library-features/pattern.md | 7 + .../src/library-features/placement-in.md | 7 + .../placement-new-protocol.md | 7 + .../src/library-features/print.md | 5 + .../library-features/proc-macro-internals.md | 7 + .../library-features/question-mark-carrier.md | 7 + .../src/library-features/rand.md | 5 + .../src/library-features/range-contains.md | 7 + .../unstable-book/src/library-features/raw.md | 7 + .../src/library-features/reverse-cmp-key.md | 7 + .../unstable-book/src/library-features/rt.md | 5 + .../src/library-features/rustc-private.md | 7 + .../library-features/sanitizer-runtime-lib.md | 5 + .../src/library-features/set-stdio.md | 5 + .../src/library-features/shared.md | 7 + .../src/library-features/sip-hash-13.md | 7 + .../src/library-features/slice-concat-ext.md | 7 + .../src/library-features/slice-get-slice.md | 7 + .../src/library-features/slice-rsplit.md | 10 + .../src/library-features/sort-internals.md | 5 + .../src/library-features/sort-unstable.md | 40 + .../src/library-features/step-by.md | 7 + .../src/library-features/step-trait.md | 7 + .../library-features/str-checked-slicing.md | 7 + .../src/library-features/str-escape.md | 7 + .../src/library-features/str-internals.md | 5 + .../src/library-features/str-mut-extras.md | 8 + .../src/{ => library-features}/test.md | 0 .../src/library-features/thread-id.md | 7 + .../thread-local-internals.md | 5 + .../library-features/thread-local-state.md | 7 + .../library-features/toowned-clone-into.md | 7 + .../src/library-features/trusted-len.md | 7 + .../src/library-features/try-from.md | 7 + .../src/library-features/unicode.md | 7 + .../src/library-features/unique.md | 7 + .../src/library-features/unsize.md | 7 + .../library-features/update-panic-count.md | 5 + .../library-features/utf8-error-error-len.md | 7 + .../src/library-features/vec-remove-item.md | 7 + .../src/library-features/windows-c.md | 5 + .../src/library-features/windows-handle.md | 5 + .../src/library-features/windows-net.md | 5 + .../src/library-features/windows-stdio.md | 5 + src/doc/unstable-book/src/non-ascii-idents.md | 10 - src/doc/unstable-book/src/pub-restricted.md | 10 - src/doc/unstable-book/src/static-recursion.md | 10 - .../unstable-book/src/the-unstable-book.md | 2 +- .../unstable-book/src/windows-subsystem.md | 10 - src/etc/char_private.py | 132 +- src/etc/make-win-dist.py | 3 +- src/etc/natvis/libcollections.natvis | 8 +- src/etc/rust-gdb | 5 +- src/grammar/verify.rs | 6 +- src/liballoc/arc.rs | 68 +- src/liballoc/heap.rs | 40 +- src/liballoc/lib.rs | 1 + src/liballoc/raw_vec.rs | 17 +- src/liballoc/rc.rs | 126 +- src/liballoc_jemalloc/build.rs | 2 +- src/liballoc_jemalloc/lib.rs | 33 +- src/liballoc_system/lib.rs | 34 +- src/libcollections/Cargo.toml | 4 +- src/libcollections/benches/lib.rs | 1 + src/libcollections/benches/slice.rs | 110 +- src/libcollections/binary_heap.rs | 123 +- src/libcollections/borrow.rs | 38 + src/libcollections/btree/map.rs | 96 +- src/libcollections/btree/set.rs | 59 +- src/libcollections/enum_set.rs | 312 - src/libcollections/fmt.rs | 7 +- src/libcollections/lib.rs | 52 +- src/libcollections/linked_list.rs | 45 +- src/libcollections/range.rs | 10 +- src/libcollections/slice.rs | 320 +- src/libcollections/str.rs | 255 +- src/libcollections/string.rs | 134 +- .../tests}/binary_heap.rs | 37 - .../tests}/btree/map.rs | 0 .../tests}/btree/mod.rs | 0 .../tests}/btree/set.rs | 0 .../tests}/cow_str.rs | 10 + .../tests}/fmt.rs | 0 .../tests}/lib.rs | 3 +- .../tests}/linked_list.rs | 0 .../tests}/slice.rs | 28 +- .../tests}/str.rs | 30 + .../tests}/string.rs | 0 .../tests}/vec.rs | 38 + .../tests}/vec_deque.rs | 0 src/libcollections/vec.rs | 268 +- src/libcollections/vec_deque.rs | 91 +- src/libcompiler_builtins/lib.rs | 20 +- src/libcore/Cargo.toml | 4 +- src/libcore/any.rs | 2 +- src/libcore/cell.rs | 98 +- src/libcore/char.rs | 33 +- src/libcore/char_private.rs | 1238 +- src/libcore/clone.rs | 4 +- src/libcore/cmp.rs | 54 +- src/libcore/convert.rs | 209 +- src/libcore/fmt/mod.rs | 31 +- src/libcore/fmt/num.rs | 5 +- src/libcore/hash/mod.rs | 241 +- src/libcore/intrinsics.rs | 116 +- src/libcore/iter/iterator.rs | 90 +- src/libcore/iter/mod.rs | 132 +- src/libcore/iter/sources.rs | 22 +- src/libcore/iter/traits.rs | 58 +- src/libcore/iter_private.rs | 2 +- src/libcore/lib.rs | 12 +- src/libcore/macros.rs | 68 +- src/libcore/marker.rs | 21 +- src/libcore/mem.rs | 132 +- src/libcore/num/bignum.rs | 8 +- src/libcore/num/dec2flt/algorithm.rs | 42 +- src/libcore/num/dec2flt/mod.rs | 20 +- src/libcore/num/dec2flt/rawfp.rs | 238 +- src/libcore/num/diy_float.rs | 2 +- src/libcore/num/f32.rs | 45 - src/libcore/num/f64.rs | 45 - src/libcore/num/flt2dec/decoder.rs | 4 +- src/libcore/num/flt2dec/mod.rs | 2 +- src/libcore/num/mod.rs | 266 +- src/libcore/ops.rs | 78 +- src/libcore/option.rs | 41 +- src/libcore/ptr.rs | 125 +- src/libcore/raw.rs | 2 +- src/libcore/result.rs | 6 +- src/libcore/{slice.rs => slice/mod.rs} | 364 +- src/libcore/slice/sort.rs | 703 + src/libcore/str/mod.rs | 624 +- src/libcore/sync/atomic.rs | 170 +- src/{libcoretest => libcore/tests}/any.rs | 0 src/{libcoretest => libcore/tests}/array.rs | 0 src/{libcoretest => libcore/tests}/atomic.rs | 15 +- src/{libcoretest => libcore/tests}/cell.rs | 0 src/{libcoretest => libcore/tests}/char.rs | 0 src/{libcoretest => libcore/tests}/clone.rs | 0 src/{libcoretest => libcore/tests}/cmp.rs | 0 .../tests}/fmt/builders.rs | 0 .../tests}/fmt/float.rs | 0 src/{libcoretest => libcore/tests}/fmt/mod.rs | 0 src/{libcoretest => libcore/tests}/fmt/num.rs | 0 .../tests}/hash/mod.rs | 0 .../tests}/hash/sip.rs | 0 .../tests}/intrinsics.rs | 0 src/{libcoretest => libcore/tests}/iter.rs | 0 src/{libcoretest => libcore/tests}/lib.rs | 5 +- src/{libcoretest => libcore/tests}/mem.rs | 0 src/{libcoretest => libcore/tests}/nonzero.rs | 0 .../tests}/num/bignum.rs | 0 .../tests}/num/dec2flt/mod.rs | 0 .../tests}/num/dec2flt/parse.rs | 0 .../tests}/num/dec2flt/rawfp.rs | 47 +- .../tests}/num/flt2dec/estimator.rs | 0 .../tests}/num/flt2dec/mod.rs | 0 .../tests}/num/flt2dec/strategy/dragon.rs | 0 .../tests}/num/flt2dec/strategy/grisu.rs | 0 src/{libcoretest => libcore/tests}/num/i16.rs | 0 src/{libcoretest => libcore/tests}/num/i32.rs | 0 src/{libcoretest => libcore/tests}/num/i64.rs | 0 src/{libcoretest => libcore/tests}/num/i8.rs | 0 .../tests}/num/int_macros.rs | 0 src/{libcoretest => libcore/tests}/num/mod.rs | 0 src/{libcoretest => libcore/tests}/num/u16.rs | 0 src/{libcoretest => libcore/tests}/num/u32.rs | 0 src/{libcoretest => libcore/tests}/num/u64.rs | 0 src/{libcoretest => libcore/tests}/num/u8.rs | 0 .../tests}/num/uint_macros.rs | 0 src/{libcoretest => libcore/tests}/ops.rs | 0 src/{libcoretest => libcore/tests}/option.rs | 0 src/{libcoretest => libcore/tests}/ptr.rs | 0 src/{libcoretest => libcore/tests}/result.rs | 0 src/{libcoretest => libcore/tests}/slice.rs | 84 +- src/{libcoretest => libcore/tests}/str.rs | 2 +- src/{libcoretest => libcore/tests}/tuple.rs | 0 src/libgraphviz/lib.rs | 6 +- src/liblibc/.travis.yml | 25 +- src/liblibc/Cargo.lock | 4 +- src/liblibc/Cargo.toml | 2 +- src/liblibc/appveyor.yml | 2 +- ...licenses.sh => android-accept-licenses.sh} | 0 .../install-ndk.sh => android-install-ndk.sh} | 19 +- .../install-sdk.sh => android-install-sdk.sh} | 40 +- .../docker/aarch64-linux-android/Dockerfile | 32 + .../docker/arm-linux-androideabi/Dockerfile | 20 +- .../ci/docker/i686-linux-android/Dockerfile | 32 + .../ci/docker/x86_64-linux-android/Dockerfile | 32 + src/liblibc/ci/run-docker.sh | 7 +- src/liblibc/ci/run.sh | 17 +- src/liblibc/libc-test/build.rs | 13 +- src/liblibc/src/unix/bsd/apple/b64.rs | 2 + src/liblibc/src/unix/bsd/apple/mod.rs | 185 +- .../src/unix/bsd/freebsdlike/dragonfly/mod.rs | 30 +- .../src/unix/bsd/freebsdlike/freebsd/mod.rs | 128 +- src/liblibc/src/unix/bsd/freebsdlike/mod.rs | 164 +- src/liblibc/src/unix/bsd/mod.rs | 73 +- src/liblibc/src/unix/bsd/netbsdlike/mod.rs | 141 +- .../src/unix/bsd/netbsdlike/netbsd/mod.rs | 51 + .../unix/bsd/netbsdlike/openbsdlike/mod.rs | 50 + .../bsd/netbsdlike/openbsdlike/openbsd.rs | 5 + src/liblibc/src/unix/haiku/mod.rs | 46 +- src/liblibc/src/unix/mod.rs | 123 +- .../src/unix/notbsd/android/b32/arm.rs | 6 + .../notbsd/android/{b32.rs => b32/mod.rs} | 48 + .../src/unix/notbsd/android/b32/x86.rs | 6 + .../src/unix/notbsd/android/b64/aarch64.rs | 56 + .../notbsd/android/{b64.rs => b64/mod.rs} | 95 +- .../src/unix/notbsd/android/b64/x86_64.rs | 50 + src/liblibc/src/unix/notbsd/android/mod.rs | 149 +- src/liblibc/src/unix/notbsd/linux/mips/mod.rs | 108 +- src/liblibc/src/unix/notbsd/linux/mod.rs | 58 +- .../src/unix/notbsd/linux/musl/b32/arm.rs | 9 + .../src/unix/notbsd/linux/musl/b32/mips.rs | 23 +- .../src/unix/notbsd/linux/musl/b32/x86.rs | 9 + .../src/unix/notbsd/linux/musl/b64/mod.rs | 9 + src/liblibc/src/unix/notbsd/linux/musl/mod.rs | 37 + .../src/unix/notbsd/linux/other/b32/arm.rs | 34 + .../unix/notbsd/linux/other/b32/powerpc.rs | 43 +- .../src/unix/notbsd/linux/other/b32/x86.rs | 40 + .../unix/notbsd/linux/other/b64/aarch64.rs | 83 +- .../unix/notbsd/linux/other/b64/powerpc64.rs | 84 +- .../src/unix/notbsd/linux/other/b64/x86_64.rs | 83 +- .../src/unix/notbsd/linux/other/mod.rs | 13 +- src/liblibc/src/unix/notbsd/linux/s390x.rs | 1 - src/liblibc/src/unix/notbsd/mod.rs | 170 +- src/liblibc/src/unix/solaris/mod.rs | 83 +- src/liblog/Cargo.toml | 9 - src/liblog/directive.rs | 193 - src/liblog/lib.rs | 506 - src/liblog/macros.rs | 205 - src/libproc_macro_plugin/lib.rs | 78 +- .../{qquote.rs => quote.rs} | 26 +- src/librand/distributions/gamma.rs | 12 +- src/librustc/Cargo.toml | 2 +- src/librustc/cfg/construct.rs | 128 +- src/librustc/dep_graph/dep_node.rs | 69 +- src/librustc/dep_graph/dep_tracking_map.rs | 17 +- src/librustc/dep_graph/edges.rs | 12 +- src/librustc/dep_graph/shadow.rs | 10 +- src/librustc/dep_graph/visit.rs | 9 +- src/librustc/diagnostics.rs | 30 +- src/librustc/hir/check_attr.rs | 28 +- src/librustc/hir/def.rs | 8 +- src/librustc/hir/def_id.rs | 53 + src/librustc/hir/intravisit.rs | 25 +- src/librustc/hir/lowering.rs | 1752 +- src/librustc/hir/map/def_collector.rs | 75 +- src/librustc/hir/map/definitions.rs | 237 +- src/librustc/hir/map/hir_id_validator.rs | 184 + src/librustc/hir/map/mod.rs | 42 +- src/librustc/hir/mod.rs | 123 +- src/librustc/hir/print.rs | 14 +- .../ich}/caching_codemap_view.rs | 6 +- .../ich/fingerprint.rs | 4 +- src/librustc/ich/hcx.rs | 350 + src/librustc/ich/impls_const_math.rs | 71 + src/librustc/ich/impls_hir.rs | 1122 ++ src/librustc/ich/impls_mir.rs | 408 + src/librustc/ich/impls_syntax.rs | 301 + src/librustc/ich/impls_ty.rs | 681 + src/librustc/ich/mod.rs | 58 + src/librustc/infer/bivariate.rs | 123 - src/librustc/infer/combine.rs | 352 +- src/librustc/infer/equate.rs | 30 +- src/librustc/infer/error_reporting/mod.rs | 288 +- src/librustc/infer/error_reporting/note.rs | 2 + src/librustc/infer/freshen.rs | 2 +- src/librustc/infer/fudge.rs | 67 +- src/librustc/infer/glb.rs | 3 +- src/librustc/infer/lattice.rs | 28 +- src/librustc/infer/lub.rs | 3 +- src/librustc/infer/mod.rs | 112 +- src/librustc/infer/region_inference/mod.rs | 8 +- src/librustc/infer/sub.rs | 38 +- src/librustc/infer/type_variable.rs | 250 +- src/librustc/lib.rs | 7 +- src/librustc/lint/context.rs | 31 +- src/librustc/macros.rs | 79 + src/librustc/middle/const_val.rs | 204 +- src/librustc/middle/cstore.rs | 62 +- src/librustc/middle/dead.rs | 11 +- src/librustc/middle/effect.rs | 3 - src/librustc/middle/entry.rs | 3 - src/librustc/middle/expr_use_visitor.rs | 8 +- src/librustc/middle/free_region.rs | 5 + src/librustc/middle/intrinsicck.rs | 7 +- src/librustc/middle/lang_items.rs | 14 +- src/librustc/middle/liveness.rs | 139 +- src/librustc/middle/mem_categorization.rs | 153 +- src/librustc/middle/reachable.rs | 31 +- src/librustc/middle/region.rs | 2 +- src/librustc/middle/resolve_lifetime.rs | 20 +- src/librustc/middle/stability.rs | 19 +- src/librustc/mir/cache.rs | 11 +- src/librustc/mir/mod.rs | 93 +- src/librustc/mir/tcx.rs | 2 +- src/librustc/mir/visit.rs | 6 +- src/librustc/session/code_stats.rs | 5 +- src/librustc/session/config.rs | 50 +- src/librustc/session/mod.rs | 68 +- src/librustc/traits/coherence.rs | 8 +- src/librustc/traits/error_reporting.rs | 199 +- src/librustc/traits/fulfill.rs | 35 +- src/librustc/traits/mod.rs | 15 +- src/librustc/traits/object_safety.rs | 13 +- src/librustc/traits/select.rs | 73 +- src/librustc/traits/specialize/mod.rs | 38 +- .../traits/specialize/specialization_graph.rs | 4 + src/librustc/traits/structural_impls.rs | 5 + src/librustc/traits/trans/mod.rs | 212 + src/librustc/traits/util.rs | 9 +- src/librustc/ty/adjustment.rs | 17 +- src/librustc/ty/contents.rs | 255 - src/librustc/ty/context.rs | 45 +- src/librustc/ty/error.rs | 2 +- src/librustc/ty/fold.rs | 22 +- src/librustc/ty/instance.rs | 125 + src/librustc/ty/item_path.rs | 6 +- src/librustc/ty/layout.rs | 506 +- src/librustc/ty/maps.rs | 156 +- src/librustc/ty/mod.rs | 847 +- src/librustc/ty/relate.rs | 55 +- src/librustc/ty/structural_impls.rs | 35 +- src/librustc/ty/sty.rs | 64 +- src/librustc/ty/subst.rs | 3 + src/librustc/ty/util.rs | 425 +- src/librustc/ty/wf.rs | 5 + src/librustc/util/common.rs | 7 +- src/librustc/util/fs.rs | 20 - src/librustc/util/ppaux.rs | 14 + src/librustc_asan/lib.rs | 4 +- src/librustc_back/Cargo.toml | 2 +- src/librustc_back/lib.rs | 42 + src/librustc_back/target/aarch64_apple_ios.rs | 2 + .../target/aarch64_linux_android.rs | 2 + .../target/aarch64_unknown_freebsd.rs | 2 + .../target/aarch64_unknown_fuchsia.rs | 2 + .../target/aarch64_unknown_linux_gnu.rs | 2 + src/librustc_back/target/android_base.rs | 4 +- src/librustc_back/target/apple_base.rs | 12 +- src/librustc_back/target/apple_ios_base.rs | 15 +- .../target/arm_linux_androideabi.rs | 2 + .../target/arm_unknown_linux_gnueabi.rs | 2 + .../target/arm_unknown_linux_gnueabihf.rs | 2 + .../target/arm_unknown_linux_musleabi.rs | 2 + .../target/arm_unknown_linux_musleabihf.rs | 2 + .../target/armv5te_unknown_linux_gnueabi.rs | 3 +- src/librustc_back/target/armv7_apple_ios.rs | 2 + .../target/armv7_linux_androideabi.rs | 2 + .../target/armv7_unknown_linux_gnueabihf.rs | 3 +- .../target/armv7_unknown_linux_musleabihf.rs | 2 + src/librustc_back/target/armv7s_apple_ios.rs | 2 + .../target/asmjs_unknown_emscripten.rs | 11 +- src/librustc_back/target/dragonfly_base.rs | 26 +- src/librustc_back/target/freebsd_base.rs | 26 +- src/librustc_back/target/fuchsia_base.rs | 34 +- src/librustc_back/target/i386_apple_ios.rs | 2 + src/librustc_back/target/i686_apple_darwin.rs | 4 +- .../target/i686_linux_android.rs | 2 + .../target/i686_pc_windows_gnu.rs | 5 +- .../target/i686_pc_windows_msvc.rs | 7 +- .../target/i686_unknown_dragonfly.rs | 4 +- .../target/i686_unknown_freebsd.rs | 4 +- .../target/i686_unknown_haiku.rs | 4 +- .../target/i686_unknown_linux_gnu.rs | 4 +- .../target/i686_unknown_linux_musl.rs | 6 +- .../target/i686_unknown_netbsd.rs | 4 +- .../target/i686_unknown_openbsd.rs | 4 +- src/librustc_back/target/le32_unknown_nacl.rs | 19 +- src/librustc_back/target/linux_base.rs | 32 +- src/librustc_back/target/linux_musl_base.rs | 9 +- .../target/mips64_unknown_linux_gnuabi64.rs | 2 + .../target/mips64el_unknown_linux_gnuabi64.rs | 2 + .../target/mips_unknown_linux_gnu.rs | 2 + .../target/mips_unknown_linux_musl.rs | 2 + .../target/mips_unknown_linux_uclibc.rs | 2 + .../target/mipsel_unknown_linux_gnu.rs | 2 + .../target/mipsel_unknown_linux_musl.rs | 2 + .../target/mipsel_unknown_linux_uclibc.rs | 2 + src/librustc_back/target/mod.rs | 82 +- src/librustc_back/target/netbsd_base.rs | 26 +- src/librustc_back/target/openbsd_base.rs | 26 +- .../target/powerpc64_unknown_linux_gnu.rs | 4 +- .../target/powerpc64le_unknown_linux_gnu.rs | 4 +- .../target/powerpc_unknown_linux_gnu.rs | 4 +- src/librustc_back/target/redox_base.rs | 33 +- .../target/s390x_unknown_linux_gnu.rs | 2 + .../target/sparc64_unknown_linux_gnu.rs | 2 + .../target/sparc64_unknown_netbsd.rs | 4 +- .../target/sparcv9_sun_solaris.rs | 4 +- .../target/thumbv6m_none_eabi.rs | 2 + .../target/thumbv7em_none_eabi.rs | 2 + .../target/thumbv7em_none_eabihf.rs | 2 + .../target/thumbv7m_none_eabi.rs | 2 + .../target/wasm32_unknown_emscripten.rs | 14 +- src/librustc_back/target/windows_base.rs | 59 +- src/librustc_back/target/windows_msvc_base.rs | 13 +- .../target/x86_64_apple_darwin.rs | 4 +- src/librustc_back/target/x86_64_apple_ios.rs | 2 + .../target/x86_64_linux_android.rs | 34 + .../target/x86_64_pc_windows_gnu.rs | 4 +- .../target/x86_64_pc_windows_msvc.rs | 2 + .../target/x86_64_rumprun_netbsd.rs | 4 +- .../target/x86_64_sun_solaris.rs | 4 +- .../target/x86_64_unknown_bitrig.rs | 4 +- .../target/x86_64_unknown_dragonfly.rs | 4 +- .../target/x86_64_unknown_freebsd.rs | 4 +- .../target/x86_64_unknown_fuchsia.rs | 4 +- .../target/x86_64_unknown_haiku.rs | 4 +- .../target/x86_64_unknown_linux_gnu.rs | 4 +- .../target/x86_64_unknown_linux_musl.rs | 4 +- .../target/x86_64_unknown_netbsd.rs | 4 +- .../target/x86_64_unknown_openbsd.rs | 4 +- .../target/x86_64_unknown_redox.rs | 4 +- src/librustc_borrowck/Cargo.toml | 2 +- src/librustc_borrowck/borrowck/README.md | 6 +- src/librustc_borrowck/borrowck/fragments.rs | 24 +- .../borrowck/gather_loans/lifetime.rs | 2 +- .../borrowck/gather_loans/mod.rs | 9 - .../borrowck/mir/dataflow/graphviz.rs | 3 +- .../borrowck/mir/dataflow/impls.rs | 2 +- .../borrowck/mir/dataflow/mod.rs | 11 +- .../borrowck/mir/elaborate_drops.rs | 826 +- .../borrowck/mir/gather_moves.rs | 2 +- src/librustc_borrowck/borrowck/mir/mod.rs | 52 +- src/librustc_borrowck/borrowck/mod.rs | 273 +- src/librustc_borrowck/borrowck/move_data.rs | 30 +- src/librustc_borrowck/diagnostics.rs | 6 +- src/librustc_borrowck/graphviz.rs | 2 +- src/librustc_borrowck/lib.rs | 2 + src/librustc_const_eval/Cargo.toml | 3 +- src/librustc_const_eval/_match.rs | 4 +- src/librustc_const_eval/check_match.rs | 39 +- src/librustc_const_eval/diagnostics.rs | 25 +- src/librustc_const_eval/eval.rs | 489 +- src/librustc_const_eval/lib.rs | 1 - src/librustc_const_eval/pattern.rs | 23 +- src/librustc_data_structures/Cargo.toml | 2 +- .../accumulate_vec.rs | 8 +- src/librustc_data_structures/array_vec.rs | 43 +- src/librustc_data_structures/base_n.rs | 2 +- src/librustc_data_structures/blake2b.rs | 34 +- src/librustc_data_structures/indexed_set.rs | 8 +- src/librustc_data_structures/indexed_vec.rs | 7 + src/librustc_data_structures/lib.rs | 5 +- .../obligation_forest/mod.rs | 53 +- src/librustc_data_structures/stable_hasher.rs | 199 +- .../transitive_relation.rs | 46 + src/librustc_driver/Cargo.toml | 3 +- src/librustc_driver/derive_registrar.rs | 2 - src/librustc_driver/driver.rs | 79 +- src/librustc_driver/lib.rs | 28 +- src/librustc_driver/pretty.rs | 9 +- src/librustc_driver/test.rs | 13 +- src/librustc_errors/diagnostic.rs | 72 +- src/librustc_errors/diagnostic_builder.rs | 10 +- src/librustc_errors/emitter.rs | 281 +- src/librustc_errors/lib.rs | 9 +- src/librustc_errors/snippet.rs | 35 +- src/librustc_incremental/Cargo.toml | 2 +- src/librustc_incremental/assert_dep_graph.rs | 2 +- .../calculate_svh/def_path_hash.rs | 36 - src/librustc_incremental/calculate_svh/mod.rs | 208 +- .../calculate_svh/svh_visitor.rs | 1150 -- src/librustc_incremental/lib.rs | 13 +- src/librustc_incremental/persist/data.rs | 16 +- src/librustc_incremental/persist/directory.rs | 4 - .../persist/dirty_clean.rs | 88 +- .../persist/file_format.rs | 4 +- src/librustc_incremental/persist/fs.rs | 2 +- src/librustc_incremental/persist/hash.rs | 2 +- src/librustc_incremental/persist/load.rs | 2 +- src/librustc_incremental/persist/preds/mod.rs | 30 +- src/librustc_incremental/persist/save.rs | 94 +- src/librustc_lint/Cargo.toml | 2 +- src/librustc_lint/bad_style.rs | 2 +- src/librustc_lint/builtin.rs | 12 +- src/librustc_lint/lib.rs | 6 +- src/librustc_lint/types.rs | 8 +- src/librustc_lint/unused.rs | 7 +- src/librustc_llvm/build.rs | 28 +- src/librustc_llvm/ffi.rs | 8 +- src/librustc_lsan/lib.rs | 4 +- src/librustc_metadata/Cargo.toml | 2 +- src/librustc_metadata/astencode.rs | 42 +- src/librustc_metadata/creader.rs | 21 +- src/librustc_metadata/cstore.rs | 10 +- src/librustc_metadata/cstore_impl.rs | 82 +- src/librustc_metadata/decoder.rs | 120 +- src/librustc_metadata/diagnostics.rs | 2 +- src/librustc_metadata/encoder.rs | 190 +- src/librustc_metadata/index.rs | 67 +- src/librustc_metadata/index_builder.rs | 142 +- src/librustc_metadata/lib.rs | 2 +- src/librustc_metadata/locator.rs | 6 +- src/librustc_metadata/schema.rs | 155 +- src/librustc_mir/Cargo.toml | 2 +- src/librustc_mir/build/block.rs | 170 +- src/librustc_mir/build/cfg.rs | 4 +- src/librustc_mir/build/expr/as_lvalue.rs | 3 +- src/librustc_mir/build/expr/as_operand.rs | 2 +- src/librustc_mir/build/expr/as_rvalue.rs | 23 +- src/librustc_mir/build/expr/as_temp.rs | 9 +- src/librustc_mir/build/expr/into.rs | 66 +- src/librustc_mir/build/expr/stmt.rs | 16 +- src/librustc_mir/build/matches/mod.rs | 3 +- src/librustc_mir/build/matches/test.rs | 17 +- src/librustc_mir/build/misc.rs | 10 +- src/librustc_mir/build/mod.rs | 18 +- src/librustc_mir/build/scope.rs | 57 +- src/librustc_mir/diagnostics.rs | 33 + src/librustc_mir/hair/cx/block.rs | 1 + src/librustc_mir/hair/cx/expr.rs | 66 +- src/librustc_mir/hair/cx/mod.rs | 24 +- src/librustc_mir/hair/mod.rs | 1 + src/librustc_mir/lib.rs | 9 +- src/librustc_mir/mir_map.rs | 72 +- src/librustc_mir/shim.rs | 486 + src/librustc_mir/transform/add_call_guards.rs | 68 +- src/librustc_mir/transform/copy_prop.rs | 4 +- src/librustc_mir/transform/deaggregator.rs | 8 +- src/librustc_mir/transform/dump_mir.rs | 18 +- src/librustc_mir/transform/erase_regions.rs | 28 +- src/librustc_mir/transform/inline.rs | 21 +- src/librustc_mir/transform/no_landing_pads.rs | 10 +- src/librustc_mir/transform/promote_consts.rs | 10 +- src/librustc_mir/transform/qualify_consts.rs | 28 +- src/librustc_mir/transform/simplify.rs | 48 +- .../transform/simplify_branches.rs | 6 +- src/librustc_mir/transform/type_check.rs | 59 +- src/librustc_mir/{ => util}/def_use.rs | 0 src/librustc_mir/util/elaborate_drops.rs | 694 + src/librustc_mir/{ => util}/graphviz.rs | 0 .../util/mod.rs} | 22 +- .../mir => librustc_mir/util}/patch.rs | 5 +- src/librustc_mir/{ => util}/pretty.rs | 7 +- src/librustc_msan/lib.rs | 4 +- src/librustc_passes/Cargo.toml | 4 +- src/librustc_passes/ast_validation.rs | 4 +- src/librustc_passes/consts.rs | 33 +- src/librustc_passes/diagnostics.rs | 33 - src/librustc_passes/lib.rs | 1 - src/librustc_passes/loops.rs | 27 +- src/librustc_passes/mir_stats.rs | 2 +- src/librustc_passes/rvalues.rs | 103 - src/librustc_passes/static_recursion.rs | 3 - src/librustc_plugin/build.rs | 2 - src/librustc_plugin/load.rs | 14 +- src/librustc_privacy/lib.rs | 87 +- src/librustc_resolve/Cargo.toml | 2 +- src/librustc_resolve/build_reduced_graph.rs | 12 +- src/librustc_resolve/diagnostics.rs | 6 +- src/librustc_resolve/lib.rs | 83 +- src/librustc_resolve/macros.rs | 213 +- src/librustc_resolve/resolve_imports.rs | 33 +- src/librustc_save_analysis/Cargo.toml | 9 +- src/librustc_save_analysis/csv_dumper.rs | 8 +- src/librustc_save_analysis/data.rs | 70 +- src/librustc_save_analysis/dump.rs | 2 + src/librustc_save_analysis/dump_visitor.rs | 83 +- src/librustc_save_analysis/external_data.rs | 163 +- src/librustc_save_analysis/json_api_dumper.rs | 459 +- src/librustc_save_analysis/json_dumper.rs | 585 +- src/librustc_save_analysis/lib.rs | 254 +- src/librustc_save_analysis/span_utils.rs | 7 +- src/librustc_trans/Cargo.toml | 3 +- src/librustc_trans/abi.rs | 614 +- src/librustc_trans/adt.rs | 184 +- src/librustc_trans/asm.rs | 16 +- src/librustc_trans/assert_module_sources.rs | 9 +- src/librustc_trans/attributes.rs | 1 + src/librustc_trans/back/archive.rs | 4 +- src/librustc_trans/back/link.rs | 77 +- src/librustc_trans/back/linker.rs | 259 +- src/librustc_trans/back/lto.rs | 4 +- src/librustc_trans/back/rpath.rs | 14 +- src/librustc_trans/back/symbol_export.rs | 30 +- src/librustc_trans/back/symbol_names.rs | 284 +- src/librustc_trans/back/write.rs | 20 +- src/librustc_trans/base.rs | 542 +- src/librustc_trans/builder.rs | 18 +- src/librustc_trans/cabi_aarch64.rs | 178 +- src/librustc_trans/cabi_arm.rs | 155 +- src/librustc_trans/cabi_asmjs.rs | 35 +- src/librustc_trans/cabi_mips.rs | 88 +- src/librustc_trans/cabi_mips64.rs | 88 +- src/librustc_trans/cabi_msp430.rs | 21 +- src/librustc_trans/cabi_nvptx.rs | 21 +- src/librustc_trans/cabi_nvptx64.rs | 21 +- src/librustc_trans/cabi_powerpc.rs | 93 +- src/librustc_trans/cabi_powerpc64.rs | 180 +- src/librustc_trans/cabi_s390x.rs | 140 +- src/librustc_trans/cabi_sparc.rs | 90 +- src/librustc_trans/cabi_sparc64.rs | 181 +- src/librustc_trans/cabi_x86.rs | 37 +- src/librustc_trans/cabi_x86_64.rs | 510 +- src/librustc_trans/cabi_x86_win64.rs | 45 +- src/librustc_trans/callee.rs | 556 +- src/librustc_trans/cleanup.rs | 162 - src/librustc_trans/collector.rs | 733 +- src/librustc_trans/common.rs | 119 +- src/librustc_trans/consts.rs | 35 +- src/librustc_trans/context.rs | 435 +- .../debuginfo/create_scope_map.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 16 +- src/librustc_trans/debuginfo/mod.rs | 22 +- src/librustc_trans/debuginfo/utils.rs | 2 +- src/librustc_trans/disr.rs | 82 - src/librustc_trans/glue.rs | 431 +- src/librustc_trans/intrinsic.rs | 36 +- src/librustc_trans/lib.rs | 9 +- src/librustc_trans/meth.rs | 132 +- src/librustc_trans/mir/analyze.rs | 12 +- src/librustc_trans/mir/block.rs | 291 +- src/librustc_trans/mir/constant.rs | 112 +- src/librustc_trans/mir/lvalue.rs | 78 +- src/librustc_trans/mir/mod.rs | 91 +- src/librustc_trans/mir/operand.rs | 99 +- src/librustc_trans/mir/rvalue.rs | 111 +- src/librustc_trans/mir/statement.rs | 3 +- src/librustc_trans/monomorphize.rs | 277 +- src/librustc_trans/partitioning.rs | 98 +- src/librustc_trans/symbol_cache.rs | 42 + src/librustc_trans/symbol_map.rs | 13 +- src/librustc_trans/symbol_names_test.rs | 17 +- src/librustc_trans/trans_item.rs | 145 +- src/librustc_trans/tvec.rs | 7 +- src/librustc_trans/type_.rs | 10 +- src/librustc_trans/type_of.rs | 142 +- src/librustc_tsan/lib.rs | 4 +- src/librustc_typeck/Cargo.toml | 3 +- src/librustc_typeck/astconv.rs | 17 +- src/librustc_typeck/check/_match.rs | 92 +- src/librustc_typeck/check/assoc.rs | 39 - src/librustc_typeck/check/autoderef.rs | 72 +- src/librustc_typeck/check/callee.rs | 15 +- src/librustc_typeck/check/cast.rs | 12 +- src/librustc_typeck/check/closure.rs | 1 + src/librustc_typeck/check/coercion.rs | 494 +- src/librustc_typeck/check/compare_method.rs | 73 +- src/librustc_typeck/check/demand.rs | 101 +- src/librustc_typeck/check/dropck.rs | 420 +- src/librustc_typeck/check/intrinsic.rs | 5 +- src/librustc_typeck/check/method/confirm.rs | 186 +- src/librustc_typeck/check/method/mod.rs | 78 +- src/librustc_typeck/check/method/probe.rs | 34 +- src/librustc_typeck/check/method/suggest.rs | 26 +- src/librustc_typeck/check/mod.rs | 1380 +- src/librustc_typeck/check/op.rs | 12 +- src/librustc_typeck/check/regionck.rs | 9 +- src/librustc_typeck/check/wfcheck.rs | 2 +- src/librustc_typeck/check/writeback.rs | 259 +- src/librustc_typeck/check_unused.rs | 3 - src/librustc_typeck/coherence/builtin.rs | 97 +- .../{inherent.rs => inherent_impls.rs} | 184 +- .../coherence/inherent_impls_overlap.rs | 105 + src/librustc_typeck/coherence/mod.rs | 22 +- src/librustc_typeck/coherence/orphan.rs | 3 +- src/librustc_typeck/coherence/overlap.rs | 2 +- src/librustc_typeck/collect.rs | 120 +- src/librustc_typeck/diagnostics.rs | 110 +- src/librustc_typeck/impl_wf_check.rs | 3 +- src/librustc_typeck/lib.rs | 22 +- src/librustc_typeck/variance/constraints.rs | 2 +- src/librustc_typeck/variance/terms.rs | 1 + src/librustc_typeck/variance/xform.rs | 29 - src/librustdoc/Cargo.toml | 7 +- src/librustdoc/build.rs | 1 + src/librustdoc/clean/inline.rs | 10 +- src/librustdoc/clean/mod.rs | 52 +- src/librustdoc/core.rs | 10 +- src/librustdoc/html/format.rs | 257 +- src/librustdoc/html/markdown.rs | 735 +- src/librustdoc/html/render.rs | 450 +- src/librustdoc/html/static/main.js | 15 +- src/librustdoc/html/static/rustdoc.css | 15 +- src/librustdoc/html/static/styles/main.css | 10 +- src/librustdoc/lib.rs | 27 +- src/librustdoc/markdown.rs | 29 +- src/librustdoc/passes/unindent_comments.rs | 13 +- src/librustdoc/plugins.rs | 2 +- src/librustdoc/test.rs | 96 +- src/librustdoc/visit_ast.rs | 27 +- src/librustdoc/visit_lib.rs | 8 + src/libstd/ascii.rs | 95 +- src/libstd/collections/hash/map.rs | 155 +- src/libstd/collections/hash/set.rs | 171 +- src/libstd/collections/hash/table.rs | 365 +- src/libstd/collections/mod.rs | 60 +- src/libstd/error.rs | 5 + src/libstd/f32.rs | 299 +- src/libstd/f64.rs | 257 +- src/libstd/ffi/c_str.rs | 44 +- src/libstd/ffi/os_str.rs | 110 +- src/libstd/fs.rs | 91 +- src/libstd/io/buffered.rs | 17 +- src/libstd/io/cursor.rs | 4 + src/libstd/io/error.rs | 4 +- src/libstd/io/mod.rs | 234 +- src/libstd/io/stdio.rs | 4 +- src/libstd/io/util.rs | 6 +- src/libstd/lib.rs | 34 +- src/libstd/net/addr.rs | 198 +- src/libstd/net/ip.rs | 249 +- src/libstd/net/mod.rs | 51 +- src/libstd/net/parser.rs | 14 +- src/libstd/net/tcp.rs | 97 +- src/libstd/net/udp.rs | 56 +- src/libstd/num.rs | 3 - src/libstd/os/android/raw.rs | 63 + src/libstd/os/linux/fs.rs | 19 + src/libstd/os/macos/mod.rs | 2 +- src/libstd/os/macos/raw.rs | 2 +- src/libstd/os/raw.rs | 10 +- src/libstd/panicking.rs | 8 +- src/libstd/path.rs | 460 +- src/libstd/prelude/mod.rs | 16 +- src/libstd/primitive_docs.rs | 29 +- src/libstd/process.rs | 88 +- src/libstd/rand/mod.rs | 4 +- src/libstd/rt.rs | 4 +- src/libstd/sync/barrier.rs | 9 +- src/libstd/sync/condvar.rs | 18 +- src/libstd/sync/mpsc/mod.rs | 332 +- src/libstd/sync/mutex.rs | 24 +- src/libstd/sync/once.rs | 37 +- src/libstd/sync/rwlock.rs | 12 +- src/libstd/sys/redox/fast_thread_local.rs | 6 +- src/libstd/sys/redox/os_str.rs | 6 + src/libstd/sys/redox/process.rs | 23 +- src/libstd/sys/redox/syscall/call.rs | 5 + src/libstd/sys/redox/syscall/number.rs | 1 + src/libstd/sys/unix/backtrace/mod.rs | 8 +- src/libstd/sys/unix/ext/net.rs | 40 +- src/libstd/sys/unix/fast_thread_local.rs | 8 +- src/libstd/sys/unix/fd.rs | 2 +- src/libstd/sys/unix/fs.rs | 4 +- src/libstd/sys/unix/mod.rs | 2 +- src/libstd/sys/unix/os_str.rs | 6 + src/libstd/sys/unix/pipe.rs | 22 +- src/libstd/sys/unix/process/magenta.rs | 77 +- src/libstd/sys/unix/process/process_common.rs | 20 +- src/libstd/sys/unix/process/process_unix.rs | 13 +- src/libstd/sys/unix/stack_overflow.rs | 2 +- src/libstd/sys/windows/ext/fs.rs | 2 +- src/libstd/sys/windows/ext/process.rs | 1 + src/libstd/sys/windows/os_str.rs | 6 + src/libstd/sys/windows/process.rs | 9 +- src/libstd/sys/windows/stdio.rs | 92 +- src/libstd/sys_common/backtrace.rs | 4 +- src/libstd/sys_common/net.rs | 4 +- src/libstd/sys_common/poison.rs | 4 +- src/libstd/sys_common/thread_info.rs | 7 +- src/libstd/sys_common/wtf8.rs | 6 + src/libstd/thread/local.rs | 6 +- src/libstd/thread/mod.rs | 76 +- src/libstd_unicode/char.rs | 24 +- src/libstd_unicode/u_str.rs | 6 + src/libsyntax/Cargo.toml | 2 +- src/libsyntax/ast.rs | 117 +- src/libsyntax/attr.rs | 413 +- src/libsyntax/codemap.rs | 499 +- src/libsyntax/config.rs | 70 +- src/libsyntax/diagnostic_list.rs | 2 +- src/libsyntax/ext/base.rs | 99 +- src/libsyntax/ext/derive.rs | 86 +- src/libsyntax/ext/expand.rs | 260 +- src/libsyntax/ext/placeholders.rs | 18 +- src/libsyntax/ext/quote.rs | 16 +- src/libsyntax/ext/source_util.rs | 8 +- src/libsyntax/ext/tt/macro_parser.rs | 27 +- src/libsyntax/ext/tt/macro_rules.rs | 86 +- src/libsyntax/ext/tt/quoted.rs | 27 +- src/libsyntax/ext/tt/transcribe.rs | 9 +- src/libsyntax/feature_gate.rs | 116 +- src/libsyntax/fold.rs | 21 +- src/libsyntax/json.rs | 2 +- src/libsyntax/lib.rs | 14 +- src/libsyntax/parse/attr.rs | 67 +- src/libsyntax/parse/lexer/mod.rs | 44 +- src/libsyntax/parse/lexer/unicode_chars.rs | 4 +- src/libsyntax/parse/mod.rs | 141 +- src/libsyntax/parse/obsolete.rs | 1 + src/libsyntax/parse/parser.rs | 1547 +- src/libsyntax/parse/token.rs | 99 +- src/libsyntax/print/pprust.rs | 132 +- src/libsyntax/ptr.rs | 12 + src/libsyntax/std_inject.rs | 29 +- src/libsyntax/test.rs | 23 +- src/libsyntax/test_snippet.rs | 213 +- src/libsyntax/tokenstream.rs | 24 +- src/libsyntax/util/rc_slice.rs | 13 + src/libsyntax/visit.rs | 11 +- src/libsyntax_ext/Cargo.toml | 2 +- src/libsyntax_ext/asm.rs | 12 +- src/libsyntax_ext/deriving/clone.rs | 2 +- src/libsyntax_ext/deriving/cmp/eq.rs | 2 +- src/libsyntax_ext/deriving/custom.rs | 8 +- src/libsyntax_ext/deriving/debug.rs | 4 +- src/libsyntax_ext/deriving/generic/mod.rs | 16 +- src/libsyntax_ext/deriving/mod.rs | 34 +- src/libsyntax_ext/format.rs | 18 +- src/libsyntax_ext/global_asm.rs | 65 + src/libsyntax_ext/lib.rs | 2 + src/libsyntax_ext/proc_macro_registrar.rs | 18 +- .../ext => libsyntax_pos}/hygiene.rs | 103 +- src/libsyntax_pos/lib.rs | 152 +- src/{libsyntax => libsyntax_pos}/symbol.rs | 104 +- src/libterm/terminfo/searcher.rs | 4 +- src/libtest/stats.rs | 6 +- src/libunwind/build.rs | 3 +- src/libunwind/lib.rs | 1 + src/rtstartup/rsbegin.rs | 7 +- src/rustc/rustdoc.rs | 2 +- src/rustllvm/RustWrapper.cpp | 30 +- src/rustllvm/llvm-rebuild-trigger | 4 - src/stage0.txt | 3 +- .../cross-crate-generic-functions.rs | 2 - .../drop_in_place_intrinsic.rs | 7 +- .../item-collection/function-as-argument.rs | 4 +- .../item-collection/generic-drop-glue.rs | 19 +- .../instantiation-through-vtable.rs | 3 +- .../items-within-generic-items.rs | 2 - .../item-collection/non-generic-drop-glue.rs | 8 +- .../item-collection/non-generic-functions.rs | 2 - .../item-collection/overloaded-operators.rs | 2 - .../item-collection/static-init.rs | 1 - .../item-collection/statics-and-consts.rs | 2 - .../item-collection/trait-implementations.rs | 2 - .../trait-method-as-argument.rs | 8 +- .../trait-method-default-impl.rs | 2 - .../item-collection/transitive-drop-glue.rs | 21 +- .../item-collection/tuple-drop-glue.rs | 9 +- .../codegen-units/item-collection/unsizing.rs | 8 +- .../unused-traits-and-generics.rs | 1 - .../partitioning/extern-drop-glue.rs | 7 +- .../partitioning/extern-generic.rs | 2 - .../partitioning/local-drop-glue.rs | 9 +- .../partitioning/regular-modules.rs | 2 - .../codegen-units/partitioning/statics.rs | 2 - .../partitioning/vtable-through-const.rs | 2 +- src/test/codegen/drop.rs | 2 +- src/test/codegen/foo.s | 3 + src/test/codegen/function-arguments.rs | 4 +- src/test/codegen/global_asm.rs | 73 + src/test/codegen/global_asm_include.rs | 68 + src/test/codegen/global_asm_x2.rs | 90 + src/test/codegen/move-val-init.rs | 29 + src/test/codegen/naked-functions.rs | 47 +- src/test/codegen/panic-abort-windows.rs | 41 + src/test/codegen/personality_lifetimes.rs | 42 + .../auxiliary/pub_and_stability.rs | 1 - .../proc-macro/auxiliary/issue-41211.rs | 23 + .../proc-macro/issue-41211.rs | 22 + .../proc-macro/proc-macro-attributes.rs | 1 + src/test/compile-fail-fulldeps/qquote.rs | 8 - src/test/compile-fail/E0120.rs | 2 +- src/test/compile-fail/E0178.rs | 3 - .../compile-fail/allocator-dylib-is-system.rs | 2 +- .../allocator-rust-dylib-is-jemalloc.rs | 2 +- src/test/compile-fail/attr-usage-repr.rs | 4 + .../compile-fail/augmented-assignments.rs | 2 +- .../auxiliary/trait_impl_conflict.rs | 1 + src/test/compile-fail/binop-move-semantics.rs | 2 - .../borrowck/borrowck-issue-14498.rs | 6 +- .../borrowck/borrowck-lend-flow-loop.rs | 1 - .../borrowck-mut-borrow-linear-errors.rs | 1 - src/test/compile-fail/catch-bad-lifetime.rs | 43 + .../catch-bad-type.rs} | 20 +- src/test/compile-fail/catch-in-match.rs | 15 + src/test/compile-fail/catch-in-while.rs | 15 + .../compile-fail/catch-maybe-bad-lifetime.rs | 51 + .../catch-opt-init.rs} | 27 +- src/test/compile-fail/coerce-to-bang-cast.rs | 23 + src/test/compile-fail/coerce-to-bang.rs | 90 + src/test/compile-fail/coercion-slice.rs | 1 - ...herence-conflicting-negative-trait-impl.rs | 3 +- .../coherence-default-trait-impl.rs | 2 +- src/test/compile-fail/coherence-impls-send.rs | 2 +- .../coherence-no-direct-lifetime-dispatch.rs | 2 +- .../coherence-overlap-all-t-and-tuple.rs | 1 + .../coherence-overlap-messages.rs | 8 +- .../coherence-projection-conflict-orphan.rs | 2 +- .../coherence-projection-conflict-ty-param.rs | 2 +- .../coherence-projection-conflict.rs | 2 +- ...erence_copy_like_err_fundamental_struct.rs | 2 +- ...ce_copy_like_err_fundamental_struct_ref.rs | 2 +- ..._copy_like_err_fundamental_struct_tuple.rs | 2 +- .../coherence_copy_like_err_struct.rs | 2 +- .../coherence_copy_like_err_tuple.rs | 2 +- .../compile-fail/conflicting-repr-hints.rs | 9 +- src/test/compile-fail/const-call.rs | 2 - .../compile-fail/const-match-pattern-arm.rs | 25 + .../const-pattern-not-const-evaluable.rs | 11 +- src/test/compile-fail/cross-borrow-trait.rs | 2 +- .../compile-fail/default_ty_param_conflict.rs | 33 - .../default_ty_param_conflict_cross_crate.rs | 32 - .../compile-fail/defaulted-unit-warning.rs | 12 +- .../dep-graph-struct-signature.rs | 11 - .../compile-fail/destructure-trait-ref.rs | 2 +- .../diverging-tuple-parts-39485.rs} | 30 +- .../duplicate-check-macro-exports.rs | 19 + .../compile-fail/feature-gate-catch_expr.rs | 17 + .../feature-gate-global_asm.rs} | 6 +- .../feature-gate-linker-flavor.rs | 20 + .../feature-gate-macro-vis-matcher.rs | 19 + .../feature-gate-overlapping_marker_traits.rs | 19 + .../compile-fail/feature-gate-repr_align.rs | 15 + .../feature-gate-rvalue_static_promotion.rs | 15 + src/test/compile-fail/feature-gate-used.rs | 15 + src/test/compile-fail/forget-init-unsafe.rs | 3 +- src/test/compile-fail/imports/macro-paths.rs | 2 - src/test/compile-fail/imports/macros.rs | 2 - .../imports/shadow_builtin_macros.rs | 71 + src/test/compile-fail/imports/unused.rs | 1 - src/test/compile-fail/index-bot.rs | 2 +- .../compile-fail/indexing-requires-a-uint.rs | 2 +- src/test/compile-fail/integral-indexing.rs | 8 +- src/test/compile-fail/issue-10176.rs | 2 +- src/test/compile-fail/issue-11374.rs | 2 +- src/test/compile-fail/issue-12187-1.rs | 1 + src/test/compile-fail/issue-12187-2.rs | 1 + src/test/compile-fail/issue-13058.rs | 1 + src/test/compile-fail/issue-13847.rs | 2 +- src/test/compile-fail/issue-15207.rs | 2 +- src/test/compile-fail/issue-17373.rs | 2 +- src/test/compile-fail/issue-18532.rs | 3 +- src/test/compile-fail/issue-2149.rs | 2 +- src/test/compile-fail/issue-22897.rs | 19 - src/test/compile-fail/issue-25385.rs | 1 - src/test/compile-fail/issue-25579.rs | 1 - src/test/compile-fail/issue-27042.rs | 8 +- src/test/compile-fail/issue-30225.rs | 48 + src/test/compile-fail/issue-33819.rs | 2 +- src/test/compile-fail/issue-34334.rs | 2 +- src/test/compile-fail/issue-35675.rs | 67 + src/test/compile-fail/issue-38412.rs | 1 - src/test/compile-fail/issue-39559.rs | 4 - src/test/compile-fail/issue-41139.rs | 18 + src/test/compile-fail/issue-41394.rs | 20 + src/test/compile-fail/issue-41726.rs | 17 + src/test/compile-fail/issue-41742.rs | 35 + src/test/compile-fail/issue-41776.rs | 13 + src/test/compile-fail/issue-7813.rs | 8 +- src/test/compile-fail/lint-unused-imports.rs | 1 - src/test/compile-fail/loop-break-value.rs | 23 +- .../macro-attribute.rs | 2 - .../compile-fail/macro-with-seps-err-msg.rs | 1 + .../compile-fail/malformed-derive-entry.rs | 4 +- .../compile-fail/manual-link-framework.rs | 2 +- ....rs => match-no-arms-unreachable-after.rs} | 14 +- ...achable-warning-with-diverging-discrim.rs} | 7 +- .../compile-fail/match-unresolved-one-arm.rs | 17 + src/test/compile-fail/mut-suggestion.rs | 4 +- .../compile-fail/never-assign-dead-code.rs | 1 + .../compile-fail/never-assign-wrong-type.rs | 1 + src/test/compile-fail/never-fallback.rs | 41 - ....rs => object-safety-associated-consts.rs} | 20 +- .../object-safety-supertrait-mentions-Self.rs | 2 +- .../on-unimplemented/slice-index.rs | 4 +- src/test/compile-fail/osx-frameworks.rs | 2 +- src/test/compile-fail/overlap-marker-trait.rs | 41 + .../restricted/auxiliary/pub_restricted.rs | 2 - .../restricted/lookup-ignores-private.rs | 2 +- .../privacy/restricted/private-in-public.rs | 2 - .../restricted/struct-literal-field.rs | 1 - .../compile-fail/privacy/restricted/test.rs | 1 - .../restricted/tuple-struct-fields/test.rs | 9 +- .../restricted/tuple-struct-fields/test2.rs | 9 +- .../restricted/tuple-struct-fields/test3.rs | 9 +- .../privacy/restricted/ty-params.rs | 2 - .../privacy/union-field-privacy-1.rs | 1 - .../privacy/union-field-privacy-2.rs | 1 - ...n-bounds-on-objects-and-type-parameters.rs | 2 +- ...region-invariant-static-error-reporting.rs | 8 +- .../regions-adjusted-lvalue-op.rs | 26 + src/test/compile-fail/regions-bounds.rs | 10 +- .../regions-trait-object-subtyping.rs | 2 +- src/test/compile-fail/repr-align.rs | 23 + .../repr-packed-contains-align.rs | 25 + .../compile-fail/resolve-bad-visibility.rs | 2 - .../specialization/specialization-overlap.rs | 8 +- .../compile-fail/static-lifetime-bound.rs | 16 + .../compile-fail/suffixed-literal-meta.rs | 25 + .../trait-object-macro-matcher.rs} | 14 +- ...ect-reference-without-parens-suggestion.rs | 3 +- .../union/union-borrow-move-parent-sibling.rs | 57 + .../variance-contravariant-arg-object.rs | 4 +- .../variance-covariant-arg-object.rs | 4 +- .../variance-invariant-arg-object.rs | 4 +- .../compile-fail/windows-subsystem-invalid.rs | 1 - src/test/incremental/hashes/enum_defs.rs | 100 +- src/test/incremental/hashes/extern_mods.rs | 40 +- .../incremental/hashes/function_interfaces.rs | 10 +- src/test/incremental/hashes/inherent_impls.rs | 20 +- src/test/incremental/hashes/struct_defs.rs | 90 +- src/test/incremental/hashes/trait_defs.rs | 121 +- src/test/incremental/hashes/trait_impls.rs | 58 +- .../unchecked_dirty_clean_metadata.rs | 10 - src/test/mir-opt/issue-41110.rs | 53 + src/test/parse-fail/attr-bad-meta.rs | 6 +- .../parse-fail/bound-single-question-mark.rs | 13 + src/test/parse-fail/issue-17904.rs | 2 +- src/test/parse-fail/issue-21153.rs | 5 +- src/test/parse-fail/match-refactor-to-expr.rs | 4 +- src/test/parse-fail/mod_file_not_exist.rs | 2 + .../parse-fail/mod_file_not_exist_windows.rs | 32 + .../parse-fail/removed-syntax-ptr-lifetime.rs | 2 +- .../parse-fail/removed-syntax-uniq-mut-ty.rs | 2 +- src/test/parse-fail/suffixed-literal-meta.rs | 25 - .../parse-fail/trait-object-bad-parens.rs | 20 + .../trait-object-lifetime-parens.rs} | 18 +- .../parse-fail/trait-object-macro-matcher.rs | 20 + .../trait-object-polytrait-priority.rs | 19 + .../parse-fail/trait-object-trait-parens.rs | 21 + src/test/parse-fail/trait-pub-assoc-const.rs | 2 +- src/test/parse-fail/trait-pub-assoc-ty.rs | 2 +- src/test/parse-fail/trait-pub-method.rs | 2 +- src/test/run-fail-fulldeps/qquote.rs | 8 - .../extern-fn-struct-passing-abi/test.c | 19 + .../extern-fn-struct-passing-abi/test.rs | 11 + src/test/run-make/graphviz-flowgraph/Makefile | 38 - .../graphviz-flowgraph/f00.dot-expected.dot | 9 - .../graphviz-flowgraph/f01.dot-expected.dot | 13 - .../graphviz-flowgraph/f02.dot-expected.dot | 13 - .../graphviz-flowgraph/f03.dot-expected.dot | 17 - .../graphviz-flowgraph/f04.dot-expected.dot | 15 - src/test/run-make/graphviz-flowgraph/f04.rs | 13 - .../graphviz-flowgraph/f05.dot-expected.dot | 23 - src/test/run-make/graphviz-flowgraph/f05.rs | 13 - .../graphviz-flowgraph/f06.dot-expected.dot | 19 - src/test/run-make/graphviz-flowgraph/f06.rs | 14 - .../graphviz-flowgraph/f07.dot-expected.dot | 39 - .../graphviz-flowgraph/f08.dot-expected.dot | 38 - .../graphviz-flowgraph/f09.dot-expected.dot | 54 - .../graphviz-flowgraph/f10.dot-expected.dot | 36 - .../graphviz-flowgraph/f11.dot-expected.dot | 35 - src/test/run-make/graphviz-flowgraph/f11.rs | 18 - .../graphviz-flowgraph/f12.dot-expected.dot | 50 - .../graphviz-flowgraph/f13.dot-expected.dot | 54 - src/test/run-make/graphviz-flowgraph/f13.rs | 18 - .../graphviz-flowgraph/f14.dot-expected.dot | 36 - src/test/run-make/graphviz-flowgraph/f14.rs | 18 - .../graphviz-flowgraph/f15.dot-expected.dot | 105 - src/test/run-make/graphviz-flowgraph/f15.rs | 30 - .../graphviz-flowgraph/f16.dot-expected.dot | 111 - src/test/run-make/graphviz-flowgraph/f16.rs | 31 - .../graphviz-flowgraph/f17.dot-expected.dot | 21 - src/test/run-make/graphviz-flowgraph/f17.rs | 13 - .../graphviz-flowgraph/f18.dot-expected.dot | 23 - src/test/run-make/graphviz-flowgraph/f18.rs | 14 - .../graphviz-flowgraph/f19.dot-expected.dot | 29 - src/test/run-make/graphviz-flowgraph/f19.rs | 16 - .../graphviz-flowgraph/f20.dot-expected.dot | 29 - src/test/run-make/graphviz-flowgraph/f20.rs | 14 - .../graphviz-flowgraph/f21.dot-expected.dot | 101 - src/test/run-make/graphviz-flowgraph/f21.rs | 30 - .../graphviz-flowgraph/f22.dot-expected.dot | 107 - src/test/run-make/graphviz-flowgraph/f22.rs | 31 - .../graphviz-flowgraph/f23.dot-expected.dot | 113 - .../graphviz-flowgraph/f24.dot-expected.dot | 161 - src/test/run-make/graphviz-flowgraph/f24.rs | 36 - .../graphviz-flowgraph/f25.dot-expected.dot | 161 - src/test/run-make/graphviz-flowgraph/f25.rs | 36 - src/test/run-make/save-analysis-fail/foo.rs | 5 + src/test/run-make/save-analysis/foo.rs | 17 + src/test/run-make/simd-ffi/simd.rs | 6 +- src/test/run-make/target-specs/foo.rs | 6 +- .../target-specs/my-awesome-platform.json | 1 + .../target-specs/my-incomplete-platform.json | 1 + .../x86_64-unknown-linux-gnu.json | 1 + src/test/run-make/used/Makefile | 11 + src/test/run-make/used/used.rs | 17 + .../run-make/windows-subsystem/console.rs | 1 - .../run-make/windows-subsystem/windows.rs | 1 - .../auxiliary/cond_plugin.rs | 5 +- .../auxiliary/custom_derive_plugin.rs | 6 + .../auxiliary/hello_macro.rs | 7 +- .../auxiliary/logging_right_crate.rs | 18 - .../auxiliary/proc_macro_def.rs | 10 +- src/test/run-pass-fulldeps/issue-40663.rs | 19 + .../run-pass-fulldeps/logging-right-crate.rs | 31 - .../logging-separate-lines.rs | 40 - src/test/run-pass-fulldeps/macro-quote-1.rs | 4 +- ...te-empty-delims.rs => macro-quote-test.rs} | 0 .../run-pass-fulldeps/proc-macro/attr-args.rs | 6 +- .../proc-macro/auxiliary/attr-args.rs | 5 + .../proc-macro/auxiliary/derive-b.rs | 2 +- .../run-pass-fulldeps/proc-macro/derive-b.rs | 7 +- src/test/run-pass-fulldeps/qquote.rs | 8 - src/test/run-pass-fulldeps/rust-log-filter.rs | 58 - src/test/run-pass-fulldeps/switch-stdout.rs | 64 + src/test/run-pass/align-struct.rs | 196 + .../run-pass/auxiliary/allocator-dummy.rs | 5 + .../issue-41394.rs} | 21 +- .../auxiliary/issue_41053.rs} | 6 +- src/test/run-pass/catch-expr.rs | 74 + .../run-pass/coerce-overloaded-autoderef.rs | 4 + .../run-pass/conditional-debug-macro-on.rs | 2 - src/test/run-pass/const-err.rs | 4 + ...iated_type.rs => const-pattern-variant.rs} | 36 +- .../default_ty_param_struct_and_type_alias.rs | 40 - .../diverging-fallback-control-flow.rs | 106 + .../diverging-fallback-method-chain.rs | 27 + .../run-pass/diverging-fallback-option.rs | 22 + src/test/run-pass/empty_global_asm.rs | 28 + src/test/run-pass/i128.rs | 5 + src/test/run-pass/ifmt.rs | 28 + src/test/run-pass/issue-16671.rs | 27 +- .../f07.rs => run-pass/issue-23898.rs} | 10 +- src/test/run-pass/issue-28279.rs | 3 +- src/test/run-pass/issue-29948.rs | 17 +- .../f10.rs => run-pass/issue-34571.rs} | 14 +- src/test/run-pass/issue-39808.rs | 26 + src/test/run-pass/issue-40408.rs | 16 + src/test/run-pass/issue-40951.rs | 20 + .../f08.rs => run-pass/issue-40962.rs} | 14 +- src/test/run-pass/issue-41053.rs | 30 + .../f12.rs => run-pass/issue-41213.rs} | 26 +- .../f09.rs => run-pass/issue-41272.rs} | 23 +- src/test/run-pass/issue-41298.rs | 16 + src/test/run-pass/issue-41394.rs | 17 + src/test/run-pass/issue-41479.rs | 18 + src/test/run-pass/issue-41498.rs | 26 + src/test/run-pass/issue-41604.rs | 20 + src/test/run-pass/issue-41677.rs | 37 + src/test/run-pass/issue-41803.rs | 30 + src/test/run-pass/issue-41849-variance-req.rs | 43 + ...sue-41936-variance-coerce-unsized-cycle.rs | 38 + src/test/run-pass/issue-8460.rs | 35 +- .../macro-nested_definition_issue-31946.rs | 18 + src/test/run-pass/macro-pub-matcher.rs | 115 + src/test/run-pass/mir_calls_to_shims.rs | 56 + src/test/run-pass/optimization-fuel-0.rs | 24 + src/test/run-pass/optimization-fuel-1.rs | 26 + ...ap-doesnt-conflict-with-specialization.rs} | 22 +- ...overlap-permitted-for-marker-traits-neg.rs | 20 + .../overlap-permitted-for-marker-traits.rs | 36 + src/test/run-pass/rvalue-static-promotion.rs | 17 + .../run-pass/simd-intrinsic-generic-cast.rs | 2 +- src/test/run-pass/simple_global_asm.rs | 31 + .../sync-send-iterators-in-libcollections.rs | 19 +- .../run-pass/syntax-extension-source-utils.rs | 2 +- .../run-pass/type-infer-generalize-ty-var.rs | 60 + src/test/run-pass/type-sizes.rs | 13 + src/test/run-pass/u128.rs | 45 + src/test/run-pass/union/union-transmute.rs | 8 +- src/test/run-pass/unit-fallback.rs | 38 - src/test/run-pass/while-let.rs | 2 - src/test/rustdoc/assoc-item-cast.rs | 26 + src/test/rustdoc/auxiliary/issue-40936.rs | 15 + .../auxiliary/pub-use-extern-macros.rs | 30 + src/test/rustdoc/const-doc.rs | 31 + .../const.rs} | 16 +- src/test/rustdoc/doc-assoc-item.rs | 28 + src/test/rustdoc/impl-parts.rs | 4 +- src/test/rustdoc/issue-20646.rs | 4 +- src/test/rustdoc/issue-20727-4.rs | 4 +- src/test/rustdoc/issue-40936.rs | 16 + src/test/rustdoc/pub-use-extern-macros.rs | 31 + src/test/rustdoc/test-lists.rs | 36 + src/test/rustdoc/where.rs | 2 +- ...herence-overlapping-inherent-impl-trait.rs | 4 +- ...nce-overlapping-inherent-impl-trait.stderr | 10 + .../huge_multispan_highlight.stderr | 2 +- .../overlapping_inherent_impls.rs} | 9 +- .../overlapping_inherent_impls.stderr | 29 + .../ui/compare-method/region-extra-2.stderr | 5 +- .../traits-misc-mismatch-2.stderr | 5 +- src/test/ui/did_you_mean/issue-31424.stderr | 2 + src/test/ui/did_you_mean/issue-35937.rs | 31 + src/test/ui/did_you_mean/issue-35937.stderr | 26 + src/test/ui/did_you_mean/issue-38147-2.stderr | 2 +- src/test/ui/did_you_mean/issue-38147-3.stderr | 4 +- src/test/ui/did_you_mean/issue-39544.rs | 41 +- src/test/ui/did_you_mean/issue-39544.stderr | 96 +- src/test/ui/did_you_mean/issue-40006.rs | 33 + src/test/ui/did_you_mean/issue-40006.stderr | 68 + src/test/ui/did_you_mean/issue-40396.rs | 23 + src/test/ui/did_you_mean/issue-40396.stderr | 34 + .../f02.rs => ui/did_you_mean/issue-40823.rs} | 7 +- src/test/ui/did_you_mean/issue-40823.stderr | 8 + ...dropck-eyepatch-implies-unsafe-impl.stderr | 10 +- .../impl-trait/equality.rs | 2 +- src/test/ui/impl-trait/equality.stderr | 55 + .../issue-37311.stderr | 5 +- ...x1-return-one-existing-name-if-else.stderr | 8 +- .../ex2a-push-one-existing-name.stderr | 12 +- .../ex2b-push-no-existing-names.stderr | 12 +- .../ex2c-push-inference-variable.stderr | 10 +- .../ex2d-push-inference-variable-2.stderr | 8 +- .../ex2e-push-inference-variable-3.stderr | 8 +- src/test/ui/loop-break-value-no-repeat.rs | 25 + src/test/ui/loop-break-value-no-repeat.stderr | 8 + .../macros/macro_path_as_generic_bound.stderr | 5 +- src/test/ui/mismatched_types/abridged.rs | 61 + src/test/ui/mismatched_types/abridged.stderr | 68 + src/test/ui/mismatched_types/binops.rs | 18 + src/test/ui/mismatched_types/binops.stderr | 58 + src/test/ui/mismatched_types/main.stderr | 4 +- src/test/ui/missing-items/m2.stderr | 5 +- src/test/ui/print-fuel/print-fuel.rs | 21 + src/test/ui/print-fuel/print-fuel.stdout | 1 + src/test/ui/print_type_sizes/nullable.stdout | 35 +- src/test/ui/print_type_sizes/packed.stdout | 10 +- src/test/ui/print_type_sizes/padding.stdout | 16 +- src/test/ui/print_type_sizes/repr-align.rs | 43 + .../ui/print_type_sizes/repr-align.stdout | 16 + src/test/ui/pub/pub-restricted-error-fn.rs | 13 + .../ui/pub/pub-restricted-error-fn.stderr | 8 + src/test/ui/pub/pub-restricted-error.rs | 19 + src/test/ui/pub/pub-restricted-error.stderr | 8 + .../ui/pub/pub-restricted-non-path.rs} | 8 +- .../ui/pub/pub-restricted-non-path.stderr | 8 + src/test/ui/pub/pub-restricted.rs | 37 + src/test/ui/pub/pub-restricted.stderr | 47 + src/test/ui/reachable/README.md | 7 + src/test/ui/reachable/expr_add.rs | 28 + src/test/ui/reachable/expr_add.stderr | 14 + src/test/ui/reachable/expr_again.rs | 20 + src/test/ui/reachable/expr_again.stderr | 15 + src/test/ui/reachable/expr_andand.rs | 21 + src/test/ui/reachable/expr_andand.stderr | 0 src/test/ui/reachable/expr_array.rs | 28 + src/test/ui/reachable/expr_array.stderr | 20 + src/test/ui/reachable/expr_assign.rs | 39 + src/test/ui/reachable/expr_assign.stderr | 26 + src/test/ui/reachable/expr_block.rs | 41 + src/test/ui/reachable/expr_block.stderr | 22 + .../E0102.rs => ui/reachable/expr_box.rs} | 9 +- src/test/ui/reachable/expr_box.stderr | 14 + .../reachable/expr_call.rs} | 28 +- src/test/ui/reachable/expr_call.stderr | 20 + src/test/ui/reachable/expr_cast.rs | 23 + src/test/ui/reachable/expr_cast.stderr | 14 + src/test/ui/reachable/expr_if.rs | 41 + src/test/ui/reachable/expr_if.stderr | 15 + src/test/ui/reachable/expr_loop.rs | 44 + src/test/ui/reachable/expr_loop.stderr | 31 + src/test/ui/reachable/expr_match.rs | 54 + src/test/ui/reachable/expr_match.stderr | 30 + src/test/ui/reachable/expr_method.rs | 34 + src/test/ui/reachable/expr_method.stderr | 20 + src/test/ui/reachable/expr_oror.rs | 20 + src/test/ui/reachable/expr_oror.stderr | 0 src/test/ui/reachable/expr_repeat.rs | 23 + src/test/ui/reachable/expr_repeat.stderr | 14 + src/test/ui/reachable/expr_return.rs | 24 + src/test/ui/reachable/expr_return.stderr | 14 + src/test/ui/reachable/expr_struct.rs | 43 + src/test/ui/reachable/expr_struct.stderr | 32 + src/test/ui/reachable/expr_tup.rs | 28 + src/test/ui/reachable/expr_tup.stderr | 20 + src/test/ui/reachable/expr_type.rs | 23 + src/test/ui/reachable/expr_type.stderr | 14 + src/test/ui/reachable/expr_unary.rs | 21 + src/test/ui/reachable/expr_unary.stderr | 8 + src/test/ui/reachable/expr_while.rs | 38 + src/test/ui/reachable/expr_while.stderr | 31 + .../resolve/auxiliary/privacy-struct-ctor.rs | 2 - src/test/ui/resolve/issue-3907-2.stderr | 2 +- src/test/ui/resolve/privacy-struct-ctor.rs | 2 - .../ui/resolve/privacy-struct-ctor.stderr | 32 +- .../ui/resolve/token-error-correct-3.stderr | 11 +- .../ui/resolve/token-error-correct.stderr | 2 +- src/test/{compile-fail => ui/span}/E0072.rs | 3 +- src/test/ui/span/E0072.stderr | 10 + src/test/ui/span/E0536.stderr | 2 +- src/test/ui/span/E0537.stderr | 2 +- ...ck-borrow-overloaded-auto-deref-mut.stderr | 8 +- ...orrowck-borrow-overloaded-deref-mut.stderr | 4 +- .../ui/span/borrowck-object-mutability.stderr | 3 + src/test/ui/span/coerce-suggestions.rs | 1 - src/test/ui/span/coerce-suggestions.stderr | 14 +- .../ui/span/impl-wrong-item-for-trait.stderr | 29 +- src/test/ui/span/issue-23729.stderr | 10 +- src/test/ui/span/issue-23827.stderr | 8 +- src/test/ui/span/issue-24356.stderr | 5 +- .../span/issue-29595.rs} | 12 +- src/test/ui/span/issue-29595.stderr | 10 + src/test/ui/span/issue-33884.rs | 27 + src/test/ui/span/issue-33884.stderr | 12 + src/test/ui/span/issue-34264.rs | 20 + src/test/ui/span/issue-34264.stderr | 49 + src/test/ui/span/issue-7575.stderr | 10 +- src/test/ui/span/lint-unused-unsafe.stderr | 30 +- src/test/ui/span/multiline-span-E0072.rs | 20 + src/test/ui/span/multiline-span-E0072.stderr | 15 + src/test/ui/span/multiline-span-simple.stderr | 10 +- src/test/ui/span/pub-struct-field.rs | 2 - src/test/ui/span/pub-struct-field.stderr | 14 +- .../confuse-field-and-method}/issue-18343.rs | 6 +- .../issue-18343.stderr | 10 + .../confuse-field-and-method}/issue-2392.rs | 39 +- .../issue-2392.stderr | 90 + .../confuse-field-and-method}/issue-32128.rs | 6 +- .../issue-32128.stderr | 10 + .../confuse-field-and-method}/issue-33784.rs | 9 +- .../issue-33784.stderr | 26 + .../confuse-field-and-method/private-field.rs | 29 + .../private-field.stderr | 8 + .../suggestions}/tuple-float-index.rs | 4 +- .../ui/suggestions/tuple-float-index.stderr | 11 + .../token}/bounds-obj-parens.rs | 6 +- src/test/ui/token/bounds-obj-parens.stderr | 8 + .../token}/issue-10636-2.rs | 2 + src/test/ui/token/issue-10636-2.stderr | 28 + .../f01.rs => ui/token/issue-41155.rs} | 6 +- src/test/ui/token/issue-41155.stderr | 18 + .../token}/macro-incomplete-parse.rs | 2 + .../ui/token/macro-incomplete-parse.stderr | 32 + .../token}/trailing-plus-in-bounds.rs | 8 +- .../ui/token/trailing-plus-in-bounds.stderr | 8 + ...12-2.rs => cannot_infer_local_or_array.rs} | 2 +- .../cannot_infer_local_or_array.stderr | 10 + ...-38812.rs => cannot_infer_local_or_vec.rs} | 0 ...tderr => cannot_infer_local_or_vec.stderr} | 2 +- .../cannot_infer_local_or_vec_in_tuples.rs | 13 + ...cannot_infer_local_or_vec_in_tuples.stderr | 12 + src/test/ui/type-check/issue-22897.rs | 15 + src/test/ui/type-check/issue-22897.stderr | 8 + src/test/ui/type-check/issue-38812-2.stderr | 12 - src/test/ui/type-check/issue-40294.stderr | 5 +- .../ui/type-check/unknown_type_for_closure.rs | 13 + .../unknown_type_for_closure.stderr | 8 + src/tools/build-manifest/src/main.rs | 47 +- src/tools/cargotest/lockfiles/iron-Cargo.lock | 359 +- src/tools/cargotest/main.rs | 2 +- src/tools/compiletest/Cargo.toml | 2 +- src/tools/compiletest/src/json.rs | 1 + src/tools/compiletest/src/main.rs | 5 +- src/tools/compiletest/src/procsrv.rs | 5 +- src/tools/compiletest/src/raise_fd_limit.rs | 2 +- src/tools/compiletest/src/runtest.rs | 38 +- src/tools/error_index_generator/main.rs | 6 +- src/tools/linkchecker/main.rs | 15 +- src/tools/rustbook/Cargo.toml | 2 +- src/tools/tidy/Cargo.toml | 2 - src/tools/tidy/src/bins.rs | 3 +- src/tools/tidy/src/cargo.rs | 5 +- src/tools/tidy/src/errors.rs | 5 +- src/tools/tidy/src/features.rs | 155 +- src/tools/tidy/src/main.rs | 21 +- src/tools/tidy/src/pal.rs | 5 +- src/tools/tidy/src/style.rs | 9 +- src/tools/tidy/src/unstable_book.rs | 142 + src/vendor/aho-corasick/.cargo-checksum.json | 2 +- src/vendor/aho-corasick/Cargo.toml | 2 +- src/vendor/aho-corasick/src/autiter.rs | 27 + src/vendor/atty/.cargo-checksum.json | 1 + src/vendor/atty/.cargo-ok | 0 src/vendor/atty/.gitignore | 3 + src/vendor/atty/.travis.yml | 44 + src/vendor/atty/CHANGELOG.md | 25 + src/vendor/atty/Cargo.toml | 17 + src/vendor/atty/LICENSE | 20 + src/vendor/atty/README.md | 78 + src/vendor/atty/appveyor.yml | 17 + src/vendor/atty/examples/atty.rs | 9 + src/vendor/atty/src/lib.rs | 183 + src/vendor/bitflags/.cargo-checksum.json | 2 +- src/vendor/bitflags/.travis.yml | 20 +- src/vendor/bitflags/Cargo.toml | 6 +- src/vendor/bitflags/README.md | 21 +- src/vendor/bitflags/src/lib.rs | 48 +- src/vendor/bitflags/tests/i128_bitflags.rs | 30 + src/vendor/clap/.cargo-checksum.json | 2 +- src/vendor/clap/CHANGELOG.md | 95 + src/vendor/clap/CONTRIBUTORS.md | 65 +- src/vendor/clap/Cargo.toml | 21 +- src/vendor/clap/README.md | 155 +- src/vendor/clap/clap-test.rs | 11 +- src/vendor/clap/justfile | 7 +- src/vendor/clap/src/app/help.rs | 55 +- src/vendor/clap/src/app/macros.rs | 142 +- src/vendor/clap/src/app/mod.rs | 129 +- src/vendor/clap/src/app/parser.rs | 1973 +-- src/vendor/clap/src/app/settings.rs | 166 +- src/vendor/clap/src/app/usage.rs | 437 + src/vendor/clap/src/app/validator.rs | 454 + src/vendor/clap/src/args/any_arg.rs | 7 +- src/vendor/clap/src/args/arg.rs | 883 +- src/vendor/clap/src/args/arg_builder/base.rs | 47 +- src/vendor/clap/src/args/arg_builder/flag.rs | 34 +- .../clap/src/args/arg_builder/option.rs | 57 +- .../clap/src/args/arg_builder/positional.rs | 50 +- .../clap/src/args/arg_builder/switched.rs | 11 +- .../clap/src/args/arg_builder/valued.rs | 35 +- src/vendor/clap/src/args/arg_matcher.rs | 21 +- src/vendor/clap/src/args/arg_matches.rs | 66 +- src/vendor/clap/src/args/group.rs | 1 + src/vendor/clap/src/args/matched_arg.rs | 7 +- src/vendor/clap/src/args/mod.rs | 10 - src/vendor/clap/src/args/settings.rs | 50 +- src/vendor/clap/src/completions/bash.rs | 38 +- src/vendor/clap/src/completions/fish.rs | 3 + src/vendor/clap/src/completions/powershell.rs | 9 +- src/vendor/clap/src/errors.rs | 64 +- src/vendor/clap/src/fmt.rs | 20 +- src/vendor/clap/src/lib.rs | 10 +- src/vendor/clap/src/macros.rs | 268 +- src/vendor/clap/src/osstringext.rs | 2 +- src/vendor/clap/src/suggestions.rs | 5 +- src/vendor/clap/src/usage_parser.rs | 894 +- src/vendor/cmake/.cargo-checksum.json | 2 +- src/vendor/cmake/Cargo.toml | 2 +- src/vendor/cmake/src/lib.rs | 16 +- .../env_logger-0.3.5/.cargo-checksum.json | 1 - src/vendor/env_logger-0.3.5/Cargo.toml | 23 - src/vendor/env_logger-0.3.5/src/lib.rs | 623 - src/vendor/env_logger-0.3.5/src/regex.rs | 28 - src/vendor/env_logger-0.3.5/src/string.rs | 21 - .../env_logger-0.3.5/tests/regexp_filter.rs | 51 - src/vendor/gcc/.cargo-checksum.json | 2 +- src/vendor/gcc/Cargo.toml | 2 +- src/vendor/gcc/src/lib.rs | 71 +- src/vendor/gcc/tests/test.rs | 1 - src/vendor/handlebars/.cargo-checksum.json | 2 +- src/vendor/handlebars/CHANGELOG.md | 4 + src/vendor/handlebars/Cargo.toml | 2 +- src/vendor/handlebars/src/partial.rs | 47 +- src/vendor/lazy_static/.cargo-checksum.json | 2 +- src/vendor/lazy_static/Cargo.toml | 2 +- src/vendor/lazy_static/src/lib.rs | 9 +- src/vendor/mdbook/.cargo-checksum.json | 2 +- src/vendor/mdbook/Cargo.toml | 108 +- src/vendor/mdbook/README.md | 252 +- src/vendor/mdbook/src/book/mod.rs | 946 +- src/vendor/mdbook/src/lib.rs | 178 +- .../renderer/html_handlebars/hbs_renderer.rs | 675 +- .../html_handlebars/helpers/playpen.rs | 390 +- .../renderer/html_handlebars/helpers/toc.rs | 276 +- src/vendor/mdbook/src/theme/book.css | 1636 +- src/vendor/mdbook/src/theme/book.js | 459 +- src/vendor/mdbook/src/theme/index.hbs | 233 +- src/vendor/mdbook/src/theme/mod.rs | 210 +- .../mdbook/src/theme/stylus/general.styl | 75 +- .../mdbook/src/theme/stylus/themes/base.styl | 256 +- .../mdbook/src/theme/stylus/themes/coal.styl | 56 +- .../mdbook/src/theme/stylus/themes/index.styl | 8 +- .../mdbook/src/theme/stylus/themes/light.styl | 56 +- .../mdbook/src/theme/stylus/themes/navy.styl | 56 +- .../mdbook/src/theme/stylus/themes/rust.styl | 56 +- .../pulldown-cmark-0.0.8/.cargo-checksum.json | 1 + src/vendor/pulldown-cmark-0.0.8/.cargo-ok | 0 src/vendor/pulldown-cmark-0.0.8/.gitignore | 3 + .../pulldown-cmark-0.0.8/CONTRIBUTING.md | 24 + src/vendor/pulldown-cmark-0.0.8/Cargo.toml | 15 + src/vendor/pulldown-cmark-0.0.8/LICENSE | 21 + src/vendor/pulldown-cmark-0.0.8/README.md | 108 + .../pulldown-cmark-0.0.8/specs/footnotes.txt | 154 + .../pulldown-cmark-0.0.8/specs/table.txt | 215 + .../pulldown-cmark-0.0.8/src/entities.rs | 4284 +++++ src/vendor/pulldown-cmark-0.0.8/src/escape.rs | 120 + src/vendor/pulldown-cmark-0.0.8/src/html.rs | 237 + src/vendor/pulldown-cmark-0.0.8/src/lib.rs | 37 + src/vendor/pulldown-cmark-0.0.8/src/main.rs | 193 + src/vendor/pulldown-cmark-0.0.8/src/parse.rs | 1675 ++ src/vendor/pulldown-cmark-0.0.8/src/passes.rs | 102 + .../pulldown-cmark-0.0.8/src/puncttable.rs | 348 + .../pulldown-cmark-0.0.8/src/scanners.rs | 666 + src/vendor/pulldown-cmark-0.0.8/src/utils.rs | 53 + .../pulldown-cmark-0.0.8/tools/mk_entities.py | 72 + .../tools/mk_puncttable.py | 130 + .../pulldown-cmark/.cargo-checksum.json | 2 +- src/vendor/pulldown-cmark/Cargo.toml | 14 +- src/vendor/pulldown-cmark/README.md | 16 + src/vendor/pulldown-cmark/build.rs | 149 + src/vendor/pulldown-cmark/specs/footnotes.txt | 33 +- src/vendor/pulldown-cmark/specs/table.txt | 53 +- src/vendor/pulldown-cmark/src/html.rs | 118 +- src/vendor/pulldown-cmark/src/lib.rs | 5 + src/vendor/pulldown-cmark/src/main.rs | 167 +- src/vendor/pulldown-cmark/src/parse.rs | 92 +- src/vendor/pulldown-cmark/src/scanners.rs | 65 +- src/vendor/pulldown-cmark/tests/footnotes.rs | 247 + src/vendor/pulldown-cmark/tests/html.rs | 208 + src/vendor/pulldown-cmark/tests/spec.rs | 14280 ++++++++++++++++ src/vendor/pulldown-cmark/tests/table.rs | 355 + .../third_party/CommonMark/LICENSE | 105 + .../third_party/CommonMark/README.google | 12 + .../third_party/CommonMark/spec.txt | 9353 ++++++++++ src/vendor/rls-data/.cargo-checksum.json | 1 + src/vendor/rls-data/.cargo-ok | 0 src/vendor/rls-data/.gitignore | 2 + src/vendor/rls-data/Cargo.toml | 12 + src/vendor/rls-data/README.md | 11 + src/vendor/rls-data/src/lib.rs | 213 + src/vendor/rls-span/.cargo-checksum.json | 1 + src/vendor/rls-span/.cargo-ok | 0 src/vendor/rls-span/.gitignore | 1 + src/vendor/rls-span/Cargo.toml | 18 + src/vendor/rls-span/src/compiler.rs | 78 + src/vendor/rls-span/src/lib.rs | 435 + .../rustc-serialize/.cargo-checksum.json | 2 +- src/vendor/rustc-serialize/Cargo.toml | 2 +- src/vendor/rustc-serialize/src/json.rs | 9 +- src/vendor/rustc-serialize/src/lib.rs | 3 + src/vendor/vec_map/.cargo-checksum.json | 2 +- src/vendor/vec_map/Cargo.toml | 8 +- src/vendor/vec_map/src/lib.rs | 5 +- version | 2 +- 2135 files changed, 141074 insertions(+), 35140 deletions(-) create mode 100644 rls/.travis.yml create mode 100644 rls/COPYRIGHT create mode 100644 rls/Cargo.lock create mode 100644 rls/Cargo.toml create mode 100644 rls/LICENSE-APACHE create mode 100644 rls/LICENSE-MIT create mode 100644 rls/README.md create mode 100644 rls/appveyor.yml create mode 100644 rls/contributing.md create mode 100755 rls/goto_def.sh create mode 100755 rls/ls.sh create mode 100644 rls/src/actions/compiler_message_parsing.rs create mode 100644 rls/src/actions/lsp_extensions.rs create mode 100644 rls/src/actions/mod.rs create mode 100644 rls/src/build.rs create mode 100644 rls/src/config.rs create mode 100644 rls/src/lsp_data.rs create mode 100644 rls/src/main.rs create mode 100644 rls/src/server.rs create mode 100644 rls/src/test/mod.rs create mode 100644 rls/src/test/types.rs create mode 100644 rls/test_data/borrow_error/Cargo.lock create mode 100644 rls/test_data/borrow_error/Cargo.toml create mode 100644 rls/test_data/borrow_error/src/main.rs create mode 100644 rls/test_data/completion/Cargo.lock create mode 100644 rls/test_data/completion/Cargo.toml create mode 100644 rls/test_data/completion/src/main.rs create mode 100644 rls/test_data/find_all_refs/Cargo.lock create mode 100644 rls/test_data/find_all_refs/Cargo.toml create mode 100644 rls/test_data/find_all_refs/src/main.rs create mode 100644 rls/test_data/find_all_refs_no_cfg_test/Cargo.lock create mode 100644 rls/test_data/find_all_refs_no_cfg_test/Cargo.toml create mode 100644 rls/test_data/find_all_refs_no_cfg_test/rls.toml create mode 100644 rls/test_data/find_all_refs_no_cfg_test/src/main.rs create mode 100644 rls/test_data/goto_def/Cargo.lock create mode 100644 rls/test_data/goto_def/Cargo.toml create mode 100644 rls/test_data/goto_def/src/main.rs create mode 100644 rls/test_data/highlight/Cargo.lock create mode 100644 rls/test_data/highlight/Cargo.toml create mode 100644 rls/test_data/highlight/src/main.rs create mode 100644 rls/test_data/hover/Cargo.lock create mode 100644 rls/test_data/hover/Cargo.toml create mode 100644 rls/test_data/hover/src/main.rs create mode 100644 rls/test_data/rename/Cargo.lock create mode 100644 rls/test_data/rename/Cargo.toml create mode 100644 rls/test_data/rename/rls.toml create mode 100644 rls/test_data/rename/src/main.rs rename src/ci/docker/{dist-armv7-aarch64-linux => dist-aarch64-linux}/Dockerfile (79%) rename src/ci/docker/{dist-armv7-aarch64-linux => dist-aarch64-linux}/aarch64-linux-gnu.config (100%) create mode 100755 src/ci/docker/dist-aarch64-linux/build-toolchains.sh create mode 100644 src/ci/docker/dist-armhf-linux/Dockerfile rename src/ci/docker/{dist-arm-linux => dist-armhf-linux}/arm-linux-gnueabihf.config (100%) create mode 100755 src/ci/docker/dist-armhf-linux/build-toolchains.sh create mode 100644 src/ci/docker/dist-armv7-linux/Dockerfile rename src/ci/docker/{dist-armv7-aarch64-linux => dist-armv7-linux}/armv7-linux-gnueabihf.config (100%) rename src/ci/docker/{dist-armv7-aarch64-linux => dist-armv7-linux}/build-toolchains.sh (88%) rename src/ci/docker/{dist-freebsd => dist-i686-freebsd}/Dockerfile (77%) rename src/ci/docker/{dist-freebsd => dist-i686-freebsd}/build-toolchain.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/Dockerfile (98%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-binutils.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-cmake.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-curl.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-gcc.sh (79%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-git.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-headers.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-openssl.sh (86%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/build-python.sh (100%) rename src/ci/docker/{dist-x86-linux => dist-i686-linux}/shared.sh (100%) create mode 100644 src/ci/docker/dist-mips64el-linux/Dockerfile create mode 100644 src/ci/docker/dist-mipsel-linux/Dockerfile create mode 100644 src/ci/docker/dist-powerpc64le-linux/Dockerfile rename src/ci/docker/{dist-powerpc64-linux => dist-powerpc64le-linux}/build-powerpc64le-toolchain.sh (100%) create mode 100644 src/ci/docker/dist-powerpc64le-linux/shared.sh delete mode 100755 src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh rename src/ci/docker/{dist-s390x-linux-netbsd => dist-s390x-linux}/Dockerfile (86%) rename src/ci/docker/{dist-s390x-linux-netbsd => dist-s390x-linux}/build-s390x-toolchain.sh (100%) rename src/ci/docker/{dist-s390x-linux-netbsd => dist-s390x-linux}/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch (100%) rename src/ci/docker/{dist-s390x-linux-netbsd => dist-s390x-linux}/s390x-linux-gnu.config (100%) create mode 100644 src/ci/docker/dist-x86_64-freebsd/Dockerfile create mode 100755 src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh create mode 100644 src/ci/docker/dist-x86_64-linux/Dockerfile create mode 100755 src/ci/docker/dist-x86_64-linux/build-binutils.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-cmake.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-curl.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-gcc.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-git.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-headers.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-openssl.sh create mode 100755 src/ci/docker/dist-x86_64-linux/build-python.sh create mode 100644 src/ci/docker/dist-x86_64-linux/shared.sh create mode 100644 src/ci/docker/dist-x86_64-netbsd/Dockerfile create mode 100755 src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh create mode 100755 src/ci/init_repo.sh create mode 100644 src/doc/book/.github/ISSUE_TEMPLATE.md create mode 100644 src/doc/book/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 src/doc/book/.travis.yml create mode 100644 src/doc/book/CONTRIBUTING.md create mode 100644 src/doc/book/COPYRIGHT create mode 100644 src/doc/book/LICENSE-APACHE create mode 100644 src/doc/book/LICENSE-MIT create mode 100644 src/doc/book/README.md create mode 100644 src/doc/book/ci/build.sh create mode 100644 src/doc/book/ci/deploy.sh create mode 100644 src/doc/book/ci/stable-check/Cargo.lock create mode 100644 src/doc/book/ci/stable-check/Cargo.toml create mode 100644 src/doc/book/ci/stable-check/src/main.rs create mode 100644 src/doc/book/first-edition/book.toml rename src/doc/book/{ => first-edition}/src/README.md (100%) rename src/doc/book/{ => first-edition}/src/SUMMARY.md (100%) rename src/doc/book/{ => first-edition}/src/associated-types.md (100%) rename src/doc/book/{ => first-edition}/src/attributes.md (96%) rename src/doc/book/{ => first-edition}/src/bibliography.md (97%) rename src/doc/book/{ => first-edition}/src/borrow-and-asref.md (92%) rename src/doc/book/{ => first-edition}/src/casting-between-types.md (100%) rename src/doc/book/{ => first-edition}/src/chapter_1.md (100%) rename src/doc/book/{ => first-edition}/src/choosing-your-guarantees.md (97%) rename src/doc/book/{ => first-edition}/src/closures.md (96%) rename src/doc/book/{ => first-edition}/src/comments.md (100%) rename src/doc/book/{ => first-edition}/src/concurrency.md (97%) rename src/doc/book/{ => first-edition}/src/conditional-compilation.md (100%) rename src/doc/book/{ => first-edition}/src/const-and-static.md (100%) rename src/doc/book/{ => first-edition}/src/crates-and-modules.md (96%) rename src/doc/book/{ => first-edition}/src/deref-coercions.md (98%) rename src/doc/book/{ => first-edition}/src/documentation.md (95%) rename src/doc/book/{ => first-edition}/src/drop.md (95%) rename src/doc/book/{ => first-edition}/src/effective-rust.md (100%) rename src/doc/book/{ => first-edition}/src/enums.md (100%) rename src/doc/book/{ => first-edition}/src/error-handling.md (95%) rename src/doc/book/{ => first-edition}/src/ffi.md (97%) rename src/doc/book/{ => first-edition}/src/functions.md (100%) rename src/doc/book/{ => first-edition}/src/generics.md (97%) rename src/doc/book/{ => first-edition}/src/getting-started.md (100%) rename src/doc/book/{ => first-edition}/src/glossary.md (97%) rename src/doc/book/{ => first-edition}/src/guessing-game.md (98%) rename src/doc/book/{ => first-edition}/src/if-let.md (100%) rename src/doc/book/{ => first-edition}/src/if.md (100%) rename src/doc/book/{ => first-edition}/src/iterators.md (97%) rename src/doc/book/{ => first-edition}/src/lifetimes.md (100%) rename src/doc/book/{ => first-edition}/src/loops.md (88%) rename src/doc/book/{ => first-edition}/src/macros.md (99%) rename src/doc/book/{ => first-edition}/src/match.md (100%) rename src/doc/book/{ => first-edition}/src/method-syntax.md (100%) rename src/doc/book/{ => first-edition}/src/mutability.md (97%) rename src/doc/book/{ => first-edition}/src/operators-and-overloading.md (97%) rename src/doc/book/{ => first-edition}/src/ownership.md (100%) rename src/doc/book/{ => first-edition}/src/patterns.md (100%) rename src/doc/book/{ => first-edition}/src/primitive-types.md (92%) rename src/doc/book/{ => first-edition}/src/procedural-macros.md (99%) rename src/doc/book/{ => first-edition}/src/raw-pointers.md (98%) rename src/doc/book/{ => first-edition}/src/references-and-borrowing.md (100%) rename src/doc/book/{ => first-edition}/src/release-channels.md (100%) rename src/doc/book/{ => first-edition}/src/strings.md (98%) rename src/doc/book/{ => first-edition}/src/structs.md (100%) rename src/doc/book/{ => first-edition}/src/syntax-and-semantics.md (100%) rename src/doc/book/{ => first-edition}/src/syntax-index.md (97%) rename src/doc/book/{ => first-edition}/src/testing.md (99%) rename src/doc/book/{ => first-edition}/src/the-stack-and-the-heap.md (99%) rename src/doc/book/{ => first-edition}/src/trait-objects.md (99%) rename src/doc/book/{ => first-edition}/src/traits.md (95%) rename src/doc/book/{ => first-edition}/src/type-aliases.md (97%) rename src/doc/book/{ => first-edition}/src/ufcs.md (100%) rename src/doc/book/{ => first-edition}/src/unsafe.md (98%) rename src/doc/book/{ => first-edition}/src/unsized-types.md (100%) rename src/doc/book/{ => first-edition}/src/using-rust-without-the-standard-library.md (80%) rename src/doc/book/{ => first-edition}/src/variable-bindings.md (99%) rename src/doc/book/{ => first-edition}/src/vectors.md (95%) create mode 100644 src/doc/book/index.md create mode 100644 src/doc/book/redirects/README.md create mode 100644 src/doc/book/redirects/SUMMARY.md create mode 100644 src/doc/book/redirects/associated-types.md create mode 100644 src/doc/book/redirects/attributes.md create mode 100644 src/doc/book/redirects/bibliography.md create mode 100644 src/doc/book/redirects/borrow-and-asref.md create mode 100644 src/doc/book/redirects/casting-between-types.md create mode 100644 src/doc/book/redirects/choosing-your-guarantees.md create mode 100644 src/doc/book/redirects/closures.md create mode 100644 src/doc/book/redirects/comments.md create mode 100644 src/doc/book/redirects/compiler-plugins.md create mode 100644 src/doc/book/redirects/concurrency.md create mode 100644 src/doc/book/redirects/conditional-compilation.md create mode 100644 src/doc/book/redirects/const-and-static.md create mode 100644 src/doc/book/redirects/crates-and-modules.md create mode 100644 src/doc/book/redirects/deref-coercions.md create mode 100644 src/doc/book/redirects/documentation.md create mode 100644 src/doc/book/redirects/drop.md create mode 100644 src/doc/book/redirects/effective-rust.md create mode 100644 src/doc/book/redirects/enums.md create mode 100644 src/doc/book/redirects/error-handling.md create mode 100644 src/doc/book/redirects/ffi.md create mode 100644 src/doc/book/redirects/functions.md create mode 100644 src/doc/book/redirects/generics.md create mode 100644 src/doc/book/redirects/getting-started.md create mode 100644 src/doc/book/redirects/glossary.md create mode 100644 src/doc/book/redirects/guessing-game.md create mode 100644 src/doc/book/redirects/if-let.md create mode 100644 src/doc/book/redirects/if.md create mode 100644 src/doc/book/redirects/iterators.md create mode 100644 src/doc/book/redirects/lifetimes.md create mode 100644 src/doc/book/redirects/loops.md create mode 100644 src/doc/book/redirects/macros.md create mode 100644 src/doc/book/redirects/match.md create mode 100644 src/doc/book/redirects/method-syntax.md create mode 100644 src/doc/book/redirects/mutability.md create mode 100644 src/doc/book/redirects/operators-and-overloading.md create mode 100644 src/doc/book/redirects/ownership.md create mode 100644 src/doc/book/redirects/patterns.md create mode 100644 src/doc/book/redirects/primitive-types.md create mode 100644 src/doc/book/redirects/procedural-macros.md create mode 100644 src/doc/book/redirects/raw-pointers.md create mode 100644 src/doc/book/redirects/references-and-borrowing.md create mode 100644 src/doc/book/redirects/release-channels.md create mode 100644 src/doc/book/redirects/strings.md create mode 100644 src/doc/book/redirects/structs.md create mode 100644 src/doc/book/redirects/syntax-and-semantics.md create mode 100644 src/doc/book/redirects/syntax-index.md create mode 100644 src/doc/book/redirects/testing.md create mode 100644 src/doc/book/redirects/the-stack-and-the-heap.md create mode 100644 src/doc/book/redirects/trait-objects.md create mode 100644 src/doc/book/redirects/traits.md create mode 100644 src/doc/book/redirects/type-aliases.md create mode 100644 src/doc/book/redirects/ufcs.md create mode 100644 src/doc/book/redirects/unsafe.md create mode 100644 src/doc/book/redirects/unsized-types.md create mode 100644 src/doc/book/redirects/using-rust-without-the-standard-library.md create mode 100644 src/doc/book/redirects/variable-bindings.md create mode 100644 src/doc/book/redirects/vectors.md create mode 100644 src/doc/book/second-edition/Cargo.lock create mode 100644 src/doc/book/second-edition/Cargo.toml create mode 100644 src/doc/book/second-edition/LICENSE-APACHE create mode 100644 src/doc/book/second-edition/LICENSE-MIT create mode 100644 src/doc/book/second-edition/book.toml create mode 100644 src/doc/book/second-edition/dictionary.txt create mode 100755 src/doc/book/second-edition/doc-to-md.sh create mode 100644 src/doc/book/second-edition/dot/trpl04-01.dot create mode 100644 src/doc/book/second-edition/dot/trpl04-02.dot create mode 100644 src/doc/book/second-edition/dot/trpl04-03.dot create mode 100644 src/doc/book/second-edition/dot/trpl04-04.dot create mode 100644 src/doc/book/second-edition/dot/trpl04-05.dot create mode 100644 src/doc/book/second-edition/dot/trpl04-06.dot create mode 100644 src/doc/book/second-edition/dot/trpl15-01.dot create mode 100644 src/doc/book/second-edition/dot/trpl15-02.dot create mode 100644 src/doc/book/second-edition/dot/trpl15-03.dot create mode 100755 src/doc/book/second-edition/nostarch.sh create mode 100644 src/doc/book/second-edition/nostarch/appendix.md create mode 100644 src/doc/book/second-edition/nostarch/chapter01.md create mode 100644 src/doc/book/second-edition/nostarch/chapter02.md create mode 100644 src/doc/book/second-edition/nostarch/chapter03.md create mode 100644 src/doc/book/second-edition/nostarch/chapter04.md create mode 100644 src/doc/book/second-edition/nostarch/chapter05.md create mode 100644 src/doc/book/second-edition/nostarch/chapter06.md create mode 100644 src/doc/book/second-edition/nostarch/chapter07.md create mode 100644 src/doc/book/second-edition/nostarch/chapter08.md create mode 100644 src/doc/book/second-edition/nostarch/chapter09.md create mode 100644 src/doc/book/second-edition/nostarch/chapter10.md create mode 100644 src/doc/book/second-edition/nostarch/chapter11.md create mode 100644 src/doc/book/second-edition/nostarch/chapter12.md create mode 100644 src/doc/book/second-edition/nostarch/chapter13.md create mode 100644 src/doc/book/second-edition/nostarch/chapter14.md create mode 100644 src/doc/book/second-edition/nostarch/chapter15.md create mode 100644 src/doc/book/second-edition/nostarch/chapter16.md create mode 100644 src/doc/book/second-edition/nostarch/chapter17.md create mode 100644 src/doc/book/second-edition/nostarch/chapter18.md create mode 100644 src/doc/book/second-edition/nostarch/odt/chapter02.doc create mode 100644 src/doc/book/second-edition/nostarch/odt/chapter03.docx create mode 100644 src/doc/book/second-edition/nostarch/odt/chapter04.docx create mode 100644 src/doc/book/second-edition/nostarch/odt/chapter05.odt create mode 100644 src/doc/book/second-edition/nostarch/odt/chapter06.docx create mode 100644 src/doc/book/second-edition/nostarch/odt/chapter07.docx create mode 100644 src/doc/book/second-edition/nostarch/odt/chapter08.docx create mode 100644 src/doc/book/second-edition/nostarch/odt/chapter09.docx create mode 100755 src/doc/book/second-edition/spellcheck.sh create mode 100644 src/doc/book/second-edition/src/SUMMARY.md create mode 100644 src/doc/book/second-edition/src/appendix-00.md create mode 100644 src/doc/book/second-edition/src/appendix-01-keywords.md create mode 100644 src/doc/book/second-edition/src/appendix-02-operators.md create mode 100644 src/doc/book/second-edition/src/appendix-06-translation.md create mode 100644 src/doc/book/second-edition/src/appendix-07-newest-features.md create mode 100644 src/doc/book/second-edition/src/ch01-00-introduction.md create mode 100644 src/doc/book/second-edition/src/ch01-01-installation.md create mode 100644 src/doc/book/second-edition/src/ch01-02-hello-world.md create mode 100644 src/doc/book/second-edition/src/ch02-00-guessing-game-tutorial.md create mode 100644 src/doc/book/second-edition/src/ch03-00-common-programming-concepts.md create mode 100644 src/doc/book/second-edition/src/ch03-01-variables-and-mutability.md create mode 100644 src/doc/book/second-edition/src/ch03-02-data-types.md create mode 100644 src/doc/book/second-edition/src/ch03-03-how-functions-work.md create mode 100644 src/doc/book/second-edition/src/ch03-04-comments.md create mode 100644 src/doc/book/second-edition/src/ch03-05-control-flow.md create mode 100644 src/doc/book/second-edition/src/ch04-00-understanding-ownership.md create mode 100644 src/doc/book/second-edition/src/ch04-01-what-is-ownership.md create mode 100644 src/doc/book/second-edition/src/ch04-02-references-and-borrowing.md create mode 100644 src/doc/book/second-edition/src/ch04-03-slices.md create mode 100644 src/doc/book/second-edition/src/ch05-00-structs.md create mode 100644 src/doc/book/second-edition/src/ch05-01-method-syntax.md create mode 100644 src/doc/book/second-edition/src/ch06-00-enums.md create mode 100644 src/doc/book/second-edition/src/ch06-01-defining-an-enum.md create mode 100644 src/doc/book/second-edition/src/ch06-02-match.md create mode 100644 src/doc/book/second-edition/src/ch06-03-if-let.md create mode 100644 src/doc/book/second-edition/src/ch07-00-modules.md create mode 100644 src/doc/book/second-edition/src/ch07-01-mod-and-the-filesystem.md create mode 100644 src/doc/book/second-edition/src/ch07-02-controlling-visibility-with-pub.md create mode 100644 src/doc/book/second-edition/src/ch07-03-importing-names-with-use.md create mode 100644 src/doc/book/second-edition/src/ch08-00-common-collections.md create mode 100644 src/doc/book/second-edition/src/ch08-01-vectors.md create mode 100644 src/doc/book/second-edition/src/ch08-02-strings.md create mode 100644 src/doc/book/second-edition/src/ch08-03-hash-maps.md create mode 100644 src/doc/book/second-edition/src/ch09-00-error-handling.md create mode 100644 src/doc/book/second-edition/src/ch09-01-unrecoverable-errors-with-panic.md create mode 100644 src/doc/book/second-edition/src/ch09-02-recoverable-errors-with-result.md create mode 100644 src/doc/book/second-edition/src/ch09-03-to-panic-or-not-to-panic.md create mode 100644 src/doc/book/second-edition/src/ch10-00-generics.md create mode 100644 src/doc/book/second-edition/src/ch10-01-syntax.md create mode 100644 src/doc/book/second-edition/src/ch10-02-traits.md create mode 100644 src/doc/book/second-edition/src/ch10-03-lifetime-syntax.md create mode 100644 src/doc/book/second-edition/src/ch11-00-testing.md create mode 100644 src/doc/book/second-edition/src/ch11-01-writing-tests.md create mode 100644 src/doc/book/second-edition/src/ch11-02-running-tests.md create mode 100644 src/doc/book/second-edition/src/ch11-03-test-organization.md create mode 100644 src/doc/book/second-edition/src/ch12-00-an-io-project.md create mode 100644 src/doc/book/second-edition/src/ch12-01-accepting-command-line-arguments.md create mode 100644 src/doc/book/second-edition/src/ch12-02-reading-a-file.md create mode 100644 src/doc/book/second-edition/src/ch12-03-improving-error-handling-and-modularity.md create mode 100644 src/doc/book/second-edition/src/ch12-04-testing-the-librarys-functionality.md create mode 100644 src/doc/book/second-edition/src/ch12-05-working-with-environment-variables.md create mode 100644 src/doc/book/second-edition/src/ch12-06-writing-to-stderr-instead-of-stdout.md create mode 100644 src/doc/book/second-edition/src/ch13-00-functional-features.md create mode 100644 src/doc/book/second-edition/src/ch13-01-closures.md create mode 100644 src/doc/book/second-edition/src/ch13-02-iterators.md create mode 100644 src/doc/book/second-edition/src/ch13-03-improving-our-io-project.md create mode 100644 src/doc/book/second-edition/src/ch13-04-performance.md create mode 100644 src/doc/book/second-edition/src/ch14-00-more-about-cargo.md create mode 100644 src/doc/book/second-edition/src/ch14-01-release-profiles.md create mode 100644 src/doc/book/second-edition/src/ch14-02-publishing-to-crates-io.md create mode 100644 src/doc/book/second-edition/src/ch14-03-cargo-workspaces.md create mode 100644 src/doc/book/second-edition/src/ch14-04-installing-binaries.md create mode 100644 src/doc/book/second-edition/src/ch14-05-extending-cargo.md create mode 100644 src/doc/book/second-edition/src/ch15-00-smart-pointers.md create mode 100644 src/doc/book/second-edition/src/ch15-01-box.md create mode 100644 src/doc/book/second-edition/src/ch15-02-deref.md create mode 100644 src/doc/book/second-edition/src/ch15-03-drop.md create mode 100644 src/doc/book/second-edition/src/ch15-04-rc.md create mode 100644 src/doc/book/second-edition/src/ch15-05-interior-mutability.md create mode 100644 src/doc/book/second-edition/src/ch15-06-reference-cycles.md create mode 100644 src/doc/book/second-edition/src/ch16-00-concurrency.md create mode 100644 src/doc/book/second-edition/src/ch16-01-threads.md create mode 100644 src/doc/book/second-edition/src/ch16-02-message-passing.md create mode 100644 src/doc/book/second-edition/src/ch16-03-shared-state.md create mode 100644 src/doc/book/second-edition/src/ch16-04-extensible-concurrency-sync-and-send.md create mode 100644 src/doc/book/second-edition/src/ch17-00-oop.md create mode 100644 src/doc/book/second-edition/src/ch17-01-what-is-oo.md create mode 100644 src/doc/book/second-edition/src/ch17-02-trait-objects.md create mode 100644 src/doc/book/second-edition/src/ch17-03-oo-design-patterns.md create mode 100644 src/doc/book/second-edition/src/ch18-00-patterns.md create mode 100644 src/doc/book/second-edition/src/ch18-01-all-the-places-for-patterns.md create mode 100644 src/doc/book/second-edition/src/ch18-02-refutability.md create mode 100644 src/doc/book/second-edition/src/ch18-03-pattern-syntax.md create mode 100644 src/doc/book/second-edition/src/ch19-00-advanced-features.md create mode 100644 src/doc/book/second-edition/src/ch19-01-unsafe-rust.md create mode 100644 src/doc/book/second-edition/src/ch19-02-advanced-lifetimes.md create mode 100644 src/doc/book/second-edition/src/ch19-03-advanced-traits.md create mode 100644 src/doc/book/second-edition/src/ch19-04-advanced-types.md create mode 100644 src/doc/book/second-edition/src/ch19-05-advanced-functions-and-closures.md create mode 100644 src/doc/book/second-edition/src/ch20-00-final-project-a-web-server.md create mode 100644 src/doc/book/second-edition/src/img/trpl04-01.svg create mode 100644 src/doc/book/second-edition/src/img/trpl04-02.svg create mode 100644 src/doc/book/second-edition/src/img/trpl04-03.svg create mode 100644 src/doc/book/second-edition/src/img/trpl04-04.svg create mode 100644 src/doc/book/second-edition/src/img/trpl04-05.svg create mode 100644 src/doc/book/second-edition/src/img/trpl04-06.svg create mode 100644 src/doc/book/second-edition/src/img/trpl15-01.svg create mode 100644 src/doc/book/second-edition/src/img/trpl15-02.svg create mode 100644 src/doc/book/second-edition/src/img/trpl15-03.svg create mode 100644 src/doc/book/second-edition/src/img/trpl15-04.svg create mode 100644 src/doc/book/second-edition/style-guide.md create mode 100644 src/doc/book/second-edition/theme/index.hbs create mode 100644 src/doc/book/second-edition/tools/docx-to-md.xsl create mode 100644 src/doc/book/second-edition/tools/src/bin/concat_chapters.rs create mode 100644 src/doc/book/second-edition/tools/src/bin/lfp.rs create mode 100644 src/doc/book/second-edition/tools/src/bin/link2print.rs create mode 100644 src/doc/book/second-edition/tools/src/bin/remove_links.rs create mode 100644 src/doc/book/second-edition/tools/src/bin/remove_markup.rs delete mode 100644 src/doc/book/src/compiler-plugins.md create mode 100644 src/doc/nomicon/.travis.yml create mode 100644 src/doc/nomicon/README.md create mode 100644 src/doc/reference/.travis.yml create mode 100644 src/doc/reference/book.toml create mode 100644 src/doc/reference/src/undocumented.md create mode 100644 src/doc/reference/stable-check/Cargo.lock create mode 100644 src/doc/reference/stable-check/Cargo.toml create mode 100644 src/doc/reference/stable-check/src/main.rs delete mode 100644 src/doc/unstable-book/src/abi-msp430-interrupt.md delete mode 100644 src/doc/unstable-book/src/abi-ptx.md delete mode 100644 src/doc/unstable-book/src/compiler-builtins.md create mode 100644 src/doc/unstable-book/src/compiler-flags.md create mode 100644 src/doc/unstable-book/src/compiler-flags/linker-flavor.md delete mode 100644 src/doc/unstable-book/src/conservative-impl-trait.md delete mode 100644 src/doc/unstable-book/src/const-fn.md delete mode 100644 src/doc/unstable-book/src/const-indexing.md delete mode 100644 src/doc/unstable-book/src/field-init-shorthand.md create mode 100644 src/doc/unstable-book/src/language-features.md create mode 100644 src/doc/unstable-book/src/language-features/abi-msp430-interrupt.md create mode 100644 src/doc/unstable-book/src/language-features/abi-ptx.md rename src/doc/unstable-book/src/{ => language-features}/abi-sysv64.md (100%) rename src/doc/unstable-book/src/{ => language-features}/abi-unadjusted.md (100%) rename src/doc/unstable-book/src/{ => language-features}/abi-vectorcall.md (100%) rename src/doc/unstable-book/src/{ => language-features}/abi-x86-interrupt.md (100%) rename src/doc/unstable-book/src/{ => language-features}/advanced-slice-patterns.md (100%) rename src/doc/unstable-book/src/{ => language-features}/allocator.md (96%) rename src/doc/unstable-book/src/{ => language-features}/allow-internal-unstable.md (100%) rename src/doc/unstable-book/src/{ => language-features}/asm.md (97%) rename src/doc/unstable-book/src/{ => language-features}/associated-consts.md (100%) rename src/doc/unstable-book/src/{ => language-features}/associated-type-defaults.md (100%) rename src/doc/unstable-book/src/{ => language-features}/attr-literals.md (100%) rename src/doc/unstable-book/src/{ => language-features}/box-patterns.md (100%) rename src/doc/unstable-book/src/{ => language-features}/box-syntax.md (100%) create mode 100644 src/doc/unstable-book/src/language-features/catch-expr.md rename src/doc/unstable-book/src/{ => language-features}/cfg-target-feature.md (100%) rename src/doc/unstable-book/src/{ => language-features}/cfg-target-has-atomic.md (100%) rename src/doc/unstable-book/src/{ => language-features}/cfg-target-thread-local.md (100%) rename src/doc/unstable-book/src/{ => language-features}/cfg-target-vendor.md (100%) create mode 100644 src/doc/unstable-book/src/language-features/closure-to-fn-coercion.md create mode 100644 src/doc/unstable-book/src/language-features/compiler-builtins.md create mode 100644 src/doc/unstable-book/src/language-features/concat-idents.md create mode 100644 src/doc/unstable-book/src/language-features/conservative-impl-trait.md create mode 100644 src/doc/unstable-book/src/language-features/const-fn.md create mode 100644 src/doc/unstable-book/src/language-features/const-indexing.md rename src/doc/unstable-book/src/{ => language-features}/custom-attribute.md (100%) rename src/doc/unstable-book/src/{ => language-features}/custom-derive.md (100%) rename src/doc/unstable-book/src/{ => language-features}/default-type-parameter-fallback.md (100%) rename src/doc/unstable-book/src/{ => language-features}/drop-types-in-const.md (100%) rename src/doc/unstable-book/src/{ => language-features}/dropck-eyepatch.md (100%) rename src/doc/unstable-book/src/{ => language-features}/dropck-parametricity.md (100%) rename src/doc/unstable-book/src/{ => language-features}/exclusive-range-pattern.md (100%) rename src/doc/unstable-book/src/{ => language-features}/fundamental.md (100%) rename src/doc/unstable-book/src/{ => language-features}/generic-param-attrs.md (100%) create mode 100644 src/doc/unstable-book/src/language-features/global_asm.md create mode 100644 src/doc/unstable-book/src/language-features/i128-type.md create mode 100644 src/doc/unstable-book/src/language-features/inclusive-range-syntax.md rename src/doc/unstable-book/src/{ => language-features}/intrinsics.md (100%) rename src/doc/unstable-book/src/{ => language-features}/lang-items.md (100%) rename src/doc/unstable-book/src/{ => language-features}/link-args.md (100%) rename src/doc/unstable-book/src/{ => language-features}/link-cfg.md (100%) rename src/doc/unstable-book/src/{ => language-features}/link-llvm-intrinsics.md (100%) rename src/doc/unstable-book/src/{ => language-features}/linkage.md (100%) rename src/doc/unstable-book/src/{ => language-features}/log-syntax.md (100%) rename src/doc/unstable-book/src/{ => language-features}/loop-break-value.md (100%) rename src/doc/unstable-book/src/{ => language-features}/macro-reexport.md (100%) create mode 100644 src/doc/unstable-book/src/language-features/macro-vis-matcher.md rename src/doc/unstable-book/src/{ => language-features}/main.md (100%) rename src/doc/unstable-book/src/{ => language-features}/naked-functions.md (100%) rename src/doc/unstable-book/src/{ => language-features}/needs-allocator.md (100%) rename src/doc/unstable-book/src/{ => language-features}/needs-panic-runtime.md (100%) rename src/doc/unstable-book/src/{ => language-features}/never-type.md (100%) rename src/doc/unstable-book/src/{ => language-features}/no-core.md (100%) rename src/doc/unstable-book/src/{ => language-features}/no-debug.md (100%) create mode 100644 src/doc/unstable-book/src/language-features/non-ascii-idents.md rename src/doc/unstable-book/src/{ => language-features}/omit-gdb-pretty-printer-section.md (100%) rename src/doc/unstable-book/src/{ => language-features}/on-unimplemented.md (100%) rename src/doc/unstable-book/src/{ => language-features}/optin-builtin-traits.md (100%) create mode 100644 src/doc/unstable-book/src/language-features/overlapping-marker-traits.md rename src/doc/unstable-book/src/{ => language-features}/panic-runtime.md (100%) rename src/doc/unstable-book/src/{ => language-features}/placement-in-syntax.md (100%) rename src/doc/unstable-book/src/{ => language-features}/platform-intrinsics.md (100%) rename src/doc/unstable-book/src/{ => language-features}/plugin-registrar.md (100%) rename src/doc/unstable-book/src/{ => language-features}/plugin.md (98%) rename src/doc/unstable-book/src/{ => language-features}/prelude-import.md (100%) rename src/doc/unstable-book/src/{ => language-features}/proc-macro.md (100%) rename src/doc/unstable-book/src/{ => language-features}/quote.md (100%) rename src/doc/unstable-book/src/{ => language-features}/relaxed-adts.md (100%) create mode 100644 src/doc/unstable-book/src/language-features/repr-align.md rename src/doc/unstable-book/src/{ => language-features}/repr-simd.md (100%) rename src/doc/unstable-book/src/{ => language-features}/rustc-attrs.md (100%) rename src/doc/unstable-book/src/{ => language-features}/rustc-diagnostic-macros.md (100%) create mode 100644 src/doc/unstable-book/src/language-features/rvalue-static-promotion.md rename src/doc/unstable-book/src/{ => language-features}/sanitizer-runtime.md (100%) rename src/doc/unstable-book/src/{ => language-features}/simd-ffi.md (100%) rename src/doc/unstable-book/src/{ => language-features}/simd.md (100%) rename src/doc/unstable-book/src/{ => language-features}/slice-patterns.md (100%) rename src/doc/unstable-book/src/{ => language-features}/specialization.md (62%) rename src/doc/unstable-book/src/{ => language-features}/staged-api.md (100%) rename src/doc/unstable-book/src/{ => language-features}/start.md (100%) rename src/doc/unstable-book/src/{ => language-features}/static-nobundle.md (100%) rename src/doc/unstable-book/src/{ => language-features}/stmt-expr-attributes.md (100%) rename src/doc/unstable-book/src/{ => language-features}/struct-field-attributes.md (100%) rename src/doc/unstable-book/src/{ => language-features}/structural-match.md (100%) rename src/doc/unstable-book/src/{ => language-features}/target-feature.md (100%) rename src/doc/unstable-book/src/{ => language-features}/thread-local.md (100%) rename src/doc/unstable-book/src/{ => language-features}/trace-macros.md (100%) rename src/doc/unstable-book/src/{ => language-features}/type-ascription.md (100%) rename src/doc/unstable-book/src/{ => language-features}/unboxed-closures.md (100%) rename src/doc/unstable-book/src/{ => language-features}/untagged-unions.md (100%) rename src/doc/unstable-book/src/{ => language-features}/unwind-attributes.md (100%) rename src/doc/unstable-book/src/{ => language-features}/use-extern-macros.md (100%) create mode 100644 src/doc/unstable-book/src/language-features/used.md create mode 100644 src/doc/unstable-book/src/library-features.md rename src/doc/unstable-book/src/{ => library-features}/alloc-jemalloc.md (100%) rename src/doc/unstable-book/src/{ => library-features}/alloc-system.md (100%) create mode 100644 src/doc/unstable-book/src/library-features/alloc.md create mode 100644 src/doc/unstable-book/src/library-features/as-c-str.md create mode 100644 src/doc/unstable-book/src/library-features/ascii-ctype.md create mode 100644 src/doc/unstable-book/src/library-features/box-heap.md create mode 100644 src/doc/unstable-book/src/library-features/c-void-variant.md create mode 100644 src/doc/unstable-book/src/library-features/char-escape-debug.md create mode 100644 src/doc/unstable-book/src/library-features/coerce-unsized.md create mode 100644 src/doc/unstable-book/src/library-features/collection-placement.md create mode 100644 src/doc/unstable-book/src/library-features/collections-range.md create mode 100644 src/doc/unstable-book/src/library-features/collections.md create mode 100644 src/doc/unstable-book/src/library-features/command-envs.md create mode 100644 src/doc/unstable-book/src/library-features/compiler-builtins-lib.md create mode 100644 src/doc/unstable-book/src/library-features/compiler-fences.md rename src/doc/unstable-book/src/{concat-idents.md => library-features/concat-idents-macro.md} (84%) create mode 100644 src/doc/unstable-book/src/library-features/core-char-ext.md create mode 100644 src/doc/unstable-book/src/library-features/core-float.md create mode 100644 src/doc/unstable-book/src/library-features/core-intrinsics.md create mode 100644 src/doc/unstable-book/src/library-features/core-panic.md create mode 100644 src/doc/unstable-book/src/library-features/core-private-bignum.md create mode 100644 src/doc/unstable-book/src/library-features/core-private-diy-float.md create mode 100644 src/doc/unstable-book/src/library-features/core-slice-ext.md create mode 100644 src/doc/unstable-book/src/library-features/core-str-ext.md create mode 100644 src/doc/unstable-book/src/library-features/dec2flt.md create mode 100644 src/doc/unstable-book/src/library-features/decode-utf8.md create mode 100644 src/doc/unstable-book/src/library-features/derive-clone-copy.md create mode 100644 src/doc/unstable-book/src/library-features/derive-eq.md create mode 100644 src/doc/unstable-book/src/library-features/discriminant-value.md create mode 100644 src/doc/unstable-book/src/library-features/error-type-id.md create mode 100644 src/doc/unstable-book/src/library-features/exact-size-is-empty.md create mode 100644 src/doc/unstable-book/src/library-features/fd-read.md create mode 100644 src/doc/unstable-book/src/library-features/fd.md create mode 100644 src/doc/unstable-book/src/library-features/fixed-size-array.md create mode 100644 src/doc/unstable-book/src/library-features/float-bits-conv.md create mode 100644 src/doc/unstable-book/src/library-features/flt2dec.md create mode 100644 src/doc/unstable-book/src/library-features/fmt-flags-align.md create mode 100644 src/doc/unstable-book/src/library-features/fmt-internals.md create mode 100644 src/doc/unstable-book/src/library-features/fn-traits.md create mode 100644 src/doc/unstable-book/src/library-features/fnbox.md create mode 100644 src/doc/unstable-book/src/library-features/from_utf8_error_as_bytes.md create mode 100644 src/doc/unstable-book/src/library-features/fused.md create mode 100644 src/doc/unstable-book/src/library-features/future-atomic-orderings.md create mode 100644 src/doc/unstable-book/src/library-features/get-type-id.md create mode 100644 src/doc/unstable-book/src/library-features/heap-api.md rename src/doc/unstable-book/src/{i128-type.md => library-features/i128.md} (88%) rename src/doc/unstable-book/src/{inclusive-range-syntax.md => library-features/inclusive-range.md} (81%) create mode 100644 src/doc/unstable-book/src/library-features/int-error-internals.md create mode 100644 src/doc/unstable-book/src/library-features/integer-atomics.md create mode 100644 src/doc/unstable-book/src/library-features/into-boxed-c-str.md create mode 100644 src/doc/unstable-book/src/library-features/into-boxed-os-str.md create mode 100644 src/doc/unstable-book/src/library-features/into-boxed-path.md create mode 100644 src/doc/unstable-book/src/library-features/io-error-internals.md create mode 100644 src/doc/unstable-book/src/library-features/io.md create mode 100644 src/doc/unstable-book/src/library-features/ip.md create mode 100644 src/doc/unstable-book/src/library-features/iter-rfind.md create mode 100644 src/doc/unstable-book/src/library-features/libstd-io-internals.md create mode 100644 src/doc/unstable-book/src/library-features/libstd-sys-internals.md create mode 100644 src/doc/unstable-book/src/library-features/libstd-thread-internals.md create mode 100644 src/doc/unstable-book/src/library-features/linked-list-extras.md create mode 100644 src/doc/unstable-book/src/library-features/lookup-host.md rename src/{vendor/env_logger-0.3.5/.cargo-ok => doc/unstable-book/src/library-features/manually-drop.md} (100%) create mode 100644 src/doc/unstable-book/src/library-features/mpsc-select.md create mode 100644 src/doc/unstable-book/src/library-features/n16.md create mode 100644 src/doc/unstable-book/src/library-features/never-type-impls.md create mode 100644 src/doc/unstable-book/src/library-features/nonzero.md create mode 100644 src/doc/unstable-book/src/library-features/offset-to.md create mode 100644 src/doc/unstable-book/src/library-features/once-poison.md create mode 100644 src/doc/unstable-book/src/library-features/oom.md create mode 100644 src/doc/unstable-book/src/library-features/option-entry.md create mode 100644 src/doc/unstable-book/src/library-features/osstring-shrink-to-fit.md create mode 100644 src/doc/unstable-book/src/library-features/panic-abort.md create mode 100644 src/doc/unstable-book/src/library-features/panic-unwind.md create mode 100644 src/doc/unstable-book/src/library-features/pattern.md create mode 100644 src/doc/unstable-book/src/library-features/placement-in.md create mode 100644 src/doc/unstable-book/src/library-features/placement-new-protocol.md create mode 100644 src/doc/unstable-book/src/library-features/print.md create mode 100644 src/doc/unstable-book/src/library-features/proc-macro-internals.md create mode 100644 src/doc/unstable-book/src/library-features/question-mark-carrier.md create mode 100644 src/doc/unstable-book/src/library-features/rand.md create mode 100644 src/doc/unstable-book/src/library-features/range-contains.md create mode 100644 src/doc/unstable-book/src/library-features/raw.md create mode 100644 src/doc/unstable-book/src/library-features/reverse-cmp-key.md create mode 100644 src/doc/unstable-book/src/library-features/rt.md create mode 100644 src/doc/unstable-book/src/library-features/rustc-private.md create mode 100644 src/doc/unstable-book/src/library-features/sanitizer-runtime-lib.md create mode 100644 src/doc/unstable-book/src/library-features/set-stdio.md create mode 100644 src/doc/unstable-book/src/library-features/shared.md create mode 100644 src/doc/unstable-book/src/library-features/sip-hash-13.md create mode 100644 src/doc/unstable-book/src/library-features/slice-concat-ext.md create mode 100644 src/doc/unstable-book/src/library-features/slice-get-slice.md create mode 100644 src/doc/unstable-book/src/library-features/slice-rsplit.md create mode 100644 src/doc/unstable-book/src/library-features/sort-internals.md create mode 100644 src/doc/unstable-book/src/library-features/sort-unstable.md create mode 100644 src/doc/unstable-book/src/library-features/step-by.md create mode 100644 src/doc/unstable-book/src/library-features/step-trait.md create mode 100644 src/doc/unstable-book/src/library-features/str-checked-slicing.md create mode 100644 src/doc/unstable-book/src/library-features/str-escape.md create mode 100644 src/doc/unstable-book/src/library-features/str-internals.md create mode 100644 src/doc/unstable-book/src/library-features/str-mut-extras.md rename src/doc/unstable-book/src/{ => library-features}/test.md (100%) create mode 100644 src/doc/unstable-book/src/library-features/thread-id.md create mode 100644 src/doc/unstable-book/src/library-features/thread-local-internals.md create mode 100644 src/doc/unstable-book/src/library-features/thread-local-state.md create mode 100644 src/doc/unstable-book/src/library-features/toowned-clone-into.md create mode 100644 src/doc/unstable-book/src/library-features/trusted-len.md create mode 100644 src/doc/unstable-book/src/library-features/try-from.md create mode 100644 src/doc/unstable-book/src/library-features/unicode.md create mode 100644 src/doc/unstable-book/src/library-features/unique.md create mode 100644 src/doc/unstable-book/src/library-features/unsize.md create mode 100644 src/doc/unstable-book/src/library-features/update-panic-count.md create mode 100644 src/doc/unstable-book/src/library-features/utf8-error-error-len.md create mode 100644 src/doc/unstable-book/src/library-features/vec-remove-item.md create mode 100644 src/doc/unstable-book/src/library-features/windows-c.md create mode 100644 src/doc/unstable-book/src/library-features/windows-handle.md create mode 100644 src/doc/unstable-book/src/library-features/windows-net.md create mode 100644 src/doc/unstable-book/src/library-features/windows-stdio.md delete mode 100644 src/doc/unstable-book/src/non-ascii-idents.md delete mode 100644 src/doc/unstable-book/src/pub-restricted.md delete mode 100644 src/doc/unstable-book/src/static-recursion.md delete mode 100644 src/doc/unstable-book/src/windows-subsystem.md delete mode 100644 src/libcollections/enum_set.rs rename src/{libcollectionstest => libcollections/tests}/binary_heap.rs (88%) rename src/{libcollectionstest => libcollections/tests}/btree/map.rs (100%) rename src/{libcollectionstest => libcollections/tests}/btree/mod.rs (100%) rename src/{libcollectionstest => libcollections/tests}/btree/set.rs (100%) rename src/{libcollectionstest => libcollections/tests}/cow_str.rs (94%) rename src/{libcollectionstest => libcollections/tests}/fmt.rs (100%) rename src/{libcollectionstest => libcollections/tests}/lib.rs (94%) rename src/{libcollectionstest => libcollections/tests}/linked_list.rs (100%) rename src/{libcollectionstest => libcollections/tests}/slice.rs (98%) rename src/{libcollectionstest => libcollections/tests}/str.rs (97%) rename src/{libcollectionstest => libcollections/tests}/string.rs (100%) rename src/{libcollectionstest => libcollections/tests}/vec.rs (94%) rename src/{libcollectionstest => libcollections/tests}/vec_deque.rs (100%) rename src/libcore/{slice.rs => slice/mod.rs} (88%) create mode 100644 src/libcore/slice/sort.rs rename src/{libcoretest => libcore/tests}/any.rs (100%) rename src/{libcoretest => libcore/tests}/array.rs (100%) rename src/{libcoretest => libcore/tests}/atomic.rs (82%) rename src/{libcoretest => libcore/tests}/cell.rs (100%) rename src/{libcoretest => libcore/tests}/char.rs (100%) rename src/{libcoretest => libcore/tests}/clone.rs (100%) rename src/{libcoretest => libcore/tests}/cmp.rs (100%) rename src/{libcoretest => libcore/tests}/fmt/builders.rs (100%) rename src/{libcoretest => libcore/tests}/fmt/float.rs (100%) rename src/{libcoretest => libcore/tests}/fmt/mod.rs (100%) rename src/{libcoretest => libcore/tests}/fmt/num.rs (100%) rename src/{libcoretest => libcore/tests}/hash/mod.rs (100%) rename src/{libcoretest => libcore/tests}/hash/sip.rs (100%) rename src/{libcoretest => libcore/tests}/intrinsics.rs (100%) rename src/{libcoretest => libcore/tests}/iter.rs (100%) rename src/{libcoretest => libcore/tests}/lib.rs (94%) rename src/{libcoretest => libcore/tests}/mem.rs (100%) rename src/{libcoretest => libcore/tests}/nonzero.rs (100%) rename src/{libcoretest => libcore/tests}/num/bignum.rs (100%) rename src/{libcoretest => libcore/tests}/num/dec2flt/mod.rs (100%) rename src/{libcoretest => libcore/tests}/num/dec2flt/parse.rs (100%) rename src/{libcoretest => libcore/tests}/num/dec2flt/rawfp.rs (72%) rename src/{libcoretest => libcore/tests}/num/flt2dec/estimator.rs (100%) rename src/{libcoretest => libcore/tests}/num/flt2dec/mod.rs (100%) rename src/{libcoretest => libcore/tests}/num/flt2dec/strategy/dragon.rs (100%) rename src/{libcoretest => libcore/tests}/num/flt2dec/strategy/grisu.rs (100%) rename src/{libcoretest => libcore/tests}/num/i16.rs (100%) rename src/{libcoretest => libcore/tests}/num/i32.rs (100%) rename src/{libcoretest => libcore/tests}/num/i64.rs (100%) rename src/{libcoretest => libcore/tests}/num/i8.rs (100%) rename src/{libcoretest => libcore/tests}/num/int_macros.rs (100%) rename src/{libcoretest => libcore/tests}/num/mod.rs (100%) rename src/{libcoretest => libcore/tests}/num/u16.rs (100%) rename src/{libcoretest => libcore/tests}/num/u32.rs (100%) rename src/{libcoretest => libcore/tests}/num/u64.rs (100%) rename src/{libcoretest => libcore/tests}/num/u8.rs (100%) rename src/{libcoretest => libcore/tests}/num/uint_macros.rs (100%) rename src/{libcoretest => libcore/tests}/ops.rs (100%) rename src/{libcoretest => libcore/tests}/option.rs (100%) rename src/{libcoretest => libcore/tests}/ptr.rs (100%) rename src/{libcoretest => libcore/tests}/result.rs (100%) rename src/{libcoretest => libcore/tests}/slice.rs (72%) rename src/{libcoretest => libcore/tests}/str.rs (90%) rename src/{libcoretest => libcore/tests}/tuple.rs (100%) rename src/liblibc/ci/{docker/arm-linux-androideabi/accept-licenses.sh => android-accept-licenses.sh} (100%) rename src/liblibc/ci/{docker/arm-linux-androideabi/install-ndk.sh => android-install-ndk.sh} (81%) rename src/liblibc/ci/{docker/arm-linux-androideabi/install-sdk.sh => android-install-sdk.sh} (59%) create mode 100644 src/liblibc/ci/docker/aarch64-linux-android/Dockerfile create mode 100644 src/liblibc/ci/docker/i686-linux-android/Dockerfile create mode 100644 src/liblibc/ci/docker/x86_64-linux-android/Dockerfile create mode 100644 src/liblibc/src/unix/notbsd/android/b32/arm.rs rename src/liblibc/src/unix/notbsd/android/{b32.rs => b32/mod.rs} (75%) create mode 100644 src/liblibc/src/unix/notbsd/android/b32/x86.rs create mode 100644 src/liblibc/src/unix/notbsd/android/b64/aarch64.rs rename src/liblibc/src/unix/notbsd/android/{b64.rs => b64/mod.rs} (64%) create mode 100644 src/liblibc/src/unix/notbsd/android/b64/x86_64.rs delete mode 100644 src/liblog/Cargo.toml delete mode 100644 src/liblog/directive.rs delete mode 100644 src/liblog/lib.rs delete mode 100644 src/liblog/macros.rs rename src/libproc_macro_plugin/{qquote.rs => quote.rs} (86%) create mode 100644 src/librustc/hir/map/hir_id_validator.rs rename src/{librustc_incremental/calculate_svh => librustc/ich}/caching_codemap_view.rs (97%) rename src/{librustc_incremental => librustc}/ich/fingerprint.rs (97%) create mode 100644 src/librustc/ich/hcx.rs create mode 100644 src/librustc/ich/impls_const_math.rs create mode 100644 src/librustc/ich/impls_hir.rs create mode 100644 src/librustc/ich/impls_mir.rs create mode 100644 src/librustc/ich/impls_syntax.rs create mode 100644 src/librustc/ich/impls_ty.rs create mode 100644 src/librustc/ich/mod.rs delete mode 100644 src/librustc/infer/bivariate.rs create mode 100644 src/librustc/traits/trans/mod.rs delete mode 100644 src/librustc/ty/contents.rs create mode 100644 src/librustc/ty/instance.rs create mode 100644 src/librustc_back/target/x86_64_linux_android.rs delete mode 100644 src/librustc_incremental/calculate_svh/def_path_hash.rs delete mode 100644 src/librustc_incremental/calculate_svh/svh_visitor.rs create mode 100644 src/librustc_mir/shim.rs rename src/librustc_mir/{ => util}/def_use.rs (100%) create mode 100644 src/librustc_mir/util/elaborate_drops.rs rename src/librustc_mir/{ => util}/graphviz.rs (100%) rename src/{test/run-pass-fulldeps/logging-enabled-debug.rs => librustc_mir/util/mod.rs} (56%) rename src/{librustc_borrowck/borrowck/mir => librustc_mir/util}/patch.rs (97%) rename src/librustc_mir/{ => util}/pretty.rs (97%) delete mode 100644 src/librustc_passes/rvalues.rs delete mode 100644 src/librustc_trans/cleanup.rs delete mode 100644 src/librustc_trans/disr.rs create mode 100644 src/librustc_trans/symbol_cache.rs delete mode 100644 src/librustc_typeck/check/assoc.rs rename src/librustc_typeck/coherence/{inherent.rs => inherent_impls.rs} (71%) create mode 100644 src/librustc_typeck/coherence/inherent_impls_overlap.rs create mode 100644 src/libsyntax_ext/global_asm.rs rename src/{libsyntax/ext => libsyntax_pos}/hygiene.rs (52%) rename src/{libsyntax => libsyntax_pos}/symbol.rs (77%) create mode 100644 src/test/codegen/foo.s create mode 100644 src/test/codegen/global_asm.rs create mode 100644 src/test/codegen/global_asm_include.rs create mode 100644 src/test/codegen/global_asm_x2.rs create mode 100644 src/test/codegen/move-val-init.rs create mode 100644 src/test/codegen/panic-abort-windows.rs create mode 100644 src/test/codegen/personality_lifetimes.rs create mode 100644 src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue-41211.rs create mode 100644 src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs create mode 100644 src/test/compile-fail/catch-bad-lifetime.rs rename src/test/{run-pass-fulldeps/conditional-debug-macro-off.rs => compile-fail/catch-bad-type.rs} (56%) create mode 100644 src/test/compile-fail/catch-in-match.rs create mode 100644 src/test/compile-fail/catch-in-while.rs create mode 100644 src/test/compile-fail/catch-maybe-bad-lifetime.rs rename src/test/{run-pass-fulldeps/logging-enabled.rs => compile-fail/catch-opt-init.rs} (53%) create mode 100644 src/test/compile-fail/coerce-to-bang-cast.rs create mode 100644 src/test/compile-fail/coerce-to-bang.rs create mode 100644 src/test/compile-fail/const-match-pattern-arm.rs delete mode 100644 src/test/compile-fail/default_ty_param_conflict.rs delete mode 100644 src/test/compile-fail/default_ty_param_conflict_cross_crate.rs rename src/test/{run-make/graphviz-flowgraph/f23.rs => compile-fail/diverging-tuple-parts-39485.rs} (53%) create mode 100644 src/test/compile-fail/duplicate-check-macro-exports.rs create mode 100644 src/test/compile-fail/feature-gate-catch_expr.rs rename src/test/{run-make/graphviz-flowgraph/f00.rs => compile-fail/feature-gate-global_asm.rs} (83%) create mode 100644 src/test/compile-fail/feature-gate-linker-flavor.rs create mode 100644 src/test/compile-fail/feature-gate-macro-vis-matcher.rs create mode 100644 src/test/compile-fail/feature-gate-overlapping_marker_traits.rs create mode 100644 src/test/compile-fail/feature-gate-repr_align.rs create mode 100644 src/test/compile-fail/feature-gate-rvalue_static_promotion.rs create mode 100644 src/test/compile-fail/feature-gate-used.rs create mode 100644 src/test/compile-fail/imports/shadow_builtin_macros.rs delete mode 100644 src/test/compile-fail/issue-22897.rs create mode 100644 src/test/compile-fail/issue-30225.rs create mode 100644 src/test/compile-fail/issue-35675.rs create mode 100644 src/test/compile-fail/issue-41139.rs create mode 100644 src/test/compile-fail/issue-41394.rs create mode 100644 src/test/compile-fail/issue-41726.rs create mode 100644 src/test/compile-fail/issue-41742.rs create mode 100644 src/test/compile-fail/issue-41776.rs rename src/test/{parse-fail => compile-fail}/macro-attribute.rs (94%) rename src/test/compile-fail/{windows-subsystem-gated.rs => match-no-arms-unreachable-after.rs} (75%) rename src/test/compile-fail/{E0101.rs => match-unreachable-warning-with-diverging-discrim.rs} (81%) create mode 100644 src/test/compile-fail/match-unresolved-one-arm.rs delete mode 100644 src/test/compile-fail/never-fallback.rs rename src/test/compile-fail/{non-constant-enum-for-vec-repeat.rs => object-safety-associated-consts.rs} (57%) create mode 100644 src/test/compile-fail/overlap-marker-trait.rs create mode 100644 src/test/compile-fail/regions-adjusted-lvalue-op.rs create mode 100644 src/test/compile-fail/repr-align.rs create mode 100644 src/test/compile-fail/repr-packed-contains-align.rs create mode 100644 src/test/compile-fail/static-lifetime-bound.rs create mode 100644 src/test/compile-fail/suffixed-literal-meta.rs rename src/test/{run-pass/default_ty_param_struct.rs => compile-fail/trait-object-macro-matcher.rs} (62%) create mode 100644 src/test/compile-fail/union/union-borrow-move-parent-sibling.rs create mode 100644 src/test/mir-opt/issue-41110.rs create mode 100644 src/test/parse-fail/bound-single-question-mark.rs create mode 100644 src/test/parse-fail/mod_file_not_exist_windows.rs delete mode 100644 src/test/parse-fail/suffixed-literal-meta.rs create mode 100644 src/test/parse-fail/trait-object-bad-parens.rs rename src/test/{run-pass/default_ty_param_trait_impl_simple.rs => parse-fail/trait-object-lifetime-parens.rs} (53%) create mode 100644 src/test/parse-fail/trait-object-macro-matcher.rs create mode 100644 src/test/parse-fail/trait-object-polytrait-priority.rs create mode 100644 src/test/parse-fail/trait-object-trait-parens.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/Makefile delete mode 100644 src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f04.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f05.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f06.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f11.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f13.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f14.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f15.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f16.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f17.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f18.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f19.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f20.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f21.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f22.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f24.rs delete mode 100644 src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot delete mode 100644 src/test/run-make/graphviz-flowgraph/f25.rs create mode 100644 src/test/run-make/used/Makefile create mode 100644 src/test/run-make/used/used.rs delete mode 100644 src/test/run-pass-fulldeps/auxiliary/logging_right_crate.rs create mode 100644 src/test/run-pass-fulldeps/issue-40663.rs delete mode 100644 src/test/run-pass-fulldeps/logging-right-crate.rs delete mode 100644 src/test/run-pass-fulldeps/logging-separate-lines.rs rename src/test/run-pass-fulldeps/{macro-quote-empty-delims.rs => macro-quote-test.rs} (100%) delete mode 100644 src/test/run-pass-fulldeps/rust-log-filter.rs create mode 100644 src/test/run-pass-fulldeps/switch-stdout.rs create mode 100644 src/test/run-pass/align-struct.rs rename src/test/run-pass/{default_ty_param_dependent_defaults.rs => auxiliary/issue-41394.rs} (61%) rename src/test/{run-make/graphviz-flowgraph/f03.rs => run-pass/auxiliary/issue_41053.rs} (80%) create mode 100644 src/test/run-pass/catch-expr.rs rename src/test/run-pass/{default_ty_param_default_dependent_associated_type.rs => const-pattern-variant.rs} (54%) delete mode 100644 src/test/run-pass/default_ty_param_struct_and_type_alias.rs create mode 100644 src/test/run-pass/diverging-fallback-control-flow.rs create mode 100644 src/test/run-pass/diverging-fallback-method-chain.rs create mode 100644 src/test/run-pass/diverging-fallback-option.rs create mode 100644 src/test/run-pass/empty_global_asm.rs rename src/test/{run-make/graphviz-flowgraph/f07.rs => run-pass/issue-23898.rs} (73%) rename src/test/{run-make/graphviz-flowgraph/f10.rs => run-pass/issue-34571.rs} (72%) create mode 100644 src/test/run-pass/issue-39808.rs create mode 100644 src/test/run-pass/issue-40408.rs create mode 100644 src/test/run-pass/issue-40951.rs rename src/test/{run-make/graphviz-flowgraph/f08.rs => run-pass/issue-40962.rs} (71%) create mode 100644 src/test/run-pass/issue-41053.rs rename src/test/{run-make/graphviz-flowgraph/f12.rs => run-pass/issue-41213.rs} (56%) rename src/test/{run-make/graphviz-flowgraph/f09.rs => run-pass/issue-41272.rs} (57%) create mode 100644 src/test/run-pass/issue-41298.rs create mode 100644 src/test/run-pass/issue-41394.rs create mode 100644 src/test/run-pass/issue-41479.rs create mode 100644 src/test/run-pass/issue-41498.rs create mode 100644 src/test/run-pass/issue-41604.rs create mode 100644 src/test/run-pass/issue-41677.rs create mode 100644 src/test/run-pass/issue-41803.rs create mode 100644 src/test/run-pass/issue-41849-variance-req.rs create mode 100644 src/test/run-pass/issue-41936-variance-coerce-unsized-cycle.rs create mode 100644 src/test/run-pass/macro-nested_definition_issue-31946.rs create mode 100644 src/test/run-pass/macro-pub-matcher.rs create mode 100644 src/test/run-pass/mir_calls_to_shims.rs create mode 100644 src/test/run-pass/optimization-fuel-0.rs create mode 100644 src/test/run-pass/optimization-fuel-1.rs rename src/test/run-pass/{default_ty_param_trait_impl.rs => overlap-doesnt-conflict-with-specialization.rs} (55%) create mode 100644 src/test/run-pass/overlap-permitted-for-marker-traits-neg.rs create mode 100644 src/test/run-pass/overlap-permitted-for-marker-traits.rs create mode 100644 src/test/run-pass/rvalue-static-promotion.rs create mode 100644 src/test/run-pass/simple_global_asm.rs create mode 100644 src/test/run-pass/type-infer-generalize-ty-var.rs delete mode 100644 src/test/run-pass/unit-fallback.rs create mode 100644 src/test/rustdoc/assoc-item-cast.rs create mode 100644 src/test/rustdoc/auxiliary/issue-40936.rs create mode 100644 src/test/rustdoc/auxiliary/pub-use-extern-macros.rs create mode 100644 src/test/rustdoc/const-doc.rs rename src/test/{run-pass/default_ty_param_method_call_test.rs => rustdoc/const.rs} (71%) create mode 100644 src/test/rustdoc/doc-assoc-item.rs create mode 100644 src/test/rustdoc/issue-40936.rs create mode 100644 src/test/rustdoc/pub-use-extern-macros.rs create mode 100644 src/test/rustdoc/test-lists.rs rename src/test/{compile-fail => ui/codemap_tests}/coherence-overlapping-inherent-impl-trait.rs (78%) create mode 100644 src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr rename src/test/{compile-fail/inherent-overlap.rs => ui/codemap_tests/overlapping_inherent_impls.rs} (76%) create mode 100644 src/test/ui/codemap_tests/overlapping_inherent_impls.stderr create mode 100644 src/test/ui/did_you_mean/issue-35937.rs create mode 100644 src/test/ui/did_you_mean/issue-35937.stderr create mode 100644 src/test/ui/did_you_mean/issue-40006.rs create mode 100644 src/test/ui/did_you_mean/issue-40006.stderr create mode 100644 src/test/ui/did_you_mean/issue-40396.rs create mode 100644 src/test/ui/did_you_mean/issue-40396.stderr rename src/test/{run-make/graphviz-flowgraph/f02.rs => ui/did_you_mean/issue-40823.rs} (75%) create mode 100644 src/test/ui/did_you_mean/issue-40823.stderr rename src/test/{compile-fail => ui}/impl-trait/equality.rs (95%) create mode 100644 src/test/ui/impl-trait/equality.stderr create mode 100644 src/test/ui/loop-break-value-no-repeat.rs create mode 100644 src/test/ui/loop-break-value-no-repeat.stderr create mode 100644 src/test/ui/mismatched_types/abridged.rs create mode 100644 src/test/ui/mismatched_types/abridged.stderr create mode 100644 src/test/ui/mismatched_types/binops.rs create mode 100644 src/test/ui/mismatched_types/binops.stderr create mode 100644 src/test/ui/print-fuel/print-fuel.rs create mode 100644 src/test/ui/print-fuel/print-fuel.stdout create mode 100644 src/test/ui/print_type_sizes/repr-align.rs create mode 100644 src/test/ui/print_type_sizes/repr-align.stdout create mode 100644 src/test/ui/pub/pub-restricted-error-fn.rs create mode 100644 src/test/ui/pub/pub-restricted-error-fn.stderr create mode 100644 src/test/ui/pub/pub-restricted-error.rs create mode 100644 src/test/ui/pub/pub-restricted-error.stderr rename src/{librustc_incremental/ich/mod.rs => test/ui/pub/pub-restricted-non-path.rs} (76%) create mode 100644 src/test/ui/pub/pub-restricted-non-path.stderr create mode 100644 src/test/ui/pub/pub-restricted.rs create mode 100644 src/test/ui/pub/pub-restricted.stderr create mode 100644 src/test/ui/reachable/README.md create mode 100644 src/test/ui/reachable/expr_add.rs create mode 100644 src/test/ui/reachable/expr_add.stderr create mode 100644 src/test/ui/reachable/expr_again.rs create mode 100644 src/test/ui/reachable/expr_again.stderr create mode 100644 src/test/ui/reachable/expr_andand.rs create mode 100644 src/test/ui/reachable/expr_andand.stderr create mode 100644 src/test/ui/reachable/expr_array.rs create mode 100644 src/test/ui/reachable/expr_array.stderr create mode 100644 src/test/ui/reachable/expr_assign.rs create mode 100644 src/test/ui/reachable/expr_assign.stderr create mode 100644 src/test/ui/reachable/expr_block.rs create mode 100644 src/test/ui/reachable/expr_block.stderr rename src/test/{compile-fail/E0102.rs => ui/reachable/expr_box.rs} (79%) create mode 100644 src/test/ui/reachable/expr_box.stderr rename src/test/{compile-fail/privacy/restricted/feature-gate.rs => ui/reachable/expr_call.rs} (60%) create mode 100644 src/test/ui/reachable/expr_call.stderr create mode 100644 src/test/ui/reachable/expr_cast.rs create mode 100644 src/test/ui/reachable/expr_cast.stderr create mode 100644 src/test/ui/reachable/expr_if.rs create mode 100644 src/test/ui/reachable/expr_if.stderr create mode 100644 src/test/ui/reachable/expr_loop.rs create mode 100644 src/test/ui/reachable/expr_loop.stderr create mode 100644 src/test/ui/reachable/expr_match.rs create mode 100644 src/test/ui/reachable/expr_match.stderr create mode 100644 src/test/ui/reachable/expr_method.rs create mode 100644 src/test/ui/reachable/expr_method.stderr create mode 100644 src/test/ui/reachable/expr_oror.rs create mode 100644 src/test/ui/reachable/expr_oror.stderr create mode 100644 src/test/ui/reachable/expr_repeat.rs create mode 100644 src/test/ui/reachable/expr_repeat.stderr create mode 100644 src/test/ui/reachable/expr_return.rs create mode 100644 src/test/ui/reachable/expr_return.stderr create mode 100644 src/test/ui/reachable/expr_struct.rs create mode 100644 src/test/ui/reachable/expr_struct.stderr create mode 100644 src/test/ui/reachable/expr_tup.rs create mode 100644 src/test/ui/reachable/expr_tup.stderr create mode 100644 src/test/ui/reachable/expr_type.rs create mode 100644 src/test/ui/reachable/expr_type.stderr create mode 100644 src/test/ui/reachable/expr_unary.rs create mode 100644 src/test/ui/reachable/expr_unary.stderr create mode 100644 src/test/ui/reachable/expr_while.rs create mode 100644 src/test/ui/reachable/expr_while.stderr rename src/test/{compile-fail => ui/span}/E0072.rs (84%) create mode 100644 src/test/ui/span/E0072.stderr rename src/test/{run-pass/default_ty_param_type_alias.rs => ui/span/issue-29595.rs} (66%) create mode 100644 src/test/ui/span/issue-29595.stderr create mode 100644 src/test/ui/span/issue-33884.rs create mode 100644 src/test/ui/span/issue-33884.stderr create mode 100644 src/test/ui/span/issue-34264.rs create mode 100644 src/test/ui/span/issue-34264.stderr create mode 100644 src/test/ui/span/multiline-span-E0072.rs create mode 100644 src/test/ui/span/multiline-span-E0072.stderr rename src/test/{compile-fail => ui/suggestions/confuse-field-and-method}/issue-18343.rs (79%) create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-18343.stderr rename src/test/{compile-fail => ui/suggestions/confuse-field-and-method}/issue-2392.rs (64%) create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-2392.stderr rename src/test/{compile-fail => ui/suggestions/confuse-field-and-method}/issue-32128.rs (82%) create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-32128.stderr rename src/test/{compile-fail => ui/suggestions/confuse-field-and-method}/issue-33784.rs (74%) create mode 100644 src/test/ui/suggestions/confuse-field-and-method/issue-33784.stderr create mode 100644 src/test/ui/suggestions/confuse-field-and-method/private-field.rs create mode 100644 src/test/ui/suggestions/confuse-field-and-method/private-field.stderr rename src/test/{parse-fail => ui/suggestions}/tuple-float-index.rs (75%) create mode 100644 src/test/ui/suggestions/tuple-float-index.stderr rename src/test/{parse-fail => ui/token}/bounds-obj-parens.rs (92%) create mode 100644 src/test/ui/token/bounds-obj-parens.stderr rename src/test/{compile-fail => ui/token}/issue-10636-2.rs (89%) create mode 100644 src/test/ui/token/issue-10636-2.stderr rename src/test/{run-make/graphviz-flowgraph/f01.rs => ui/token/issue-41155.rs} (82%) create mode 100644 src/test/ui/token/issue-41155.stderr rename src/test/{compile-fail => ui/token}/macro-incomplete-parse.rs (89%) create mode 100644 src/test/ui/token/macro-incomplete-parse.stderr rename src/test/{parse-fail => ui/token}/trailing-plus-in-bounds.rs (75%) create mode 100644 src/test/ui/token/trailing-plus-in-bounds.stderr rename src/test/ui/type-check/{issue-38812-2.rs => cannot_infer_local_or_array.rs} (94%) create mode 100644 src/test/ui/type-check/cannot_infer_local_or_array.stderr rename src/test/ui/type-check/{issue-38812.rs => cannot_infer_local_or_vec.rs} (100%) rename src/test/ui/type-check/{issue-38812.stderr => cannot_infer_local_or_vec.stderr} (86%) create mode 100644 src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.rs create mode 100644 src/test/ui/type-check/cannot_infer_local_or_vec_in_tuples.stderr create mode 100644 src/test/ui/type-check/issue-22897.rs create mode 100644 src/test/ui/type-check/issue-22897.stderr delete mode 100644 src/test/ui/type-check/issue-38812-2.stderr create mode 100644 src/test/ui/type-check/unknown_type_for_closure.rs create mode 100644 src/test/ui/type-check/unknown_type_for_closure.stderr create mode 100644 src/tools/tidy/src/unstable_book.rs create mode 100644 src/vendor/atty/.cargo-checksum.json create mode 100644 src/vendor/atty/.cargo-ok create mode 100644 src/vendor/atty/.gitignore create mode 100644 src/vendor/atty/.travis.yml create mode 100644 src/vendor/atty/CHANGELOG.md create mode 100644 src/vendor/atty/Cargo.toml create mode 100644 src/vendor/atty/LICENSE create mode 100644 src/vendor/atty/README.md create mode 100644 src/vendor/atty/appveyor.yml create mode 100644 src/vendor/atty/examples/atty.rs create mode 100644 src/vendor/atty/src/lib.rs create mode 100644 src/vendor/bitflags/tests/i128_bitflags.rs create mode 100644 src/vendor/clap/src/app/usage.rs create mode 100644 src/vendor/clap/src/app/validator.rs delete mode 100644 src/vendor/env_logger-0.3.5/.cargo-checksum.json delete mode 100644 src/vendor/env_logger-0.3.5/Cargo.toml delete mode 100644 src/vendor/env_logger-0.3.5/src/lib.rs delete mode 100644 src/vendor/env_logger-0.3.5/src/regex.rs delete mode 100644 src/vendor/env_logger-0.3.5/src/string.rs delete mode 100644 src/vendor/env_logger-0.3.5/tests/regexp_filter.rs create mode 100644 src/vendor/pulldown-cmark-0.0.8/.cargo-checksum.json create mode 100644 src/vendor/pulldown-cmark-0.0.8/.cargo-ok create mode 100644 src/vendor/pulldown-cmark-0.0.8/.gitignore create mode 100644 src/vendor/pulldown-cmark-0.0.8/CONTRIBUTING.md create mode 100644 src/vendor/pulldown-cmark-0.0.8/Cargo.toml create mode 100644 src/vendor/pulldown-cmark-0.0.8/LICENSE create mode 100644 src/vendor/pulldown-cmark-0.0.8/README.md create mode 100644 src/vendor/pulldown-cmark-0.0.8/specs/footnotes.txt create mode 100644 src/vendor/pulldown-cmark-0.0.8/specs/table.txt create mode 100644 src/vendor/pulldown-cmark-0.0.8/src/entities.rs create mode 100644 src/vendor/pulldown-cmark-0.0.8/src/escape.rs create mode 100644 src/vendor/pulldown-cmark-0.0.8/src/html.rs create mode 100644 src/vendor/pulldown-cmark-0.0.8/src/lib.rs create mode 100644 src/vendor/pulldown-cmark-0.0.8/src/main.rs create mode 100644 src/vendor/pulldown-cmark-0.0.8/src/parse.rs create mode 100644 src/vendor/pulldown-cmark-0.0.8/src/passes.rs create mode 100644 src/vendor/pulldown-cmark-0.0.8/src/puncttable.rs create mode 100644 src/vendor/pulldown-cmark-0.0.8/src/scanners.rs create mode 100644 src/vendor/pulldown-cmark-0.0.8/src/utils.rs create mode 100644 src/vendor/pulldown-cmark-0.0.8/tools/mk_entities.py create mode 100644 src/vendor/pulldown-cmark-0.0.8/tools/mk_puncttable.py create mode 100644 src/vendor/pulldown-cmark/build.rs create mode 100644 src/vendor/pulldown-cmark/tests/footnotes.rs create mode 100644 src/vendor/pulldown-cmark/tests/html.rs create mode 100644 src/vendor/pulldown-cmark/tests/spec.rs create mode 100644 src/vendor/pulldown-cmark/tests/table.rs create mode 100644 src/vendor/pulldown-cmark/third_party/CommonMark/LICENSE create mode 100644 src/vendor/pulldown-cmark/third_party/CommonMark/README.google create mode 100644 src/vendor/pulldown-cmark/third_party/CommonMark/spec.txt create mode 100644 src/vendor/rls-data/.cargo-checksum.json create mode 100644 src/vendor/rls-data/.cargo-ok create mode 100644 src/vendor/rls-data/.gitignore create mode 100644 src/vendor/rls-data/Cargo.toml create mode 100644 src/vendor/rls-data/README.md create mode 100644 src/vendor/rls-data/src/lib.rs create mode 100644 src/vendor/rls-span/.cargo-checksum.json create mode 100644 src/vendor/rls-span/.cargo-ok create mode 100644 src/vendor/rls-span/.gitignore create mode 100644 src/vendor/rls-span/Cargo.toml create mode 100644 src/vendor/rls-span/src/compiler.rs create mode 100644 src/vendor/rls-span/src/lib.rs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f921fb2c94..0314a5dfd8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -311,9 +311,13 @@ To save @bors some work, and to get small changes through more quickly, when the other rollup-eligible patches too, and they'll get tested and merged at the same time. -To find documentation-related issues, sort by the [A-docs label][adocs]. +To find documentation-related issues, sort by the [T-doc label][tdoc]. -[adocs]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AA-docs +[tdoc]: https://github.com/rust-lang/rust/issues?q=is%3Aopen%20is%3Aissue%20label%3AT-doc + +You can find documentation style guidelines in [RFC 1574][rfc1574]. + +[rfc1574]: https://github.com/rust-lang/rfcs/blob/master/text/1574-more-api-documentation-conventions.md#appendix-a-full-conventions-text In many cases, you don't need a full `./x.py doc`. You can use `rustdoc` directly to check small fixes. For example, `rustdoc src/doc/reference.md` will render diff --git a/README.md b/README.md index 79f11144a0..f387b4be60 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Read ["Installing Rust"] from [The Book]. 1. Make sure you have installed the dependencies: - * `g++` 4.7 or later or `clang++` 3.x + * `g++` 4.7 or later or `clang++` 3.x or later * `python` 2.7 (but not 3.x) * GNU `make` 3.81 or later * `cmake` 3.4.3 or later @@ -161,8 +161,9 @@ If you’d like to build the documentation, it’s almost the same: $ ./x.py doc ``` -The generated documentation will appear in a top-level `doc` directory, -created by the `make` rule. +The generated documentation will appear under `doc` in the `build` directory for +the ABI used. I.e., if the ABI was `x86_64-pc-windows-msvc`, the directory will be +`build\x86_64-pc-windows-msvc\doc`. ## Notes @@ -197,8 +198,8 @@ The Rust community congregates in a few places: * [users.rust-lang.org] - General discussion and broader questions. * [/r/rust] - News and general discussion. -[Stack Overflow]: http://stackoverflow.com/questions/tagged/rust -[/r/rust]: http://reddit.com/r/rust +[Stack Overflow]: https://stackoverflow.com/questions/tagged/rust +[/r/rust]: https://reddit.com/r/rust [users.rust-lang.org]: https://users.rust-lang.org/ ## Contributing diff --git a/RELEASES.md b/RELEASES.md index 606936778c..6d550bc780 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,10 +1,417 @@ +Version 1.18.0 (2017-06-08) +=========================== + +Language +-------- + +- [Stabilize pub(restricted)][40556] `pub` can now accept a module path to + make the item visible to just that module tree. Also accepts the keyword + `crate` to make something public to the whole crate but not users of the + library. Example: `pub(crate) mod utils;`. [RFC 1422]. +- [Stabilize `#![windows_subsystem]` attribute][40870] conservative exposure of the + `/SUBSYSTEM` linker flag on Windows platforms. [RFC 1665]. +- [Refactor of trait object type parsing][40043] Now `ty` in macros can accept + types like `Write + Send`, trailing `+` are now supported in trait objects, + and better error reporting for trait objects starting with `?Sized`. +- [0e+10 is now a valid floating point literal][40589] +- [Now warns if you bind a lifetime parameter to 'static][40734] +- [Tuples, Enum variant fields, and structs with no `repr` attribute or with + `#[repr(Rust)]` are reordered to minimize padding and produce a smaller + representation in some cases.][40377] + +Compiler +-------- + +- [rustc can now emit mir with `--emit mir`][39891] +- [Improved LLVM IR for trivial functions][40367] +- [Added explanation for E0090(Wrong number of lifetimes are supplied)][40723] +- [rustc compilation is now 15%-20% faster][41469] Thanks to optimisation + opportunities found through profiling +- [Improved backtrace formatting when panicking][38165] + +Libraries +--------- + +- [Specialized `Vec::from_iter` being passed `vec::IntoIter`][40731] if the + iterator hasn't been advanced the original `Vec` is reassembled with no actual + iteration or reallocation. +- [Simplified HashMap Bucket interface][40561] provides performance + improvements for iterating and cloning. +- [Specialize Vec::from_elem to use calloc][40409] +- [Fixed Race condition in fs::create_dir_all][39799] +- [No longer caching stdio on Windows][40516] +- [Optimized insertion sort in slice][40807] insertion sort in some cases + 2.50%~ faster and in one case now 12.50% faster. +- [Optimized `AtomicBool::fetch_nand`][41143] + +Stabilized APIs +--------------- + +- [`Child::try_wait`] +- [`HashMap::retain`] +- [`HashSet::retain`] +- [`PeekMut::pop`] +- [`TcpStream::peek`] +- [`UdpSocket::peek`] +- [`UdpSocket::peek_from`] + +Cargo +----- + +- [Added partial Pijul support][cargo/3842] Pijul is a version control system in Rust. + You can now create new cargo projects with Pijul using `cargo new --vcs pijul` +- [Now always emits build script warnings for crates that fail to build][cargo/3847] +- [Added Android build support][cargo/3885] +- [Added `--bins` and `--tests` flags][cargo/3901] now you can build all programs + of a certain type, for example `cargo build --bins` will build all + binaries. +- [Added support for haiku][cargo/3952] + +Misc +---- + +- [rustdoc can now use pulldown-cmark with the `--enable-commonmark` flag][40338] +- [Added rust-winbg script for better debugging on Windows][39983] +- [Rust now uses the official cross compiler for NetBSD][40612] +- [rustdoc now accepts `#` at the start of files][40828] +- [Fixed jemalloc support for musl][41168] + +Compatibility Notes +------------------- + +- [Changes to how the `0` flag works in format!][40241] Padding zeroes are now + always placed after the sign if it exists and before the digits. With the `#` + flag the zeroes are placed after the prefix and before the digits. +- [Due to the struct field optimisation][40377], using `transmute` on structs + that have no `repr` attribute or `#[repr(Rust)]` will no longer work. This has + always been undefined behavior, but is now more likely to break in practice. +- [The refactor of trait object type parsing][40043] fixed a bug where `+` was + receiving the wrong priority parsing things like `&for<'a> Tr<'a> + Send` as + `&(for<'a> Tr<'a> + Send)` instead of `(&for<'a> Tr<'a>) + Send` +- [Overlapping inherent `impl`s are now a hard error][40728] +- [`PartialOrd` and `Ord` must agree on the ordering.][41270] +- [`rustc main.rs -o out --emit=asm,llvm-ir`][41085] Now will output + `out.asm` and `out.ll` instead of only one of the filetypes. +- [ calling a function that returns `Self` will no longer work][41805] when + the size of `Self` cannot be statically determined. +- [rustc now builds with a "pthreads" flavour of MinGW for Windows GNU][40805] + this has caused a few regressions namely: + + - Changed the link order of local static/dynamic libraries (respecting the + order on given rather than having the compiler reorder). + - Changed how MinGW is linked, native code linked to dynamic libraries + may require manually linking to the gcc support library (for the native + code itself) + +[38165]: https://github.com/rust-lang/rust/pull/38165 +[39799]: https://github.com/rust-lang/rust/pull/39799 +[39891]: https://github.com/rust-lang/rust/pull/39891 +[39983]: https://github.com/rust-lang/rust/pull/39983 +[40043]: https://github.com/rust-lang/rust/pull/40043 +[40241]: https://github.com/rust-lang/rust/pull/40241 +[40338]: https://github.com/rust-lang/rust/pull/40338 +[40367]: https://github.com/rust-lang/rust/pull/40367 +[40377]: https://github.com/rust-lang/rust/pull/40377 +[40409]: https://github.com/rust-lang/rust/pull/40409 +[40516]: https://github.com/rust-lang/rust/pull/40516 +[40556]: https://github.com/rust-lang/rust/pull/40556 +[40561]: https://github.com/rust-lang/rust/pull/40561 +[40589]: https://github.com/rust-lang/rust/pull/40589 +[40612]: https://github.com/rust-lang/rust/pull/40612 +[40723]: https://github.com/rust-lang/rust/pull/40723 +[40728]: https://github.com/rust-lang/rust/pull/40728 +[40731]: https://github.com/rust-lang/rust/pull/40731 +[40734]: https://github.com/rust-lang/rust/pull/40734 +[40805]: https://github.com/rust-lang/rust/pull/40805 +[40807]: https://github.com/rust-lang/rust/pull/40807 +[40828]: https://github.com/rust-lang/rust/pull/40828 +[40870]: https://github.com/rust-lang/rust/pull/40870 +[41085]: https://github.com/rust-lang/rust/pull/41085 +[41143]: https://github.com/rust-lang/rust/pull/41143 +[41168]: https://github.com/rust-lang/rust/pull/41168 +[41270]: https://github.com/rust-lang/rust/issues/41270 +[41469]: https://github.com/rust-lang/rust/pull/41469 +[41805]: https://github.com/rust-lang/rust/issues/41805 +[RFC 1422]: https://github.com/rust-lang/rfcs/blob/master/text/1422-pub-restricted.md +[RFC 1665]: https://github.com/rust-lang/rfcs/blob/master/text/1665-windows-subsystem.md +[`Child::try_wait`]: https://doc.rust-lang.org/std/process/struct.Child.html#method.try_wait +[`HashMap::retain`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.retain +[`HashSet::retain`]: https://doc.rust-lang.org/std/collections/struct.HashSet.html#method.retain +[`PeekMut::pop`]: https://doc.rust-lang.org/std/collections/binary_heap/struct.PeekMut.html#method.pop +[`TcpStream::peek`]: https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.peek +[`UdpSocket::peek_from`]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html#method.peek_from +[`UdpSocket::peek`]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html#method.peek +[cargo/3842]: https://github.com/rust-lang/cargo/pull/3842 +[cargo/3847]: https://github.com/rust-lang/cargo/pull/3847 +[cargo/3885]: https://github.com/rust-lang/cargo/pull/3885 +[cargo/3901]: https://github.com/rust-lang/cargo/pull/3901 +[cargo/3952]: https://github.com/rust-lang/cargo/pull/3952 + + +Version 1.17.0 (2017-04-27) +=========================== + +Language +-------- + +* [The lifetime of statics and consts defaults to `'static`][39265]. [RFC 1623] +* [Fields of structs may be initialized without duplicating the field/variable + names][39761]. [RFC 1682] +* [`Self` may be included in the `where` clause of `impls`][38864]. [RFC 1647] +* [When coercing to an unsized type lifetimes must be equal][40319]. That is, + there is no subtyping between `T` and `U` when `T: Unsize`. For example, + coercing `&mut [&'a X; N]` to `&mut [&'b X]` requires `'a` be equal to + `'b`. Soundness fix. +* [Values passed to the indexing operator, `[]`, automatically coerce][40166] +* [Static variables may contain references to other statics][40027] + +Compiler +-------- + +* [Exit quickly on only `--emit dep-info`][40336] +* [Make `-C relocation-model` more correctly determine whether the linker + creates a position-independent executable][40245] +* [Add `-C overflow-checks` to directly control whether integer overflow + panics][40037] +* [The rustc type checker now checks items on demand instead of in a single + in-order pass][40008]. This is mostly an internal refactoring in support of + future work, including incremental type checking, but also resolves [RFC + 1647], allowing `Self` to appear in `impl` `where` clauses. +* [Optimize vtable loads][39995] +* [Turn off vectorization for Emscripten targets][39990] +* [Provide suggestions for unknown macros imported with `use`][39953] +* [Fix ICEs in path resolution][39939] +* [Strip exception handling code on Emscripten when `panic=abort`][39193] +* [Add clearer error message using `&str + &str`][39116] + +Stabilized APIs +--------------- + +* [`Arc::into_raw`] +* [`Arc::from_raw`] +* [`Arc::ptr_eq`] +* [`Rc::into_raw`] +* [`Rc::from_raw`] +* [`Rc::ptr_eq`] +* [`Ordering::then`] +* [`Ordering::then_with`] +* [`BTreeMap::range`] +* [`BTreeMap::range_mut`] +* [`collections::Bound`] +* [`process::abort`] +* [`ptr::read_unaligned`] +* [`ptr::write_unaligned`] +* [`Result::expect_err`] +* [`Cell::swap`] +* [`Cell::replace`] +* [`Cell::into_inner`] +* [`Cell::take`] + +Libraries +--------- + +* [`BTreeMap` and `BTreeSet` can iterate over ranges][27787] +* [`Cell` can store non-`Copy` types][39793]. [RFC 1651] +* [`String` implements `FromIterator<&char>`][40028] +* `Box` [implements][40009] a number of new conversions: + `From> for String`, + `From> for Vec`, + `From> for CString`, + `From> for OsString`, + `From> for PathBuf`, + `Into> for String`, + `Into> for Vec`, + `Into> for CString`, + `Into> for OsString`, + `Into> for PathBuf`, + `Default for Box`, + `Default for Box`, + `Default for Box`, + `From<&CStr> for Box`, + `From<&OsStr> for Box`, + `From<&Path> for Box` +* [`ffi::FromBytesWithNulError` implements `Error` and `Display`][39960] +* [Specialize `PartialOrd for [A] where A: Ord`][39642] +* [Slightly optimize `slice::sort`][39538] +* [Add `ToString` trait specialization for `Cow<'a, str>` and `String`][39440] +* [`Box<[T]>` implements `From<&[T]> where T: Copy`, + `Box` implements `From<&str>`][39438] +* [`IpAddr` implements `From` for various arrays. `SocketAddr` implements + `From<(I, u16)> where I: Into`][39372] +* [`format!` estimates the needed capacity before writing a string][39356] +* [Support unprivileged symlink creation in Windows][38921] +* [`PathBuf` implements `Default`][38764] +* [Implement `PartialEq<[A]>` for `VecDeque`][38661] +* [`HashMap` resizes adaptively][38368] to guard against DOS attacks + and poor hash functions. + +Cargo +----- + +* [Add `cargo check --all`][cargo/3731] +* [Add an option to ignore SSL revocation checking][cargo/3699] +* [Add `cargo run --package`][cargo/3691] +* [Add `required_features`][cargo/3667] +* [Assume `build.rs` is a build script][cargo/3664] +* [Find workspace via `workspace_root` link in containing member][cargo/3562] + +Misc +---- + +* [Documentation is rendered with mdbook instead of the obsolete, in-tree + `rustbook`][39633] +* [The "Unstable Book" documents nightly-only features][ubook] +* [Improve the style of the sidebar in rustdoc output][40265] +* [Configure build correctly on 64-bit CPU's with the armhf ABI][40261] +* [Fix MSP430 breakage due to `i128`][40257] +* [Preliminary Solaris/SPARCv9 support][39903] +* [`rustc` is linked statically on Windows MSVC targets][39837], allowing it to + run without installing the MSVC runtime. +* [`rustdoc --test` includes file names in test names][39788] +* This release includes builds of `std` for `sparc64-unknown-linux-gnu`, + `aarch64-unknown-linux-fuchsia`, and `x86_64-unknown-linux-fuchsia`. +* [Initial support for `aarch64-unknown-freebsd`][39491] +* [Initial support for `i686-unknown-netbsd`][39426] +* [This release no longer includes the old makefile build system][39431]. Rust + is built with a custom build system, written in Rust, and with Cargo. +* [Add Debug implementations for libcollection structs][39002] +* [`TypeId` implements `PartialOrd` and `Ord`][38981] +* [`--test-threads=0` produces an error][38945] +* [`rustup` installs documentation by default][40526] +* [The Rust source includes NatVis visualizations][39843]. These can be used by + WinDbg and Visual Studio to improve the debugging experience. + +Compatibility Notes +------------------- + +* [Rust 1.17 does not correctly detect the MSVC 2017 linker][38584]. As a + workaround, either use MSVC 2015 or run vcvars.bat. +* [When coercing to an unsized type lifetimes must be equal][40319]. That is, + disallow subtyping between `T` and `U` when `T: Unsize`, e.g. coercing + `&mut [&'a X; N]` to `&mut [&'b X]` requires `'a` be equal to `'b`. Soundness + fix. +* [`format!` and `Display::to_string` panic if an underlying formatting + implementation returns an error][40117]. Previously the error was silently + ignored. It is incorrect for `write_fmt` to return an error when writing + to a string. +* [In-tree crates are verified to be unstable][39851]. Previously, some minor + crates were marked stable and could be accessed from the stable toolchain. +* [Rust git source no longer includes vendored crates][39728]. Those that need + to build with vendored crates should build from release tarballs. +* [Fix inert attributes from `proc_macro_derives`][39572] +* [During crate resolution, rustc prefers a crate in the sysroot if two crates + are otherwise identical][39518]. Unlikely to be encountered outside the Rust + build system. +* [Fixed bugs around how type inference interacts with dead-code][39485]. The + existing code generally ignores the type of dead-code unless a type-hint is + provided; this can cause surprising inference interactions particularly around + defaulting. The new code uniformly ignores the result type of dead-code. +* [Tuple-struct constructors with private fields are no longer visible][38932] +* [Lifetime parameters that do not appear in the arguments are now considered + early-bound][38897], resolving a soundness bug (#[32330]). The + `hr_lifetime_in_assoc_type` future-compatibility lint has been in effect since + April of 2016. +* [rustdoc: fix doctests with non-feature crate attributes][38161] +* [Make transmuting from fn item types to pointer-sized types a hard + error][34198] + +[27787]: https://github.com/rust-lang/rust/issues/27787 +[32330]: https://github.com/rust-lang/rust/issues/32330 +[34198]: https://github.com/rust-lang/rust/pull/34198 +[38161]: https://github.com/rust-lang/rust/pull/38161 +[38368]: https://github.com/rust-lang/rust/pull/38368 +[38584]: https://github.com/rust-lang/rust/issues/38584 +[38661]: https://github.com/rust-lang/rust/pull/38661 +[38764]: https://github.com/rust-lang/rust/pull/38764 +[38864]: https://github.com/rust-lang/rust/issues/38864 +[38897]: https://github.com/rust-lang/rust/pull/38897 +[38921]: https://github.com/rust-lang/rust/pull/38921 +[38932]: https://github.com/rust-lang/rust/pull/38932 +[38945]: https://github.com/rust-lang/rust/pull/38945 +[38981]: https://github.com/rust-lang/rust/pull/38981 +[39002]: https://github.com/rust-lang/rust/pull/39002 +[39116]: https://github.com/rust-lang/rust/pull/39116 +[39193]: https://github.com/rust-lang/rust/pull/39193 +[39265]: https://github.com/rust-lang/rust/pull/39265 +[39356]: https://github.com/rust-lang/rust/pull/39356 +[39372]: https://github.com/rust-lang/rust/pull/39372 +[39426]: https://github.com/rust-lang/rust/pull/39426 +[39431]: https://github.com/rust-lang/rust/pull/39431 +[39438]: https://github.com/rust-lang/rust/pull/39438 +[39440]: https://github.com/rust-lang/rust/pull/39440 +[39485]: https://github.com/rust-lang/rust/pull/39485 +[39491]: https://github.com/rust-lang/rust/pull/39491 +[39518]: https://github.com/rust-lang/rust/pull/39518 +[39538]: https://github.com/rust-lang/rust/pull/39538 +[39572]: https://github.com/rust-lang/rust/pull/39572 +[39633]: https://github.com/rust-lang/rust/pull/39633 +[39642]: https://github.com/rust-lang/rust/pull/39642 +[39728]: https://github.com/rust-lang/rust/pull/39728 +[39761]: https://github.com/rust-lang/rust/pull/39761 +[39788]: https://github.com/rust-lang/rust/pull/39788 +[39793]: https://github.com/rust-lang/rust/pull/39793 +[39837]: https://github.com/rust-lang/rust/pull/39837 +[39843]: https://github.com/rust-lang/rust/pull/39843 +[39851]: https://github.com/rust-lang/rust/pull/39851 +[39903]: https://github.com/rust-lang/rust/pull/39903 +[39939]: https://github.com/rust-lang/rust/pull/39939 +[39953]: https://github.com/rust-lang/rust/pull/39953 +[39960]: https://github.com/rust-lang/rust/pull/39960 +[39990]: https://github.com/rust-lang/rust/pull/39990 +[39995]: https://github.com/rust-lang/rust/pull/39995 +[40008]: https://github.com/rust-lang/rust/pull/40008 +[40009]: https://github.com/rust-lang/rust/pull/40009 +[40027]: https://github.com/rust-lang/rust/pull/40027 +[40028]: https://github.com/rust-lang/rust/pull/40028 +[40037]: https://github.com/rust-lang/rust/pull/40037 +[40117]: https://github.com/rust-lang/rust/pull/40117 +[40166]: https://github.com/rust-lang/rust/pull/40166 +[40245]: https://github.com/rust-lang/rust/pull/40245 +[40257]: https://github.com/rust-lang/rust/pull/40257 +[40261]: https://github.com/rust-lang/rust/pull/40261 +[40265]: https://github.com/rust-lang/rust/pull/40265 +[40319]: https://github.com/rust-lang/rust/pull/40319 +[40336]: https://github.com/rust-lang/rust/pull/40336 +[40526]: https://github.com/rust-lang/rust/pull/40526 +[RFC 1623]: https://github.com/rust-lang/rfcs/blob/master/text/1623-static.md +[RFC 1647]: https://github.com/rust-lang/rfcs/blob/master/text/1647-allow-self-in-where-clauses.md +[RFC 1651]: https://github.com/rust-lang/rfcs/blob/master/text/1651-movecell.md +[RFC 1682]: https://github.com/rust-lang/rfcs/blob/master/text/1682-field-init-shorthand.md +[`Arc::from_raw`]: https://doc.rust-lang.org/std/sync/struct.Arc.html#method.from_raw +[`Arc::into_raw`]: https://doc.rust-lang.org/std/sync/struct.Arc.html#method.into_raw +[`Arc::ptr_eq`]: https://doc.rust-lang.org/std/sync/struct.Arc.html#method.ptr_eq +[`BTreeMap::range_mut`]: https://doc.rust-lang.org/std/collections/btree_map/struct.BTreeMap.html#method.range_mut +[`BTreeMap::range`]: https://doc.rust-lang.org/std/collections/btree_map/struct.BTreeMap.html#method.range +[`Cell::into_inner`]: https://doc.rust-lang.org/std/cell/struct.Cell.html#method.into_inner +[`Cell::replace`]: https://doc.rust-lang.org/std/cell/struct.Cell.html#method.replace +[`Cell::swap`]: https://doc.rust-lang.org/std/cell/struct.Cell.html#method.swap +[`Cell::take`]: https://doc.rust-lang.org/std/cell/struct.Cell.html#method.take +[`Ordering::then_with`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.then_with +[`Ordering::then`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.then +[`Rc::from_raw`]: https://doc.rust-lang.org/std/rc/struct.Rc.html#method.from_raw +[`Rc::into_raw`]: https://doc.rust-lang.org/std/rc/struct.Rc.html#method.into_raw +[`Rc::ptr_eq`]: https://doc.rust-lang.org/std/rc/struct.Rc.html#method.ptr_eq +[`Result::expect_err`]: https://doc.rust-lang.org/std/result/enum.Result.html#method.expect_err +[`collections::Bound`]: https://doc.rust-lang.org/std/collections/enum.Bound.html +[`process::abort`]: https://doc.rust-lang.org/std/process/fn.abort.html +[`ptr::read_unaligned`]: https://doc.rust-lang.org/std/ptr/fn.read_unaligned.html +[`ptr::write_unaligned`]: https://doc.rust-lang.org/std/ptr/fn.write_unaligned.html +[cargo/3562]: https://github.com/rust-lang/cargo/pull/3562 +[cargo/3664]: https://github.com/rust-lang/cargo/pull/3664 +[cargo/3667]: https://github.com/rust-lang/cargo/pull/3667 +[cargo/3691]: https://github.com/rust-lang/cargo/pull/3691 +[cargo/3699]: https://github.com/rust-lang/cargo/pull/3699 +[cargo/3731]: https://github.com/rust-lang/cargo/pull/3731 +[mdbook]: https://crates.io/crates/mdbook +[ubook]: https://doc.rust-lang.org/unstable-book/ + + Version 1.16.0 (2017-03-16) =========================== Language -------- -* Lifetimes in statics and consts default to `'static`. [RFC 1623] * [The compiler's `dead_code` lint now accounts for type aliases][38051]. * [Uninhabitable enums (those without any variants) no longer permit wildcard match patterns][38069] @@ -5056,7 +5463,7 @@ Version 0.1 (2012-01-20) * Compiler works with the following configurations: * Linux: x86 and x86_64 hosts and targets - * MacOS: x86 and x86_64 hosts and targets + * macOS: x86 and x86_64 hosts and targets * Windows: x86 hosts and targets * Cross compilation / multi-target configuration supported. diff --git a/configure b/configure index 35b376d5f2..c5ecc22368 100755 --- a/configure +++ b/configure @@ -479,6 +479,7 @@ valopt i686-linux-android-ndk "" "i686-linux-android NDK standalone path" valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path" valopt armv7-linux-androideabi-ndk "" "armv7-linux-androideabi NDK standalone path" valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path" +valopt x86_64-linux-android-ndk "" "x86_64-linux-android NDK standalone path" valopt nacl-cross-path "" "NaCl SDK path (Pepper Canary is recommended). Must be absolute!" valopt musl-root "/usr/local" "MUSL root installation directory (deprecated)" valopt musl-root-x86_64 "" "x86_64-unknown-linux-musl install directory" @@ -746,6 +747,7 @@ putvar CFG_AARCH64_LINUX_ANDROID_NDK putvar CFG_ARM_LINUX_ANDROIDEABI_NDK putvar CFG_ARMV7_LINUX_ANDROIDEABI_NDK putvar CFG_I686_LINUX_ANDROID_NDK +putvar CFG_X86_64_LINUX_ANDROID_NDK putvar CFG_NACL_CROSS_PATH putvar CFG_MANDIR putvar CFG_DOCDIR diff --git a/man/rustc.1 b/man/rustc.1 index 1656255956..6c80f11fa7 100644 --- a/man/rustc.1 +++ b/man/rustc.1 @@ -50,7 +50,7 @@ Comma separated list of types of crates for the compiler to emit. \fB\-\-crate\-name\fR \fINAME\fR Specify the name of the crate being built. .TP -\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|link|dep\-info][=\fIPATH\fR] +\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|link|dep\-info|mir][=\fIPATH\fR] Configure the output that \fBrustc\fR will produce. Each emission may also have an optional explicit output \fIPATH\fR specified for that particular emission kind. This path takes precedence over the \fB-o\fR option. diff --git a/rls/.travis.yml b/rls/.travis.yml new file mode 100644 index 0000000000..72d034ef95 --- /dev/null +++ b/rls/.travis.yml @@ -0,0 +1,17 @@ +language: rust +sudo: true +cache: cargo +os: + - linux + - osx +rust: + - nightly +before_install: + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo add-apt-repository ppa:kubuntu-ppa/backports -y; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get update -qq; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -qq cmake=2.8.12.2-0ubuntu1~ubuntu12.04.1~ppa2; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew upgrade cmake; fi +script: + - cargo build --verbose + - cargo test --release --verbose diff --git a/rls/COPYRIGHT b/rls/COPYRIGHT new file mode 100644 index 0000000000..26292d9061 --- /dev/null +++ b/rls/COPYRIGHT @@ -0,0 +1,40 @@ +Short version for non-lawyers: + +The Rust Project is dual-licensed under Apache 2.0 and MIT +terms. + + +Longer version: + +The Rust Project is copyright 2010, The Rust Project +Developers. + +Licensed under the Apache License, Version 2.0 + or the MIT +license , +at your option. All files in the project carrying such +notice may not be copied, modified, or distributed except +according to those terms. + +* Additional copyright may be retained by contributors other + than Mozilla, the Rust Project Developers, or the parties + enumerated in this file. Such copyright can be determined + on a case-by-case basis by examining the author of each + portion of a file in the revision-control commit records + of the project, or by consulting representative comments + claiming copyright ownership for a file. + + For example, the text: + + "Copyright (c) 2011 Google Inc." + + appears in some files, and these files thereby denote + that their author and copyright-holder is Google Inc. + + In all such cases, the absence of explicit licensing text + indicates that the contributor chose to license their work + for distribution under identical terms to those Mozilla + has chosen for the collective work, enumerated at the top + of this file. The only difference is the retention of + copyright itself, held by the contributor. diff --git a/rls/Cargo.lock b/rls/Cargo.lock new file mode 100644 index 0000000000..b463253f77 --- /dev/null +++ b/rls/Cargo.lock @@ -0,0 +1,1349 @@ +[root] +name = "rls" +version = "0.1.0" +dependencies = [ + "cargo 0.19.0 (git+https://github.com/rust-lang/cargo)", + "derive-new 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)", + "languageserver-types 0.7.0 (git+https://github.com/gluon-lang/languageserver-types)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "racer 2.0.6 (git+https://github.com/phildawes/racer)", + "rls-analysis 0.1.0 (git+https://github.com/nrc/rls-analysis)", + "rls-data 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-vfs 0.1.0 (git+https://github.com/nrc/rls-vfs)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfmt 0.8.3 (git+https://github.com/rust-lang-nursery/rustfmt)", + "serde 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url_serde 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "advapi32-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)", +] + +[[package]] +name = "aho-corasick" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "aho-corasick" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ansi_term" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cargo" +version = "0.19.0" +source = "git+https://github.com/rust-lang/cargo#c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28" +dependencies = [ + "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)", + "crates-io 0.8.0 (git+https://github.com/rust-lang/cargo)", + "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", + "fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.6.4 (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)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (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.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", + "psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_ignored 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.9.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.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.4.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 = "cfg-if" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "chrono" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "clap" +version = "2.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cmake" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cookie" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crates-io" +version = "0.8.0" +source = "git+https://github.com/rust-lang/cargo#c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28" +dependencies = [ + "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "curl" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "curl-sys 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-probe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.10 (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.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "derive-new" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "diff" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "docopt" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "dtoa" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "either" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "enum_primitive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "env_logger" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "env_logger" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "filetime" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "flate2" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "foreign-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fs2" +version = "0.4.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.21 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gcc" +version = "0.3.45" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "gdi32-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)", +] + +[[package]] +name = "getopts" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "git2" +version = "0.6.4" +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.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-probe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "git2-curl" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glob" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "hpack" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "httparse" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "hyper" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "idna" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itertools" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.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 = "language-tags" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "languageserver-types" +version = "0.7.0" +source = "git+https://github.com/gluon-lang/languageserver-types#2c1f975cb49f828e139e05acd09ae2ca187dc759" +dependencies = [ + "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url_serde 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libgit2-sys" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libssh2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libssh2-sys" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libz-sys" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "log" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "matches" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memchr" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mime" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miniz-sys" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miow" +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)", + "net2 0.2.27 (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)", +] + +[[package]] +name = "multimap" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "net2" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.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.21 (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)", +] + +[[package]] +name = "num" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-integer" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-iter" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num_cpus" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl-probe" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "openssl-sys" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", + "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pkg-config" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "psapi-sys" +version = "0.1.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)", +] + +[[package]] +name = "quote" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "quote" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "racer" +version = "2.0.6" +source = "git+https://github.com/phildawes/racer#7441e0cd5116a27e0b5849d7a8b0f9b159b19ff1" +dependencies = [ + "clap 2.19.3 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "typed-arena 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_syscall" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "regex" +version = "0.1.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "regex-syntax" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rls-analysis" +version = "0.1.0" +source = "git+https://github.com/nrc/rls-analysis#28d88412bd345631f7b502e418114134151dd16d" +dependencies = [ + "derive-new 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rls-data" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rls-span" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rls-vfs" +version = "0.1.0" +source = "git+https://github.com/nrc/rls-vfs#d7ff7e8bc1b51c39b558a6fdfe919e2dc88e502d" +dependencies = [ + "racer 2.0.6 (git+https://github.com/phildawes/racer)", + "rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-serialize" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc_version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustfmt" +version = "0.8.3" +source = "git+https://github.com/rust-lang-nursery/rustfmt#b46c147fedd5c744f63c6941de75e738e6c5047b" +dependencies = [ + "diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.5.10 (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.21 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "multimap 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "strings 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation 1.1.0 (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)", +] + +[[package]] +name = "same-file" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "semver" +version = "0.6.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)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "0.9.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_codegen_internals" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "syn 0.11.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "0.9.13" +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_codegen_internals 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_ignored" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "shell-escape" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "solicit" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "strings" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "strsim" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "strsim" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "syn" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "0.11.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synom" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syntex_errors" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syntex_errors" +version = "0.58.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syntex_pos" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syntex_pos" +version = "0.58.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syntex_syntax" +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.21 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syntex_syntax" +version = "0.58.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tar" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tempdir" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "term" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "term_size" +version = "0.2.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.21 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread-id" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread-id" +version = "3.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.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "time" +version = "0.1.36" +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.21 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "toml" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "toml" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "traitobject" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "typeable" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "typed-arena" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicase" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-bidi" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-segmentation" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-segmentation" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-width" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unreachable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "url" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "url_serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "user32-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)", +] + +[[package]] +name = "utf8-ranges" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "utf8-ranges" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vec_map" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "walkdir" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ws2_32-sys" +version = "0.2.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)", +] + +[metadata] +"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a" +"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" +"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" +"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" +"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" +"checksum cargo 0.19.0 (git+https://github.com/rust-lang/cargo)" = "" +"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" +"checksum chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9213f7cd7c27e95c2b57c49f0e69b1ea65b27138da84a170133fd21b07659c00" +"checksum clap 2.19.3 (registry+https://github.com/rust-lang/crates.io-index)" = "95b78f3fe0fc94c13c731714363260e04b557a637166f33a4570d3189d642374" +"checksum cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d68987ed4c516dcc3e7913659bfa4076f5182eea4a7e0038bb060953e76ac" +"checksum cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e3d6405328b6edb412158b3b7710e2634e23f3614b9bb1c412df7952489a626" +"checksum crates-io 0.8.0 (git+https://github.com/rust-lang/cargo)" = "" +"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" +"checksum curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c90e1240ef340dd4027ade439e5c7c2064dd9dc652682117bd50d1486a3add7b" +"checksum curl-sys 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d909dc402ae80b6f7b0118c039203436061b9d9a3ca5d2c2546d93e0a61aaa" +"checksum derive-new 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41be6ca3b99e0c0483fb2389685448f650459c3ecbe4e18d7705d8010ec4ab8e" +"checksum diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0a515461b6c8c08419850ced27bc29e86166dcdcde8fbe76f8b1f0589bb49472" +"checksum docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8" +"checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" +"checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a" +"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.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83" +"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" +"checksum flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "d4e4d0c15ef829cbc1b7cda651746be19cceeb238be7b1049227b14891df9e25" +"checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" +"checksum fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34edaee07555859dc13ca387e6ae05686bb4d0364c95d649b6dab959511f4baf" +"checksum gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "40899336fb50db0c78710f53e87afc54d8c7266fb76262fecc78ca1a7f09deae" +"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" +"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" +"checksum git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "046ae03385257040b2a35e56d9669d950dd911ba2bf48202fbef73ee6aab27b2" +"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 hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2da7d3a34cf6406d9d700111b8eafafe9a251de41ae71d8052748259343b58" +"checksum httparse 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a6e7a63e511f9edffbab707141fbb8707d1a3098615fb2adbd5769cdfcc9b17d" +"checksum hyper 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)" = "1b9bf64f730d6ee4b0528a5f0a316363da9d8104318731509d4ccc86248f82b3" +"checksum idna 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac85ec3f80c8e4e99d9325521337e14ec7555c458a14e377d189659a427f375" +"checksum itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4833d6978da405305126af4ac88569b5d71ff758581ce5a987dbfa3755f694fc" +"checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" +"checksum languageserver-types 0.7.0 (git+https://github.com/gluon-lang/languageserver-types)" = "" +"checksum lazy_static 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2f61b8421c7a4648c391611625d56fdd5c7567da05af1be655fd8cacc643abb3" +"checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" +"checksum libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d951fd5eccae07c74e8c2c1075b05ea1e43be7f8952245af8c2840d1480b1d95" +"checksum libssh2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "91e135645c2e198a39552c8c7686bb5b83b1b99f64831c040a6c2798a1195934" +"checksum libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e5ee912a45d686d393d5ac87fac15ba0ba18daae14e8e7543c63ebf7fb7e970c" +"checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" +"checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1" +"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" +"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" +"checksum mime 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5514f038123342d01ee5f95129e4ef1e0470c93bc29edf058a46f9ee3ba6737e" +"checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726" +"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +"checksum multimap 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9223f4774d08e06185e44e555b9a7561243d387bac49c78a6205c42d6975fbf2" +"checksum net2 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)" = "18b9642ad6222faf5ce46f6966f59b71b9775ad5758c9e09fcf0a6c8061972b4" +"checksum num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "98b15ba84e910ea7a1973bccd3df7b31ae282bf9d8bd2897779950c9b8303d40" +"checksum num-integer 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "21e4df1098d1d797d27ef0c69c178c3fab64941559b290fcae198e0825c9c8b5" +"checksum num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d1891bd7b936f12349b7d1403761c8a0b85a18b148e9da4429d5d102c1a41e" +"checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" +"checksum num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a18c392466409c50b87369414a2680c93e739aedeb498eb2bff7d7eb569744e2" +"checksum openssl 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8aa0eb7aad44f0da6f7dda13ddb4559d91a0f40cfab150b1f76ad5b39ec523f" +"checksum openssl-probe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "756d49c8424483a3df3b5d735112b4da22109ced9a8294f1f5cdf80fb3810919" +"checksum openssl-sys 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "14f5bfd12054d764510b887152d564ba11d99ae24ea7d740781778f646620576" +"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" +"checksum psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "abcd5d1a07d360e29727f757a9decb3ce8bc6e0efa8969cfaad669a8317a2478" +"checksum quote 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5cf478fe1006dbcc72567121d23dbdae5f1632386068c5c86ff4f645628504" +"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" +"checksum racer 2.0.6 (git+https://github.com/phildawes/racer)" = "" +"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" +"checksum redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "29dbdfd4b9df8ab31dec47c6087b7b13cbf4a776f335e4de8efba8288dda075b" +"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" +"checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" +"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" +"checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" +"checksum rls-analysis 0.1.0 (git+https://github.com/nrc/rls-analysis)" = "" +"checksum rls-data 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af1dfff00189fd7b78edb9af131b0de703676c04fa8126aed77fd2c586775a4d" +"checksum rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8656f7b850ac85fb204ef94318c641bbb15a32766e12f9a589a23e4c0fbc38db" +"checksum rls-vfs 0.1.0 (git+https://github.com/nrc/rls-vfs)" = "" +"checksum rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "684ce48436d6465300c9ea783b6b14c4361d6b8dcbb1375b486a69cc19e2dfb0" +"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" +"checksum rustfmt 0.8.3 (git+https://github.com/rust-lang-nursery/rustfmt)" = "" +"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" +"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" +"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)" = "231dfd55909400769e437326cfb4af8bec97c3dd56ab3d02df8ef5c7e00f179b" +"checksum serde_codegen_internals 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bc888bd283bd2420b16ad0d860e35ad8acb21941180a83a189bb2046f9d00400" +"checksum serde_derive 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)" = "d75c72ef4dd193d89eb652b73890fe2489996c9ead8b37980f57a1078f96ed50" +"checksum serde_ignored 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4b3f5576874721d14690657e9f0ed286e72a52be2f6fdc0cf2f024182bd8f64" +"checksum serde_json 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)" = "dbc45439552eb8fb86907a2c41c1fd0ef97458efb87ff7f878db466eb581824e" +"checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8" +"checksum solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "172382bac9424588d7840732b250faeeef88942e37b6e35317dce98cafdd75b2" +"checksum strings 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "54f86446ab480b4f60782188f4f78886465c5793aee248cbb48b7fdc0d022420" +"checksum strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "67f84c44fbb2f91db7fef94554e6b2ac05909c9c0b0bc23bb98d3a1aebfe7f7c" +"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" +"checksum syn 0.11.10 (registry+https://github.com/rust-lang/crates.io-index)" = "171b739972d9a1bfb169e8077238b51f9ebeaae4ff6e08072f7ba386a8802da2" +"checksum syn 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6ae6fb0dcc9bd85f89a1a4adc0df2fd90c90c98849d61433983dd7a9df6363f7" +"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" +"checksum syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e52bffe6202cfb67587784cf23e0ec5bf26d331eef4922a16d5c42e12aa1e9b" +"checksum syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "867cc5c2d7140ae7eaad2ae9e8bf39cb18a67ca651b7834f88d46ca98faadb9c" +"checksum syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "955ef4b16af4c468e4680d1497f873ff288f557d338180649e18f915af5e15ac" +"checksum syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13ad4762fe52abc9f4008e85c4fb1b1fe3aa91ccb99ff4826a439c7c598e1047" +"checksum syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde" +"checksum syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6e0e4dbae163dd98989464c23dd503161b338790640e11537686f2ef0f25c791" +"checksum tar 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c2374f318bbe2c5ac6c83dd6240d5f1a73106f72d39b3f7d6f8d8637c7b425d8" +"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" +"checksum term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d168af3930b369cfe245132550579d47dfd873d69470755a19c2c6568dbbd989" +"checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a" +"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" +"checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a" +"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" +"checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7" +"checksum time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "211b63c112206356ef1ff9b19355f43740fc3f85960c598a93d3a3d3ba7beade" +"checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" +"checksum toml 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd86ad9ebee246fdedd610e0f6d0587b754a3d81438db930a244d0480ed7878f" +"checksum traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "07eaeb7689bb7fca7ce15628319635758eda769fed481ecfe6686ddef2600616" +"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" +"checksum typed-arena 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e2f9dc90da4f9d66ffc9ad3ead2c7d57582a26f4a3292d2ce7011bd29965100" +"checksum unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a5906ca2b98c799f4b1ab4557b76367ebd6ae5ef14930ec841c74aed5f3764" +"checksum unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a078ebdd62c0e71a709c3d53d2af693fe09fe93fbff8344aebe289b78f9032" +"checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff" +"checksum unicode-segmentation 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c3bc443ded17b11305ffffe6b37e2076f328a5a8cb6aa877b1b98f77699e98b5" +"checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3" +"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" +"checksum unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb" +"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 url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e" +"checksum url_serde 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "64ddbc0a67ae30778179166934129e0aeb92c5b7051d8e0b519e3bce73aff106" +"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47" +"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" +"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" +"checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f" +"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 winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/rls/Cargo.toml b/rls/Cargo.toml new file mode 100644 index 0000000000..1ca0bd677c --- /dev/null +++ b/rls/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "rls" +version = "0.1.0" +authors = ["Jonathan Turner "] + +[dependencies] +cargo = { git = "https://github.com/rust-lang/cargo" } +derive-new = "0.3" +env_logger = "0.3" +languageserver-types = { git = "https://github.com/gluon-lang/languageserver-types" } +log = "0.3" +racer = { git = "https://github.com/phildawes/racer" } +rls-analysis = { git = "https://github.com/nrc/rls-analysis" } +rls-data = "0.1" +rls-span = { version = "0.1", features = ["serialize-serde"] } +rls-vfs = { git = "https://github.com/nrc/rls-vfs", features = ["racer-impls"] } +rustc-serialize = "0.3" +rustfmt = { git = "https://github.com/rust-lang-nursery/rustfmt" } +serde = "0.9" +serde_json = "0.9" +serde_derive = "0.9" +toml = "0.3" +url = "1.1.0" +url_serde = "0.1.0" + +[dependencies.hyper] +version = "0.9" +default-features = false diff --git a/rls/LICENSE-APACHE b/rls/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/rls/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/rls/LICENSE-MIT b/rls/LICENSE-MIT new file mode 100644 index 0000000000..40b8817a47 --- /dev/null +++ b/rls/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rls/README.md b/rls/README.md new file mode 100644 index 0000000000..c1525c9672 --- /dev/null +++ b/rls/README.md @@ -0,0 +1,123 @@ +[![Build Status](https://travis-ci.org/rust-lang-nursery/rls.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rls) [![Build status](https://ci.appveyor.com/api/projects/status/cxfejvsqnnc1oygs?svg=true)](https://ci.appveyor.com/project/jonathandturner/rls-x6grn) + + + +# Rust Language Server (RLS) + +**This project is in the alpha stage of development. It is likely to be buggy in +some situations; proceed with caution.** + +The RLS provides a server that runs in the background, providing IDEs, +editors, and other tools with information about Rust programs. It supports +functionality such as 'goto definition', symbol search, reformatting, and code +completion, and enables renaming and refactorings. + +The RLS gets its source data from the compiler and from +[Racer](https://github.com/phildawes/racer). Where possible it uses data from +the compiler which is precise and complete. Where its not possible, (for example +for code completion and where building is too slow), it uses Racer. + +Since the Rust compiler does not yet support end-to-end incremental compilation, +we can't offer a perfect experience. However, by optimising our use of the +compiler and falling back to Racer, we can offer a pretty good experience for +small to medium sized crates. As the RLS and compiler evolve, we'll offer a +better experience for larger and larger crates. + +The RLS is designed to be frontend-independent. We hope it will be widely +adopted by different editors and IDEs. To seed development, we provide a +[reference implementation of an RLS frontend](https://github.com/jonathandturner/rls_vscode) +for [Visual Studio Code](https://code.visualstudio.com/). + + +## Setup + +### Step 1: Install rustup + +You can install [rustup](http://rustup.rs/) on many platforms. This will help us quickly install the +rls and its dependencies. + +### Step 2: Switch to nightly + +Switch to the nightly compiler: + +``` +rustup default nightly +rustup update nightly +``` + +### Step 3: Install the RLS + +Once you have rustup installed, run the following commands: + +``` +rustup component add rls +rustup component add rust-analysis +rustup component add rust-src +``` + +If you've never set up Racer before, you may also need follow the [Racer configuration +steps](https://github.com/phildawes/racer#configuration) + +## Running + +Though the RLS is built to work with many IDEs and editors, we currently use +VSCode to test the RLS. + +To run with VSCode, you'll need a +[recent VSCode version](https://code.visualstudio.com/download) installed. + +Next, you'll need to run the VSCode extension (for this step, you'll need a +recent [node](https://nodejs.org/en/) installed: + +``` +git clone https://github.com/jonathandturner/rls_vscode.git +cd rls_vscode +npm install +code . +``` + +VSCode will open into the `rls_vscode` project. From here, click the Debug +button on the left-hand side (a bug with a line through it). Next, click the +green triangle at the top. This will launch a new instance of VSCode with the +`rls_vscode` plugin enabled. From there, you can open your Rust projects using +the RLS. + +You'll know it's working when you see this in the status bar at the bottom, with +a spinning indicator: + +`RLS analysis: working /` + +Once you see: + +`RLS analysis: done` + +Then you have the full set of capabilities available to you. You can goto def, +find all refs, rename, goto type, etc. Completions are also available using the +heuristics that Racer provides. As you type, your code will be checked and +error squiggles will be reported when errors occur. You can hover these +squiggles to see the text of the error. + +## Configuration + +The RLS can be configured on a per-project basis by adding a file called +`rls.toml` to the project root (i.e., next to Cargo.toml). Entries in this file +will affect how the RLS operates and how it builds your project. + +Currently we accept the following options: + +* `build_lib` (`bool`, defaults to `false`) checks the project as if you passed + the `--lib` argument to cargo. +* `cfg_test` (`bool`, defaults to `true`) checks the project as if you were + running `cargo test` rather than `cargo build`. I.e., compiles (but does not + run) test code. +* `unstable_features` (`bool`, defaults to `false`) enables unstable features. + Currently, this includes renaming and formatting. +* `sysroot` (`String`, defaults to `""`) if the given string is not empty, use + the given path as the sysroot for all rustc invocations instead of trying to + detect the sysroot automatically + + +## Contributing + +You can look in the [contributing.md](https://github.com/rust-lang-nursery/rls/blob/master/contributing.md) +in this repo to learn more about contributing to this project. diff --git a/rls/appveyor.yml b/rls/appveyor.yml new file mode 100644 index 0000000000..ef6e8c0c32 --- /dev/null +++ b/rls/appveyor.yml @@ -0,0 +1,41 @@ +environment: + global: + RUST_TEST_THREADS: 1 + PROJECT_NAME: rls + matrix: + # Nightly channel + #- TARGET: i686-pc-windows-gnu + # CHANNEL: nightly + # BITS: 32 + - TARGET: i686-pc-windows-msvc + CHANNEL: nightly + BITS: 32 + #- TARGET: x86_64-pc-windows-gnu + # CHANNEL: nightly + # BITS: 64 + - TARGET: x86_64-pc-windows-msvc + CHANNEL: nightly + BITS: 64 + +install: + - set PATH=C:\msys64\mingw%BITS%\bin;C:\msys64\usr\bin;%PATH% + - curl -sSf -o rustup-init.exe https://win.rustup.rs + # Install rust, x86_64-pc-windows-msvc host + - rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain nightly-x86_64-pc-windows-msvc + # Install the target we're compiling for + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - set PATH=%PATH%;C:\Users\appveyor\.multirust\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\%TARGET%\lib + - if NOT "%TARGET%" == "x86_64-pc-windows-msvc" rustup target add %TARGET% + - rustc -Vv + - cargo -V + + +build: false + +test_script: + - set RUST_TEST_THREADS=1 + - cargo test --release --target %TARGET% --verbose + +cache: + - target + - C:\Users\appveyor\.cargo\registry diff --git a/rls/contributing.md b/rls/contributing.md new file mode 100644 index 0000000000..ff13df06dc --- /dev/null +++ b/rls/contributing.md @@ -0,0 +1,300 @@ +# Contributing + +This document provides information for developers who want to contribute to the +RLS or run it in a heavily customised configuration. + +The RLS is open source and we'd love you to contribute to the project. Testing, +reporting issues, writing documentation, writing tests, writing code, and +implementing clients are all extremely valuable. + +Here is the list of known [issues](https://github.com/rust-lang-nursery/rls/issues). +These are [good issues to start on](https://github.com/rust-lang-nursery/rls/issues?q=is%3Aopen+is%3Aissue+label%3Aeasy). + +We're happy to help however we can. The best way to get help is either to +leave a comment on an issue in this repo, or to ping us (nrc or jntrnr) in #rust-tools +on IRC. + +We'd love for existing and new tools to use the RLS. If that sounds interesting +please get in touch by filing an issue or on IRC. + + +## Building + +**YOU NEED A VERY RECENT NIGHTLY COMPILER** + +Otherwise the RLS will not work very well. You also don't need to build the `rls` to use it. Instead, you can +install via `rustup`, which is the currently preferred method. See the [readme](README.md) for more information. + +### Step 1: Install build dependencies + +On Linux, you will need [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/) +and [zlib](http://zlib.net/): + +- On Ubuntu run: `sudo apt-get install pkg-config zlib1g-dev` +- On Fedora run: `sudo dnf install pkgconfig zlib-devel` + +### Step 2: Clone and build the RLS + +Since the RLS is closely linked to the compiler and is in active development, +you'll need a recent nightly compiler to build it. + +``` +git clone https://github.com/rust-lang-nursery/rls.git +cd rls +cargo build --release +``` + +### Step 3: Connect the RLS to your compiler + +If you're using recent versions of rustup, you will also need to make sure that +the compiler's dynamic libraries are available for the RLS to load. You can see +where they are using: + +``` +rustc --print sysroot +``` + +This will show you where the compiler keeps the dynamic libs. In Windows, this +will be in the `bin` directory under this path. On other platforms, it will be +in the `lib` directory. + +Next, you'll make the compiler available to the RLS: + +#### Windows + +On Windows, make sure this path (plus `bin`) is in your PATH. For example: + +``` +set PATH=%PATH%;C:\Users\appveyor\.multirust\toolchains\nightly-i686-pc-windows-gnu\bin +``` + +#### Mac + +For Mac, you need to set the DYLD_LIBRARY_PATH. For example: + +``` +export DYLD_LIBRARY_PATH=$(rustc --print sysroot)/lib +``` + +#### Linux + +For Linux, this path is called LD_LIBRARY_PATH. + +``` +export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib +``` + +### Step 4: Set your RLS_ROOT + +Next, we'll set the RLS_ROOT environment variable to point to where we built +the RLS: + +``` +export RLS_ROOT=/Source/rls +``` + +### Step 5: Download standard library metadata + +Finally, we need to get the metadata for the standard library. This lets +us get additional docs and types for all of `std`. The command is currently only +supported on the nightly compilers, though we hope to remove this restriction in +the future. + +``` +rustup component add rust-analysis +``` + +If you've never set up Racer before, you may also need follow the [Racer configuration +steps](https://github.com/phildawes/racer#configuration) + +## Running and testing + +You can run the rls by hand with: + +``` +cargo run +``` + +Though more commonly, you'll use an IDE plugin to invoke it for you. + +Test using `cargo test`. + +Testing is unfortunately minimal. There is support for regression tests, but not +many actual tests exists yet. There is signifcant [work to do](https://github.com/rust-lang-nursery/rls/issues/12) +before we have a comprehensive testing story. + + +## Standard library support + +The way it works is that when the libraries are built, the compiler can emit all +the data that the RLS needs. This can be read by the RLS on startup and used to +provide things like type on hover without having access to the source code for +the libraries. + +The compiler gives every definition an id, and the RLS matches up these ids. In +order for the RLS to work, the id of a identifier used in the IDE and the id of +its declaration in a library must match exactly. Since ids are very unstable, +the data used by the RLS for libraries must match exactly with the crate that +your source code links with. + +You need a version of the above data which exactly matches the standard +libraries you will use with your project. Rustup takes care of this for you and +is the preferred (and easiest) method for installing this data. If you want to +use the RLS with a Rust compiler/libraries you have built yourself, then you'll +need to take some extra steps. + + +### Install with rustup + +You'll need to be using [rustup](https://www.rustup.rs/) to manage your Rust +compiler toolchains. The RLS does not yet support cross-compilation - your +compiler host and target must be exactly the same. + +You must be using nightly (you need to be using nightly for the RLS to work at +the moment in any case). To install a nightly toolchain use `rustup install +nightly`. To switch to using that nightly toolchain by default use `rustup +default nightly`. + +Add the RLS data component using `rustup component add rust-analysis`. + +Everything should now work! You may need to restart the RLS. + + +### Build it yourself + +When you build Rust, add `-Zsave-analysis-api` to your stage 2 flags, e.g., by +setting the environment variable: + +``` +export RUSTFLAGS_STAGE2='-Zsave-analysis-api' +``` + +When the build has finished, you should have a bunch of JSON data in a directory like +`~/rust1/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/release/deps/save-analysis`. + +You need to copy all those files (should be around 16) into a new directory: +`~/rust1/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-gnu/analysis` +(assuming you are running the stage 2 compiler you just built. You'll need to +modify the root directory (`~/rust1` here) and the host triple +(`x86_64-unknown-linux-gnu` in both places)). + + +Finally, to run the RLS you'll need to set things up to use the newly built +compiler, something like: + +``` +export RUSTC="~/rust1/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" +``` + +Either before you run the RLS, or before you run the IDE which will start the +RLS. + + +### Details + +Rustup (or you, manually) will install the rls data (which is a bunch of json +files) into `$SYSROOT/lib/rustlib/$TARGET_TRIPLE/analysis`, where `$SYSROOT` is +your Rust sysroot, this can be found using `rustc --print=sysroot`. +`$TARGET_TRIPLE` is the triple which defines the compilation target. Since the +RLS currently does not support cross-compilation, this must match your host +triple. It will look something like `x86_64-unknown-linux-gnu`. + +For example, on my system RLS data is installed at: + +``` +/home/ncameron/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/analysis +``` + +This data is only for the standard libraries, project-specific data is stored +inside your project's target directory. + + +## Implementation overview + +The goal of the RLS project is to provide an awesome IDE experience *now*. That +means not waiting for incremental compilation support in the compiler. However, +Rust is a somewhat complex language to analyse and providing precise and +complete information about programs requires using the compiler. + +The RLS has two data sources - the compiler and Racer. The compiler is always +right, and always precise. But can sometimes be too slow for IDEs. Racer is +nearly always fast, but can't handle some constructs (e.g., macros) or can only +handle them with limited precision (e.g., complex generic types). + +The RLS tries to provide data using the compiler. It sets a time budget and +queries both the compiler and Racer. If the compiler completes within the time +budget, we use that data. If not, we use Racer's data. + +We link both Racer and the compiler into the RLS, so we don't need to shell out +to either (though see notes on the build process below). We also customise our +use of the compiler (via standard APIs) so that we can read modified files +directly from memory without saving them to disk. + +### Building + +The RLS tracks changes to files, and keeps the changed file in memory (i.e., the +RLS does not need the IDE to save a file before providing data). These changed +files are tracked by the 'Virtual File System' (which is a bit of a grandiose +name for a pretty simple file cache at the moment, but I expect this area to +grow significantly in the future). The VFS is in a [separate +crate](https://github.com/nrc/rls-vfs). + +We want to start building before the user needs information (it would be too +slow to start a build when data is requested). However, we don't want to start a +build on every keystroke (this would be too heavy on user resources). Nor is +there any point starting multiple builds when we would throw away the data from +some of them. We therefore try to queue up and coalesce builds. This is further +documented in [src/build.rs](src/build.rs). + +When we do start a build, we may also need to build dependent crates. We +therefore do a full `cargo build`. However, we do not compile the last crate +(the one the user is editing in the IDE). We only run Cargo to get a command +line to build that crate. Furthermore, we cache that command line, so for most +builds (where we don't need to build dependent crates, and where we can be +reasonably sure they haven't changed since a previous build) we don't run Cargo +at all. + +The command line we got from Cargo, we chop up and feed to the in-process +compiler. We then collect error messages and analysis data in JSON format +(although this is inefficient and [should +change](https://github.com/rust-lang-nursery/rls/issues/25)). + +### Analysis data + +From the compiler, we get a serialised dump of its analysis data (from name +resolution and type checking). We combine data from all crates and the standard +libraries and combine this into an index for the whole project. We cross- +reference and store this data in HashMaps and use it to look up data for the +IDE. + +Reading, processing, and storing the analysis data is handled by the +[rls-analysis crate](https://github.com/nrc/rls-analysis). + +### Communicating with IDEs + +The RLS communicates with IDEs via +the [Language Server protocol](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md). + +The LS protocol uses JSON sent over stdin/stdout. The JSON is rather dynamic - +we can't make structs to easily map to many of the protocol objects. The client +sends commands and notifications to the RLS. Commands must get a reply, +notifications do not. Usually the structure of the reply is dictated by the +protocol spec. The RLS can also send notifications to the client. So for a long +running task (such as a build), the RLS will reply quickly to acknowledge the +request, then send a message later with the result of the task. + +Associating requests with replies is done using an id which must be handled by +the RLS. + + +### Extensions to the Language Server Protocol + +The RLS uses some custom extensions to the Language Server Protocol. Currently +these are all sent from the RLS to an LSP client and are only used to improve +the user experience by showing progress indicators. + +* `rustDocument/diagnosticsBegin`: notification, no arguments. Sent before a + build starts and before any diagnostics from a build are sent. +* `rustDocument/diagnosticsEnd`: notification, no arguments. Sent when a build + is complete (successfully or not, or even skipped) and all post-build analysis + by the RLS is complete. diff --git a/rls/goto_def.sh b/rls/goto_def.sh new file mode 100755 index 0000000000..58be345258 --- /dev/null +++ b/rls/goto_def.sh @@ -0,0 +1,5 @@ +# jntrnr's test +#curl -v -H "Content-Type: application/json" -X POST -d '{{"pos": {"filepath":"sample_project/src/main.rs","line":22,"col":5}, "span":{"file_name":"sample_project/src/main.rs","line_start":22,"column_start":5,"line_end":22,"column_end":6}}}' 127.0.0.1:9000/goto_def + +# nrc's test +curl -v -H "Content-Type: application/json" -X POST -d '{{"pos": {"filepath":"sample_project_2/src/main.rs","line":18,"col":15}, "span":{"file_name":"src/main.rs","line_start":18,"column_start":13,"line_end":18,"column_end":16}}}' 127.0.0.1:9000/goto_def diff --git a/rls/ls.sh b/rls/ls.sh new file mode 100755 index 0000000000..cd6f58b7e0 --- /dev/null +++ b/rls/ls.sh @@ -0,0 +1,6 @@ +export PATH="$PWD/target/debug:$PATH" +#export RUSTC="/home/ncameron/rust/x86_64-unknown-linux-gnu/stage2/bin/rustc" +#export SYS_ROOT="/home/ncameron/rust/x86_64-unknown-linux-gnu/stage2" +#export SYS_ROOT="/usr/local" +export RUST_BACKTRACE=1 +cargo build && code diff --git a/rls/src/actions/compiler_message_parsing.rs b/rls/src/actions/compiler_message_parsing.rs new file mode 100644 index 0000000000..9fd6b14618 --- /dev/null +++ b/rls/src/actions/compiler_message_parsing.rs @@ -0,0 +1,126 @@ +// 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. + +use std::path::PathBuf; + +use ls_types::{DiagnosticSeverity, NumberOrString}; +use serde_json; +use span::compiler::DiagnosticSpan; +use span; +use actions::lsp_extensions::{RustDiagnostic, LabelledRange}; + +use lsp_data::ls_util; + +#[derive(Debug, Deserialize)] +struct CompilerMessageCode { + code: String +} + +#[derive(Debug, Deserialize)] +struct CompilerMessage { + message: String, + code: Option, + level: String, + spans: Vec, + children: Vec, +} + +#[derive(Debug)] +pub struct FileDiagnostic { + pub file_path: PathBuf, + pub diagnostic: RustDiagnostic, +} + +#[derive(Debug)] +pub enum ParseError { + JsonError(serde_json::Error), + NoSpans, +} + +impl From for ParseError { + fn from(error: serde_json::Error) -> Self { + ParseError::JsonError(error) + } +} + +pub fn parse(message: &str) -> Result { + let message = serde_json::from_str::(message)?; + + if message.spans.is_empty() { + return Err(ParseError::NoSpans); + } + + let message_text = compose_message(&message); + let primary = message.spans.iter() + .filter(|x| x.is_primary) + .collect::>()[0].clone(); + let primary_span = primary.rls_span().zero_indexed(); + let primary_range = ls_util::rls_to_range(primary_span.range); + + // build up the secondary spans + let secondary_labels: Vec = message.spans.iter() + .filter(|x| !x.is_primary) + .map(|x| { + let secondary_range = ls_util::rls_to_range(x.rls_span().zero_indexed().range); + + LabelledRange { + start: secondary_range.start, + end: secondary_range.end, + label: x.label.clone(), + } + }).collect(); + + + let diagnostic = RustDiagnostic { + range: LabelledRange { + start: primary_range.start, + end: primary_range.end, + label: primary.label.clone(), + }, + secondaryRanges: secondary_labels, + severity: Some(if message.level == "error" { + DiagnosticSeverity::Error + } else { + DiagnosticSeverity::Warning + }), + code: Some(NumberOrString::String(match message.code { + Some(c) => c.code.clone(), + None => String::new(), + })), + source: Some("rustc".into()), + message: message_text, + }; + + Ok(FileDiagnostic { + file_path: primary_span.file.clone(), + diagnostic: diagnostic + }) +} + +/// Builds a more sophisticated error message +fn compose_message(compiler_message: &CompilerMessage) -> String { + let mut message = compiler_message.message.clone(); + for sp in &compiler_message.spans { + if !sp.is_primary { + continue; + } + if let Some(ref label) = sp.label { + message.push_str("\n"); + message.push_str(label); + } + } + if !compiler_message.children.is_empty() { + message.push_str("\n"); + for child in &compiler_message.children { + message.push_str(&format!("\n{}: {}", child.level, child.message)); + } + } + message +} diff --git a/rls/src/actions/lsp_extensions.rs b/rls/src/actions/lsp_extensions.rs new file mode 100644 index 0000000000..4e8627ce92 --- /dev/null +++ b/rls/src/actions/lsp_extensions.rs @@ -0,0 +1,62 @@ +// 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. + +use url_serde; +use lsp_data::*; +use url::Url; + +#[derive(Debug, PartialEq, Deserialize, Serialize)] +pub struct PublishRustDiagnosticsParams { + /// The URI for which diagnostic information is reported. + #[serde(deserialize_with = "url_serde::deserialize", serialize_with = "url_serde::serialize")] + pub uri: Url, + + /// An array of diagnostic information items. + pub diagnostics: Vec, +} + +/// A range in a text document expressed as (zero-based) start and end positions. +/// A range is comparable to a selection in an editor. Therefore the end position is exclusive. +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct LabelledRange { + /// The range's start position. + pub start: Position, + /// The range's end position. + pub end: Position, + /// The optional label. + pub label: Option, +} + +/// Represents a diagnostic, such as a compiler error or warning. +/// Diagnostic objects are only valid in the scope of a resource. +#[allow(non_snake_case)] +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct RustDiagnostic { + /// The primary range at which the message applies. + pub range: LabelledRange, + + /// The secondary ranges that apply to the message + pub secondaryRanges: Vec, + + /// The diagnostic's severity. Can be omitted. If omitted it is up to the + /// client to interpret diagnostics as error, warning, info or hint. + pub severity: Option, + + /// The diagnostic's code. Can be omitted. + pub code: Option, + + /// A human-readable string describing the source of this + /// diagnostic, e.g. 'typescript' or 'super lint'. + pub source: Option, + + /// The diagnostic's message. + pub message: String, +} + diff --git a/rls/src/actions/mod.rs b/rls/src/actions/mod.rs new file mode 100644 index 0000000000..0a670e788b --- /dev/null +++ b/rls/src/actions/mod.rs @@ -0,0 +1,532 @@ +// 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. + +mod compiler_message_parsing; +mod lsp_extensions; + +use analysis::{AnalysisHost}; +use hyper::Url; +use vfs::{Vfs, Change}; +use racer; +use rustfmt::{Input as FmtInput, format_input}; +use rustfmt::config::{self, WriteMode}; +use serde_json; +use span; +use Span; + +use build::*; +use lsp_data::*; +use server::{ResponseData, Output}; + +use std::collections::HashMap; +use std::panic; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, Mutex}; +use std::thread; +use std::time::Duration; + +use self::lsp_extensions::{PublishRustDiagnosticsParams, RustDiagnostic}; +use self::compiler_message_parsing::{FileDiagnostic, ParseError}; + +type BuildResults = HashMap>; + +pub struct ActionHandler { + analysis: Arc, + vfs: Arc, + build_queue: Arc, + current_project: Mutex>, + previous_build_results: Mutex, +} + +impl ActionHandler { + pub fn new(analysis: Arc, + vfs: Arc, + build_queue: Arc) -> ActionHandler { + ActionHandler { + analysis: analysis, + vfs: vfs, + build_queue: build_queue, + current_project: Mutex::new(None), + previous_build_results: Mutex::new(HashMap::new()), + } + } + + pub fn init(&self, root_path: PathBuf, out: &Output) { + { + let mut results = self.previous_build_results.lock().unwrap(); + results.clear(); + } + { + let mut current_project = self.current_project.lock().unwrap(); + *current_project = Some(root_path.clone()); + } + self.build(&root_path, BuildPriority::Immediate, out); + } + + pub fn build(&self, project_path: &Path, priority: BuildPriority, out: &Output) { + fn clear_build_results(results: &mut BuildResults) { + // We must not clear the hashmap, just the values in each list. + // This allows us to save allocated before memory. + for v in &mut results.values_mut() { + v.clear(); + } + } + + fn parse_compiler_messages(messages: &[String], results: &mut BuildResults) { + for msg in messages { + match compiler_message_parsing::parse(msg) { + Ok(FileDiagnostic { file_path, diagnostic }) => { + results.entry(file_path).or_insert_with(Vec::new).push(diagnostic); + } + Err(ParseError::JsonError(e)) => { + debug!("build error {:?}", e); + debug!("from {}", msg); + } + Err(ParseError::NoSpans) => {} + } + } + } + + fn convert_build_results_to_notifications(build_results: &BuildResults, + project_path: &Path) + -> Vec> + { + let cwd = ::std::env::current_dir().unwrap(); + + build_results + .iter() + .map(|(path, diagnostics)| { + let method = "textDocument/publishDiagnostics".to_string(); + + let params = PublishRustDiagnosticsParams { + uri: Url::from_file_path(cwd.join(path)).unwrap(), + diagnostics: diagnostics.clone(), + }; + + NotificationMessage::new(method, params) + }) + .collect() + } + + // We use `rustDocument` document here since these notifications are + // custom to the RLS and not part of the LS protocol. + out.notify("rustDocument/diagnosticsBegin"); + + debug!("build {:?}", project_path); + let result = self.build_queue.request_build(project_path, priority); + match result { + BuildResult::Success(x, analysis) | BuildResult::Failure(x, analysis) => { + debug!("build - Success"); + + // These notifications will include empty sets of errors for files + // which had errors, but now don't. This instructs the IDE to clear + // errors for those files. + let notifications = { + let mut results = self.previous_build_results.lock().unwrap(); + clear_build_results(&mut results); + parse_compiler_messages(&x, &mut results); + convert_build_results_to_notifications(&results, project_path) + }; + + // TODO we don't send an OK notification if there were no errors + for notification in notifications { + // FIXME(43) factor out the notification mechanism. + let output = serde_json::to_string(¬ification).unwrap(); + out.response(output); + } + + trace!("reload analysis: {:?}", project_path); + let cwd = ::std::env::current_dir().unwrap(); + if let Some(analysis) = analysis { + self.analysis.reload_from_analysis(analysis, project_path, &cwd, false).unwrap(); + } else { + self.analysis.reload(project_path, &cwd, false).unwrap(); + } + + out.notify("rustDocument/diagnosticsEnd"); + } + BuildResult::Squashed => { + trace!("build - Squashed"); + out.notify("rustDocument/diagnosticsEnd"); + }, + BuildResult::Err => { + trace!("build - Error"); + out.notify("rustDocument/diagnosticsEnd"); + }, + } + } + + pub fn on_open(&self, open: DidOpenTextDocumentParams, out: &Output) { + let fname = parse_file_path(&open.text_document.uri).unwrap(); + self.vfs.set_file(fname.as_path(), &open.text_document.text); + + trace!("on_open: {:?}", fname); + + self.build_current_project(BuildPriority::Normal, out); + } + + pub fn on_change(&self, change: DidChangeTextDocumentParams, out: &Output) { + let fname = parse_file_path(&change.text_document.uri).unwrap(); + let changes: Vec = change.content_changes.iter().map(move |i| { + if let Some(range) = i.range { + let range = ls_util::range_to_rls(range); + Change::ReplaceText { + span: Span::from_range(range, fname.clone()), + text: i.text.clone() + } + } else { + Change::AddFile { + file: fname.clone(), + text: i.text.clone(), + } + } + }).collect(); + self.vfs.on_changes(&changes).unwrap(); + + trace!("on_change: {:?}", changes); + + self.build_current_project(BuildPriority::Normal, out); + } + + pub fn on_save(&self, save: DidSaveTextDocumentParams, out: &Output) { + let fname = parse_file_path(&save.text_document.uri).unwrap(); + self.vfs.file_saved(&fname).unwrap(); + self.build_current_project(BuildPriority::Immediate, out); + } + + fn build_current_project(&self, priority: BuildPriority, out: &Output) { + let current_project = { + let current_project = self.current_project.lock().unwrap(); + current_project.clone() + }; + match current_project { + Some(ref current_project) => self.build(current_project, priority, out), + None => debug!("build_current_project - no project path"), + } + } + + pub fn symbols(&self, id: usize, doc: DocumentSymbolParams, out: &Output) { + let t = thread::current(); + let analysis = self.analysis.clone(); + + let rustw_handle = thread::spawn(move || { + let file_name = parse_file_path(&doc.text_document.uri).unwrap(); + let symbols = analysis.symbols(&file_name).unwrap_or_else(|_| vec![]); + t.unpark(); + + symbols.into_iter().map(|s| { + SymbolInformation { + name: s.name, + kind: source_kind_from_def_kind(s.kind), + location: ls_util::rls_to_location(&s.span), + container_name: None // FIXME: more info could be added here + } + }).collect() + }); + + thread::park_timeout(Duration::from_millis(::COMPILER_TIMEOUT)); + + let result = rustw_handle.join().unwrap_or_else(|_| vec![]); + out.success(id, ResponseData::SymbolInfo(result)); + } + + pub fn complete(&self, id: usize, params: TextDocumentPositionParams, out: &Output) { + let result: Vec = panic::catch_unwind(move || { + let file_path = &parse_file_path(¶ms.text_document.uri).unwrap(); + + let cache = racer::FileCache::new(self.vfs.clone()); + let session = racer::Session::new(&cache); + + let location = pos_to_racer_location(params.position); + let results = racer::complete_from_file(file_path, location, &session); + + results.map(|comp| completion_item_from_racer_match(comp)).collect() + }).unwrap_or_else(|_| vec![]); + + out.success(id, ResponseData::CompletionItems(result)); + } + + pub fn rename(&self, id: usize, params: RenameParams, out: &Output) { + let t = thread::current(); + let span = self.convert_pos_to_span(¶ms.text_document, params.position); + let analysis = self.analysis.clone(); + + let rustw_handle = thread::spawn(move || { + let result = analysis.find_all_refs(&span, true); + t.unpark(); + + result + }); + + thread::park_timeout(Duration::from_millis(::COMPILER_TIMEOUT)); + + let result = rustw_handle.join().ok().and_then(|t| t.ok()).unwrap_or_else(Vec::new); + + let mut edits: HashMap> = HashMap::new(); + + for item in result.iter() { + let loc = ls_util::rls_to_location(item); + edits.entry(loc.uri).or_insert_with(Vec::new).push(TextEdit { + range: loc.range, + new_text: params.new_name.clone(), + }); + } + + out.success(id, ResponseData::WorkspaceEdit(WorkspaceEdit { changes: edits })); + } + + pub fn highlight(&self, id: usize, params: TextDocumentPositionParams, out: &Output) { + let t = thread::current(); + let span = self.convert_pos_to_span(¶ms.text_document, params.position); + let analysis = self.analysis.clone(); + + let handle = thread::spawn(move || { + let result = analysis.find_all_refs(&span, true); + t.unpark(); + + result + }); + + thread::park_timeout(Duration::from_millis(::COMPILER_TIMEOUT)); + + let result = handle.join().ok().and_then(|t| t.ok()).unwrap_or_else(Vec::new); + let refs: Vec<_> = result.iter().map(|span| DocumentHighlight { + range: ls_util::rls_to_range(span.range), + kind: Some(DocumentHighlightKind::Text), + }).collect(); + + out.success(id, ResponseData::Highlights(refs)); + } + + pub fn find_all_refs(&self, id: usize, params: ReferenceParams, out: &Output) { + let t = thread::current(); + let span = self.convert_pos_to_span(¶ms.text_document, params.position); + let analysis = self.analysis.clone(); + + let handle = thread::spawn(move || { + let result = analysis.find_all_refs(&span, params.context.include_declaration); + t.unpark(); + + result + }); + + thread::park_timeout(Duration::from_millis(::COMPILER_TIMEOUT)); + + let result = handle.join().ok().and_then(|t| t.ok()).unwrap_or_else(Vec::new); + let refs: Vec<_> = result.iter().map(|item| ls_util::rls_to_location(item)).collect(); + + out.success(id, ResponseData::Locations(refs)); + } + + pub fn goto_def(&self, id: usize, params: TextDocumentPositionParams, out: &Output) { + // Save-analysis thread. + let t = thread::current(); + let span = self.convert_pos_to_span(¶ms.text_document, params.position); + let analysis = self.analysis.clone(); + let vfs = self.vfs.clone(); + + let compiler_handle = thread::spawn(move || { + let result = analysis.goto_def(&span); + + t.unpark(); + + result + }); + + // Racer thread. + let racer_handle = thread::spawn(move || { + let file_path = &parse_file_path(¶ms.text_document.uri).unwrap(); + + let cache = racer::FileCache::new(vfs); + let session = racer::Session::new(&cache); + let location = pos_to_racer_location(params.position); + + racer::find_definition(file_path, location, &session) + .and_then(location_from_racer_match) + }); + + thread::park_timeout(Duration::from_millis(::COMPILER_TIMEOUT)); + + let compiler_result = compiler_handle.join(); + match compiler_result { + Ok(Ok(r)) => { + let result = vec![ls_util::rls_to_location(&r)]; + trace!("goto_def TO: {:?}", result); + out.success(id, ResponseData::Locations(result)); + } + _ => { + info!("goto_def - falling back to Racer"); + match racer_handle.join() { + Ok(Some(r)) => { + trace!("goto_def: {:?}", r); + out.success(id, ResponseData::Locations(vec![r])); + } + _ => { + debug!("Error in Racer"); + out.failure(id, "GotoDef failed to complete successfully"); + } + } + } + } + } + + pub fn hover(&self, id: usize, params: TextDocumentPositionParams, out: &Output) { + let t = thread::current(); + let span = self.convert_pos_to_span(¶ms.text_document, params.position); + + trace!("hover: {:?}", span); + + let analysis = self.analysis.clone(); + let rustw_handle = thread::spawn(move || { + let ty = analysis.show_type(&span).unwrap_or_else(|_| String::new()); + let docs = analysis.docs(&span).unwrap_or_else(|_| String::new()); + let doc_url = analysis.doc_url(&span).unwrap_or_else(|_| String::new()); + t.unpark(); + + let mut contents = vec![]; + if !docs.is_empty() { + contents.push(MarkedString::from_markdown(docs.into())); + } + if !doc_url.is_empty() { + contents.push(MarkedString::from_markdown(doc_url.into())); + } + if !ty.is_empty() { + contents.push(MarkedString::from_language_code("rust".into(), ty.into())); + } + Hover { + contents: contents, + range: None, // TODO: maybe add? + } + }); + + thread::park_timeout(Duration::from_millis(::COMPILER_TIMEOUT)); + + let result = rustw_handle.join(); + match result { + Ok(r) => { + out.success(id, ResponseData::HoverSuccess(r)); + } + Err(_) => { + out.failure(id, "Hover failed to complete successfully"); + } + } + } + + pub fn reformat(&self, id: usize, doc: TextDocumentIdentifier, out: &Output) { + trace!("Reformat: {} {:?}", id, doc); + + let path = &parse_file_path(&doc.uri).unwrap(); + let input = match self.vfs.load_file(path) { + Ok(s) => FmtInput::Text(s), + Err(e) => { + debug!("Reformat failed: {:?}", e); + out.failure(id, "Reformat failed to complete successfully"); + return; + } + }; + + let mut config = config::Config::default(); + config.skip_children = true; + config.write_mode = WriteMode::Plain; + + let mut buf = Vec::::new(); + match format_input(input, &config, Some(&mut buf)) { + Ok((summary, ..)) => { + // format_input returns Ok even if there are any errors, i.e., parsing errors. + if summary.has_no_errors() { + // Note that we don't need to keep the VFS up to date, the client + // echos back the change to us. + let range = ls_util::range_from_vfs_file(&self.vfs, path); + let text = String::from_utf8(buf).unwrap(); + let result = [TextEdit { + range: range, + new_text: text, + }]; + out.success(id, ResponseData::TextEdit(result)) + } else { + debug!("reformat: format_input failed: has errors, summary = {:?}", summary); + + out.failure(id, "Reformat failed to complete successfully") + } + } + Err(e) => { + debug!("Reformat failed: {:?}", e); + out.failure(id, "Reformat failed to complete successfully") + } + } + } + + fn convert_pos_to_span(&self, doc: &TextDocumentIdentifier, pos: Position) -> Span { + let fname = parse_file_path(&doc.uri).unwrap(); + trace!("convert_pos_to_span: {:?} {:?}", fname, pos); + + let pos = ls_util::position_to_rls(pos); + let line = self.vfs.load_line(&fname, pos.row).unwrap(); + trace!("line: `{}`", line); + + let start_pos = { + let mut col = 0; + for (i, c) in line.chars().enumerate() { + if !(c.is_alphanumeric() || c == '_') { + col = i + 1; + } + if i == pos.col.0 as usize { + break; + } + } + trace!("start: {}", col); + span::Position::new(pos.row, span::Column::new_zero_indexed(col as u32)) + }; + + let end_pos = { + let mut col = pos.col.0 as usize; + for c in line.chars().skip(col) { + if !(c.is_alphanumeric() || c == '_') { + break; + } + col += 1; + } + trace!("end: {}", col); + span::Position::new(pos.row, span::Column::new_zero_indexed(col as u32)) + }; + + Span::from_positions(start_pos, + end_pos, + fname.to_owned()) + } +} + +fn racer_coord(line: span::Row, + column: span::Column) + -> racer::Coordinate { + racer::Coordinate { + line: line.0 as usize, + column: column.0 as usize, + } +} + +fn from_racer_coord(coord: racer::Coordinate) -> (span::Row,span::Column) { + (span::Row::new_one_indexed(coord.line as u32), span::Column::new_zero_indexed(coord.column as u32)) +} + +fn pos_to_racer_location(pos: Position) -> racer::Location { + let pos = ls_util::position_to_rls(pos); + racer::Location::Coords(racer_coord(pos.row.one_indexed(), pos.col)) +} + +fn location_from_racer_match(mtch: racer::Match) -> Option { + let source_path = &mtch.filepath; + + mtch.coords.map(|coord| { + let (row, col) = from_racer_coord(coord); + let loc = span::Location::new(row.zero_indexed(), col, source_path); + ls_util::rls_location_to_location(&loc) + }) +} diff --git a/rls/src/build.rs b/rls/src/build.rs new file mode 100644 index 0000000000..4867276d6c --- /dev/null +++ b/rls/src/build.rs @@ -0,0 +1,726 @@ +// 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. + +extern crate getopts; +extern crate rustc; +extern crate rustc_driver; +extern crate rustc_errors as errors; +extern crate rustc_resolve; +extern crate rustc_save_analysis; +extern crate syntax; + +use cargo::core::{PackageId, MultiShell, Workspace}; +use cargo::ops::{compile_with_exec, Executor, Context, CompileOptions, CompileMode, CompileFilter}; +use cargo::util::{Config as CargoConfig, ProcessBuilder, ProcessError, homedir, ConfigValue}; + +use data::Analysis; +use vfs::Vfs; +use self::rustc::session::Session; +use self::rustc::session::config::{self, Input, ErrorOutputType}; +use self::rustc_driver::{RustcDefaultCalls, run_compiler, run, Compilation, CompilerCalls}; +use self::rustc_driver::driver::CompileController; +use self::rustc_save_analysis as save; +use self::rustc_save_analysis::CallbackHandler; +use self::syntax::ast; +use self::syntax::codemap::{FileLoader, RealFileLoader}; + +use config::Config; + +use std::collections::HashMap; +use std::env; +use std::ffi::OsString; +use std::fs::{read_dir, remove_file}; +use std::io::{self, Write}; +use std::mem; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::sync::{Arc, Mutex}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc::{channel, Sender}; +use std::thread; +use std::time::Duration; + + +/// Manages builds. +/// +/// The IDE will request builds quickly (possibly on every keystroke), there is +/// no point running every one. We also avoid running more than one build at once. +/// We cannot cancel builds. It might be worth running builds in parallel or +/// cancelling a started build. +/// +/// `BuildPriority::Immediate` builds are started straightaway. Normal builds are +/// started after a timeout. A new build request cancels any pending build requests. +/// +/// From the client's point of view, a build request is not guaranteed to cause +/// a build. However, a build is guaranteed to happen and that build will begin +/// after the build request is received (no guarantee on how long after), and +/// that build is guaranteed to have finished before the build reqest returns. +/// +/// There is no way for the client to specify that an individual request will +/// result in a build. However, you can tell from the result - if a build +/// was run, the build result will contain any errors or warnings and an indication +/// of success or failure. If the build was not run, the result indicates that +/// it was squashed. +pub struct BuildQueue { + build_dir: Mutex>, + cmd_line_args: Arc>>, + cmd_line_envs: Arc>>>, + // True if a build is running. + // Note I have been conservative with Ordering when accessing this atomic, + // we might be able to do better. + running: AtomicBool, + // A vec of channels to pending build threads. + pending: Mutex>>, + vfs: Arc, + config: Mutex, +} + +#[derive(Debug)] +pub enum BuildResult { + // Build was succesful, argument is warnings. + Success(Vec, Option), + // Build finished with errors, argument is errors and warnings. + Failure(Vec, Option), + // Build was coelesced with another build. + Squashed, + // There was an error attempting to build. + Err, +} + +/// Priority for a build request. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum BuildPriority { + /// Run this build as soon as possible (e.g., on save or explicit build request). + Immediate, + /// A regular build request (e.g., on a minor edit). + Normal, +} + +// Minimum time to wait before starting a `BuildPriority::Normal` build. +const WAIT_TO_BUILD: u64 = 500; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum Signal { + Build, + Skip, +} + +impl BuildQueue { + pub fn new(vfs: Arc) -> BuildQueue { + BuildQueue { + build_dir: Mutex::new(None), + cmd_line_args: Arc::new(Mutex::new(vec![])), + cmd_line_envs: Arc::new(Mutex::new(HashMap::new())), + running: AtomicBool::new(false), + pending: Mutex::new(vec![]), + vfs: vfs, + config: Mutex::new(Config::default()), + } + } + + pub fn request_build(&self, build_dir: &Path, priority: BuildPriority) -> BuildResult { + // println!("request_build, {:?} {:?}", build_dir, priority); + + // If there is a change in the project directory, then we can forget any + // pending build and start straight with this new build. + { + let mut prev_build_dir = self.build_dir.lock().unwrap(); + + if prev_build_dir.as_ref().map_or(true, |dir| dir != build_dir) { + *prev_build_dir = Some(build_dir.to_owned()); + self.cancel_pending(); + + let mut config = self.config.lock().unwrap(); + *config = Config::from_path(build_dir); + + let mut cmd_line_args = self.cmd_line_args.lock().unwrap(); + *cmd_line_args = vec![]; + } + } + + self.cancel_pending(); + + match priority { + BuildPriority::Immediate => { + // There is a build running, wait for it to finish, then run. + if self.running.load(Ordering::SeqCst) { + let (tx, rx) = channel(); + self.pending.lock().unwrap().push(tx); + // Blocks. + // println!("blocked on build"); + let signal = rx.recv().unwrap_or(Signal::Build); + if signal == Signal::Skip { + return BuildResult::Squashed; + } + } + } + BuildPriority::Normal => { + let (tx, rx) = channel(); + self.pending.lock().unwrap().push(tx); + thread::sleep(Duration::from_millis(WAIT_TO_BUILD)); + + if self.running.load(Ordering::SeqCst) { + // Blocks + // println!("blocked until wake up"); + let signal = rx.recv().unwrap_or(Signal::Build); + if signal == Signal::Skip { + return BuildResult::Squashed; + } + } else if rx.try_recv().unwrap_or(Signal::Build) == Signal::Skip { + // Doesn't block. + return BuildResult::Squashed; + } + } + } + + // If another build has started already, we don't need to build + // ourselves (it must have arrived after this request; so we don't add + // to the pending list). But we do need to wait for that build to + // finish. + if self.running.swap(true, Ordering::SeqCst) { + let mut wait = 100; + while self.running.load(Ordering::SeqCst) && wait < 50000 { + // println!("loop of death"); + thread::sleep(Duration::from_millis(wait)); + wait *= 2; + } + return BuildResult::Squashed; + } + + let result = self.build(); + self.running.store(false, Ordering::SeqCst); + + // If there is a pending build, run it now. + let mut pending = self.pending.lock().unwrap(); + let pending = mem::replace(&mut *pending, vec![]); + if !pending.is_empty() { + // Kick off one build, then skip the rest. + let mut pending = pending.iter(); + while let Some(next) = pending.next() { + if next.send(Signal::Build).is_ok() { + break; + } + } + for t in pending { + let _ = t.send(Signal::Skip); + } + } + + result + } + + // Cancels all pending builds without running any of them. + fn cancel_pending(&self) { + let mut pending = self.pending.lock().unwrap(); + let pending = mem::replace(&mut *pending, vec![]); + for t in pending { + let _ = t.send(Signal::Skip); + } + } + + // Build the project. + fn build(&self) -> BuildResult { + // When we change build directory (presumably because the IDE is + // changing project), we must do a cargo build of the whole project. + // Otherwise we just use rustc directly. + // + // The 'full cargo build' is a `cargo check` customised and run + // in-process. Cargo will shell out to call rustc (this means the + // the compiler available at runtime must match the compiler linked to + // the RLS). All but the last crate are built as normal, we intercept + // the call to the last crate and do our own rustc build. We cache the + // command line args and environment so we can avoid running Cargo in + // the future. + // + // Our 'short' rustc build runs rustc directly and in-process (we must + // do this so we can load changed code from the VFS, rather than from + // disk). We get the data we need by building with `-Zsave-analysis`. + + let needs_to_run_cargo = { + let cmd_line_args = self.cmd_line_args.lock().unwrap(); + cmd_line_args.is_empty() + }; + + let build_dir = &self.build_dir.lock().unwrap(); + let build_dir = build_dir.as_ref().unwrap(); + + if needs_to_run_cargo { + if let BuildResult::Err = self.cargo(build_dir.clone()) { + return BuildResult::Err; + } + } + + let cmd_line_args = self.cmd_line_args.lock().unwrap(); + assert!(!cmd_line_args.is_empty()); + let cmd_line_envs = self.cmd_line_envs.lock().unwrap(); + self.rustc(&*cmd_line_args, &*cmd_line_envs, build_dir) + } + + // Runs an in-process instance of Cargo. + fn cargo(&self, build_dir: PathBuf) -> BuildResult { + struct RlsExecutor { + cmd_line_args: Arc>>, + cmd_line_envs: Arc>>>, + cur_package_id: Mutex>, + config: Config, + } + + impl RlsExecutor { + fn new(cmd_line_args: Arc>>, + cmd_line_envs: Arc>>>, + config: Config) -> RlsExecutor { + RlsExecutor { + cmd_line_args: cmd_line_args, + cmd_line_envs: cmd_line_envs, + cur_package_id: Mutex::new(None), + config: config, + } + } + } + + impl Executor for RlsExecutor { + fn init(&self, cx: &Context) { + let mut cur_package_id = self.cur_package_id.lock().unwrap(); + *cur_package_id = Some(cx.ws + .current_opt() + .expect("No current package in Cargo") + .package_id() + .clone()); + } + + fn exec(&self, cmd: ProcessBuilder, id: &PackageId) -> Result<(), ProcessError> { + // Delete any stale data. We try and remove any json files with + // the same crate name as Cargo would emit. This includes files + // with the same crate name but different hashes, e.g., those + // made with a different compiler. + let args = cmd.get_args(); + let crate_name = parse_arg(args, "--crate-name").expect("no crate-name in rustc command line"); + let out_dir = parse_arg(args, "--out-dir").expect("no out-dir in rustc command line"); + let analysis_dir = Path::new(&out_dir).join("save-analysis"); + if let Ok(dir_contents) = read_dir(&analysis_dir) { + for entry in dir_contents { + let entry = entry.expect("unexpected error reading save-analysis directory"); + let name = entry.file_name(); + let name = name.to_str().unwrap(); + if name.starts_with(&crate_name) && name.ends_with(".json") { + debug!("removing: `{:?}`", name); + remove_file(entry.path()).expect("could not remove file"); + } + } + } + + let is_primary_crate = { + let cur_package_id = self.cur_package_id.lock().unwrap(); + id == cur_package_id.as_ref().expect("Executor has not been initialised") + }; + if is_primary_crate { + let mut args: Vec<_> = + cmd.get_args().iter().map(|a| a.clone().into_string().unwrap()).collect(); + + // We end up taking this code path for build scripts, we don't + // want to do that, so we check here if the crate is actually + // being linked (c.f., emit=metadata) and if just call the + // usual rustc. This is clearly a bit fragile (if the emit + // string changes, we get screwed). + if args.contains(&"--emit=dep-info,link".to_owned()) { + trace!("rustc not intercepted (link)"); + return cmd.exec(); + } + + trace!("intercepted rustc, args: {:?}", args); + + // FIXME here and below should check $RUSTC before using rustc. + { + // Cargo is going to expect to get dep-info for this crate, so we shell out + // to rustc to get that. This is not really ideal, because we are going to + // compute this info anyway when we run rustc ourselves, but we don't do + // that before we return to Cargo. + // FIXME Don't do this. Instead either persuade Cargo that it doesn't need + // this info at all, or start our build here rather than on another thread + // so the dep-info is ready by the time we return from this callback. + let mut cmd_dep_info = Command::new("rustc"); + for a in &args { + if a.starts_with("--emit") { + cmd_dep_info.arg("--emit=dep-info"); + } else { + cmd_dep_info.arg(a); + } + } + if let Some(cwd) = cmd.get_cwd() { + cmd_dep_info.current_dir(cwd); + } + cmd_dep_info.status().expect("Couldn't execute rustc"); + } + + args.insert(0, "rustc".to_owned()); + if self.config.cfg_test { + args.push("--test".to_owned()); + } + if self.config.sysroot.is_empty() { + args.push("--sysroot".to_owned()); + let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); + let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); + let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) { + format!("{}/toolchains/{}", home, toolchain) + } else { + option_env!("SYSROOT") + .map(|s| s.to_owned()) + .or_else(|| Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .ok() + .and_then(|out| String::from_utf8(out.stdout).ok()) + .map(|s| s.trim().to_owned())) + .expect("need to specify SYSROOT env var, \ + or use rustup or multirust") + }; + args.push(sys_root.to_owned()); + } + + let envs = cmd.get_envs(); + trace!("envs: {:?}", envs); + + { + let mut queue_args = self.cmd_line_args.lock().unwrap(); + *queue_args = args.clone(); + } + { + let mut queue_envs = self.cmd_line_envs.lock().unwrap(); + *queue_envs = envs.clone(); + } + + Ok(()) + } else { + trace!("rustc not intercepted"); + cmd.exec() + } + } + } + + let rls_config = { + let rls_config = self.config.lock().unwrap(); + rls_config.clone() + }; + + trace!("cargo - `{:?}`", build_dir); + let exec = RlsExecutor::new(self.cmd_line_args.clone(), + self.cmd_line_envs.clone(), + rls_config.clone()); + + let out = Arc::new(Mutex::new(vec![])); + let err = Arc::new(Mutex::new(vec![])); + let out_clone = out.clone(); + let err_clone = err.clone(); + + // Cargo may or may not spawn threads to run the various builds, since + // we may be in separate threads we need to block and wait our thread. + // However, if Cargo doesn't run a separate thread, then we'll just wait + // forever. Therefore, we spawn an extra thread here to be safe. + let handle = thread::spawn(move || { + let hardcoded = "-Zunstable-options -Zsave-analysis --error-format=json \ + -Zcontinue-parse-after-error"; + if rls_config.sysroot.is_empty() { + env::set_var("RUSTFLAGS", hardcoded); + } else { + env::set_var("RUSTFLAGS", &format!("--sysroot {} {}", rls_config.sysroot, hardcoded)); + } + + let shell = MultiShell::from_write(Box::new(BufWriter(out.clone())), + Box::new(BufWriter(err.clone()))); + let config = make_cargo_config(&build_dir, shell); + let mut manifest_path = build_dir.clone(); + manifest_path.push("Cargo.toml"); + trace!("manifest_path: {:?}", manifest_path); + let ws = Workspace::new(&manifest_path, &config).expect("could not create cargo workspace"); + + let mut opts = CompileOptions::default(&config, CompileMode::Check); + if rls_config.build_lib { + opts.filter = CompileFilter::new(true, &[], &[], &[], &[]); + } + compile_with_exec(&ws, &opts, Arc::new(exec)).expect("could not run cargo"); + }); + + match handle.join() { + Ok(_) => BuildResult::Success(vec![], None), + Err(_) => { + info!("cargo stdout {}", String::from_utf8(out_clone.lock().unwrap().to_owned()).unwrap()); + info!("cargo stderr {}", String::from_utf8(err_clone.lock().unwrap().to_owned()).unwrap()); + BuildResult::Err + } + } + } + + // Runs a single instance of rustc. Runs in-process. + fn rustc(&self, args: &[String], envs: &HashMap>, build_dir: &Path) -> BuildResult { + trace!("rustc - args: `{:?}`, envs: {:?}, build dir: {:?}", args, envs, build_dir); + + let changed = self.vfs.get_cached_files(); + + let _restore_env = Environment::push(envs); + let buf = Arc::new(Mutex::new(vec![])); + let err_buf = buf.clone(); + let args = args.to_owned(); + + let analysis = Arc::new(Mutex::new(None)); + + let mut controller = RlsRustcCalls::new(analysis.clone()); + + let exit_code = ::std::panic::catch_unwind(|| { + run(move || { + // Replace stderr so we catch most errors. + run_compiler(&args, + &mut controller, + Some(Box::new(ReplacedFileLoader::new(changed))), + Some(Box::new(BufWriter(buf)))) + }) + }); + + // FIXME(#25) given that we are running the compiler directly, there is no need + // to serialise either the error messages or save-analysis - we should pass + // them both in memory, without using save-analysis. + let stderr_json_msg = convert_message_to_json_strings(Arc::try_unwrap(err_buf) + .unwrap() + .into_inner() + .unwrap()); + + return match exit_code { + Ok(0) => BuildResult::Success(stderr_json_msg, analysis.lock().unwrap().clone()), + _ => BuildResult::Failure(stderr_json_msg, analysis.lock().unwrap().clone()), + }; + + // Our compiler controller. We mostly delegate to the default rustc + // controller, but use our own callback for save-analysis. + #[derive(Clone)] + struct RlsRustcCalls { + default_calls: RustcDefaultCalls, + analysis: Arc>>, + } + + impl RlsRustcCalls { + fn new(analysis: Arc>>) -> RlsRustcCalls { + RlsRustcCalls { + default_calls: RustcDefaultCalls, + analysis: analysis, + } + } + } + + impl<'a> CompilerCalls<'a> for RlsRustcCalls { + fn early_callback(&mut self, + matches: &getopts::Matches, + sopts: &config::Options, + cfg: &ast::CrateConfig, + descriptions: &errors::registry::Registry, + output: ErrorOutputType) + -> Compilation { + self.default_calls.early_callback(matches, sopts, cfg, descriptions, output) + } + + fn no_input(&mut self, + matches: &getopts::Matches, + sopts: &config::Options, + cfg: &ast::CrateConfig, + odir: &Option, + ofile: &Option, + descriptions: &errors::registry::Registry) + -> Option<(Input, Option)> { + self.default_calls.no_input(matches, sopts, cfg, odir, ofile, descriptions) + } + + fn late_callback(&mut self, + matches: &getopts::Matches, + sess: &Session, + input: &Input, + odir: &Option, + ofile: &Option) + -> Compilation { + self.default_calls.late_callback(matches, sess, input, odir, ofile) + } + + fn build_controller(&mut self, + sess: &Session, + matches: &getopts::Matches) + -> CompileController<'a> { + let mut result = self.default_calls.build_controller(sess, matches); + let analysis = self.analysis.clone(); + + result.after_analysis.callback = Box::new(move |state| { + save::process_crate(state.tcx.unwrap(), + state.expanded_crate.unwrap(), + state.analysis.unwrap(), + state.crate_name.unwrap(), + CallbackHandler { callback: &mut |a| { + let mut analysis = analysis.lock().unwrap(); + *analysis = Some(unsafe { ::std::mem::transmute(a.clone()) } ); + } }); + }); + result.after_analysis.run_callback_on_error = true; + result.make_glob_map = rustc_resolve::MakeGlobMap::Yes; + + result + } + } + } +} + +fn make_cargo_config(build_dir: &Path, shell: MultiShell) -> CargoConfig { + let config = CargoConfig::new(shell, + // This is Cargo's cwd. We are using the actual cwd, but perhaps + // we should use build_dir or something else? + env::current_dir().unwrap(), + homedir(&build_dir).unwrap()); + + // Cargo is expecting the config to come from a config file and keeps + // track of the path to that file. We'll make one up, it shouldn't be + // used for much. Cargo does use it for finding a root path. Since + // we pass an absolute path for the build directory, that doesn't + // matter too much. However, Cargo still takes the grandparent of this + // path, so we need to have at least two path elements. + let config_path = build_dir.join("config").join("rls-config.toml"); + + let mut config_value_map = config.load_values().unwrap(); + { + let build_value = config_value_map.entry("build".to_owned()).or_insert(ConfigValue::Table(HashMap::new(), config_path.clone())); + + let target_dir = build_dir.join("target").join("rls").to_str().unwrap().to_owned(); + let td_value = ConfigValue::String(target_dir, config_path); + if let &mut ConfigValue::Table(ref mut build_table, _) = build_value { + build_table.insert("target-dir".to_owned(), td_value); + } else { + unreachable!(); + } + } + + config.set_values(config_value_map).unwrap(); + config +} + +fn parse_arg(args: &[OsString], arg: &str) -> Option { + for (i, a) in args.iter().enumerate() { + if a == arg { + return Some(args[i + 1].clone().into_string().unwrap()); + } + } + None +} + +// A threadsafe buffer for writing. +struct BufWriter(Arc>>); + +impl Write for BufWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.lock().unwrap().write(buf) + } + fn flush(&mut self) -> io::Result<()> { + self.0.lock().unwrap().flush() + } +} + +// An RAII helper to set and reset the current working directory and env vars. +struct Environment { + old_vars: HashMap>, +} + +impl Environment { + fn push(envs: &HashMap>) -> Environment { + let mut result = Environment { + old_vars: HashMap::new(), + }; + + for (k, v) in envs { + result.old_vars.insert(k.to_owned(), env::var_os(k)); + match *v { + Some(ref v) => env::set_var(k, v), + None => env::remove_var(k), + } + } + result + } +} + +impl Drop for Environment { + fn drop(&mut self) { + for (k, v) in &self.old_vars { + match *v { + Some(ref v) => env::set_var(k, v), + None => env::remove_var(k), + } + } + } +} + +fn convert_message_to_json_strings(input: Vec) -> Vec { + let mut output = vec![]; + + // FIXME: this is *so gross* Trying to work around cargo not supporting json messages + let it = input.into_iter(); + + let mut read_iter = it.skip_while(|&x| x != b'{'); + + let mut _msg = String::new(); + loop { + match read_iter.next() { + Some(b'\n') => { + output.push(_msg); + _msg = String::new(); + while let Some(res) = read_iter.next() { + if res == b'{' { + _msg.push('{'); + break; + } + } + } + Some(x) => { + _msg.push(x as char); + } + None => { + break; + } + } + } + + output +} + +/// Tries to read a file from a list of replacements, and if the file is not +/// there, then reads it from disk, by delegating to `RealFileLoader`. +pub struct ReplacedFileLoader { + replacements: HashMap, + real_file_loader: RealFileLoader, +} + +impl ReplacedFileLoader { + pub fn new(replacements: HashMap) -> ReplacedFileLoader { + ReplacedFileLoader { + replacements: replacements, + real_file_loader: RealFileLoader, + } + } +} + +impl FileLoader for ReplacedFileLoader { + fn file_exists(&self, path: &Path) -> bool { + self.real_file_loader.file_exists(path) + } + + fn abs_path(&self, path: &Path) -> Option { + self.real_file_loader.abs_path(path) + } + + fn read_file(&self, path: &Path) -> io::Result { + if let Some(abs_path) = self.abs_path(path) { + if self.replacements.contains_key(&abs_path) { + return Ok(self.replacements[&abs_path].clone()); + } + } + self.real_file_loader.read_file(path) + } +} diff --git a/rls/src/config.rs b/rls/src/config.rs new file mode 100644 index 0000000000..2831c9e32f --- /dev/null +++ b/rls/src/config.rs @@ -0,0 +1,199 @@ +// 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. + +use toml; + +use std::fs::File; +use std::io::Read; +use std::path::Path; + +macro_rules! impl_enum_decodable { + ( $e:ident, $( $x:ident ),* ) => { + impl ::serde::Deserialize for $e { + fn decode(d: &mut D) -> Result { + use std::ascii::AsciiExt; + let s = try!(d.read_str()); + $( + if stringify!($x).eq_ignore_ascii_case(&s) { + return Ok($e::$x); + } + )* + Err(d.error("Bad variant")) + } + } + + impl ::std::str::FromStr for $e { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + use std::ascii::AsciiExt; + $( + if stringify!($x).eq_ignore_ascii_case(s) { + return Ok($e::$x); + } + )* + Err("Bad variant") + } + } + + impl ::config::ConfigType for $e { + fn get_variant_names() -> String { + let mut variants = Vec::new(); + $( + variants.push(stringify!($x)); + )* + format!("[{}]", variants.join("|")) + } + } + }; +} + +macro_rules! configuration_option_enum { + ($e:ident: $( $x:ident ),+ $(,)*) => { + #[derive(Copy, Clone, Eq, PartialEq, Debug)] + pub enum $e { + $( $x ),+ + } + + impl_enum_decodable!($e, $( $x ),+); + } +} + +// This trait and the following impl blocks are there so that we an use +// UCFS inside the get_docs() function on types for configs. +pub trait ConfigType { + fn get_variant_names() -> String; +} + +impl ConfigType for bool { + fn get_variant_names() -> String { + String::from("") + } +} + +impl ConfigType for usize { + fn get_variant_names() -> String { + String::from("") + } +} + +impl ConfigType for String { + fn get_variant_names() -> String { + String::from("") + } +} + +macro_rules! create_config { + ($($i:ident: $ty:ty, $def:expr, $unstable:expr, $( $dstring:expr ),+ );+ $(;)*) => ( + #[derive(RustcDecodable, Clone)] + pub struct Config { + $(pub $i: $ty),+ + } + + // Just like the Config struct but with each property wrapped + // as Option. This is used to parse a rustfmt.toml that doesn't + // specity all properties of `Config`. + // We first parse into `ParsedConfig`, then create a default `Config` + // and overwrite the properties with corresponding values from `ParsedConfig` + #[derive(RustcDecodable, Clone, Deserialize)] + pub struct ParsedConfig { + $(pub $i: Option<$ty>),+ + } + + impl Config { + + fn fill_from_parsed_config(mut self, parsed: ParsedConfig) -> Config { + $( + if let Some(val) = parsed.$i { + self.$i = val; + // TODO error out if unstable + } + )+ + self + } + + pub fn from_toml(toml: &str) -> Config { + let parsed_config: ParsedConfig = match toml::from_str(toml) { + Ok(decoded) => decoded, + Err(e) => { + debug!("Decoding config file failed."); + debug!("Error: {}", e); + debug!("Config:\n{}", toml); + let parsed: toml::Value = toml.parse().expect("Could not parse TOML"); + debug!("\n\nParsed:\n{:?}", parsed); + panic!(); + } + }; + Config::default().fill_from_parsed_config(parsed_config) + } + + #[allow(dead_code)] + pub fn print_docs() { + use std::cmp; + + let max = 0; + $( let max = cmp::max(max, stringify!($i).len()+1); )+ + let mut space_str = String::with_capacity(max); + for _ in 0..max { + space_str.push(' '); + } + println!("Configuration Options:"); + $( + if !$unstable { + let name_raw = stringify!($i); + let mut name_out = String::with_capacity(max); + for _ in name_raw.len()..max-1 { + name_out.push(' ') + } + name_out.push_str(name_raw); + name_out.push(' '); + println!("{}{} Default: {:?}", + name_out, + <$ty>::get_variant_names(), + $def); + $( + println!("{}{}", space_str, $dstring); + )+ + println!(""); + } + )+ + } + + /// Attempt to read a confid from rls.toml in path, failing that use defaults. + pub fn from_path(path: &Path) -> Config { + let config_path = path.to_owned().join("rls.toml"); + let config_file = File::open(config_path); + let mut toml = String::new(); + if let Ok(mut f) = config_file { + f.read_to_string(&mut toml).unwrap(); + } + Config::from_toml(&toml) + } + } + + // Template for the default configuration + impl Default for Config { + fn default() -> Config { + Config { + $( + $i: $def, + )+ + } + } + } + ) +} + +create_config! { + sysroot: String, String::new(), false, "--sysroot"; + build_lib: bool, false, false, "cargo check --lib"; + cfg_test: bool, true, false, "build cfg(test) code"; + unstable_features: bool, false, false, "enable unstable features"; +} diff --git a/rls/src/lsp_data.rs b/rls/src/lsp_data.rs new file mode 100644 index 0000000000..3194175cab --- /dev/null +++ b/rls/src/lsp_data.rs @@ -0,0 +1,179 @@ +// 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. + +use std::fmt::Debug; +use std::path::PathBuf; +use std::error::Error; + +use analysis::raw; +use hyper::Url; +use serde::Serialize; +use span; +use racer; + +pub use ls_types::*; + +macro_rules! impl_file_name { + ($ty_name: ty) => { + impl $ty_name { + pub fn file_name(&self) -> PathBuf { + uri_string_to_file_name(&self.uri) + } + } + } +} + +pub fn parse_file_path(uri: &Url) -> Result> { + if uri.scheme() != "file" { + Err("URI scheme is not `file`".into()) + } else { + uri.to_file_path().map_err(|_err| "Invalid file path in URI".into()) + } +} + + +pub mod ls_util { + use super::*; + use Span; + + use std::path::Path; + + use hyper::Url; + use vfs::Vfs; + + pub fn range_to_rls(r: Range) -> span::Range { + span::Range::from_positions(position_to_rls(r.start), position_to_rls(r.end)) + } + + pub fn position_to_rls(p: Position) -> span::Position { + span::Position::new(span::Row::new_zero_indexed(p.line as u32), + span::Column::new_zero_indexed(p.character as u32)) + } + + // An RLS span has the same info as an LSP Location + pub fn rls_to_location(span: &Span) -> Location { + Location { + uri: Url::from_file_path(&span.file).unwrap(), + range: rls_to_range(span.range), + } + } + + pub fn rls_location_to_location(l: &span::Location) -> Location { + Location { + uri: Url::from_file_path(&l.file).unwrap(), + range: rls_to_range(span::Range::from_positions(l.position, l.position)), + } + } + + pub fn rls_to_range(r: span::Range) -> Range { + Range { + start: rls_to_position(r.start()), + end: rls_to_position(r.end()), + } + } + + pub fn rls_to_position(p: span::Position) -> Position { + Position { + line: p.row.0 as u64, + character: p.col.0 as u64, + } + } + + /// Creates a `Range` spanning the whole file as currently known by `Vfs` + /// + /// Panics if `Vfs` cannot load the file. + pub fn range_from_vfs_file(vfs: &Vfs, fname: &Path) -> Range { + let content = vfs.load_file(fname).unwrap(); + if content.is_empty() { + Range {start: Position::new(0, 0), end: Position::new(0, 0)} + } else { + // range is zero-based and the end position is exclusive + Range { + start: Position::new(0, 0), + end: Position::new(content.lines().count() as u64 - 1, + content.lines().last().expect("String is not empty.").chars().count() as u64) + } + } + } +} + +pub fn source_kind_from_def_kind(k: raw::DefKind) -> SymbolKind { + match k { + raw::DefKind::Enum => SymbolKind::Enum, + raw::DefKind::Tuple => SymbolKind::Array, + raw::DefKind::Struct => SymbolKind::Class, + raw::DefKind::Union => SymbolKind::Class, + raw::DefKind::Trait => SymbolKind::Interface, + raw::DefKind::Function | + raw::DefKind::Method | + raw::DefKind::Macro => SymbolKind::Function, + raw::DefKind::Mod => SymbolKind::Module, + raw::DefKind::Type => SymbolKind::Interface, + raw::DefKind::Local | + raw::DefKind::Static | + raw::DefKind::Const | + raw::DefKind::Field => SymbolKind::Variable, + } +} + +pub fn completion_kind_from_match_type(m : racer::MatchType) -> CompletionItemKind { + match m { + racer::MatchType::Crate | + racer::MatchType::Module => CompletionItemKind::Module, + racer::MatchType::Struct => CompletionItemKind::Class, + racer::MatchType::Enum => CompletionItemKind::Enum, + racer::MatchType::StructField | + racer::MatchType::EnumVariant => CompletionItemKind::Field, + racer::MatchType::Macro | + racer::MatchType::Function | + racer::MatchType::FnArg | + racer::MatchType::Impl => CompletionItemKind::Function, + racer::MatchType::Type | + racer::MatchType::Trait | + racer::MatchType::TraitImpl => CompletionItemKind::Interface, + racer::MatchType::Let | + racer::MatchType::IfLet | + racer::MatchType::WhileLet | + racer::MatchType::For | + racer::MatchType::MatchArm | + racer::MatchType::Const | + racer::MatchType::Static => CompletionItemKind::Variable, + racer::MatchType::Builtin => CompletionItemKind::Keyword, + } +} + +pub fn completion_item_from_racer_match(m : racer::Match) -> CompletionItem { + let mut item = CompletionItem::new_simple(m.matchstr.clone(), m.contextstr.clone()); + item.kind = Some(completion_kind_from_match_type(m.mtype)); + + item +} + +/* ----------------- JSON-RPC protocol types ----------------- */ + +/// An event-like (no response needed) notification message. +#[derive(Debug, Serialize)] +pub struct NotificationMessage + where T: Debug + Serialize +{ + jsonrpc: &'static str, + pub method: String, + pub params: T, +} + +impl NotificationMessage where T: Debug + Serialize { + pub fn new(method: String, params: T) -> Self { + NotificationMessage { + jsonrpc: "2.0", + method: method, + params: params + } + } +} diff --git a/rls/src/main.rs b/rls/src/main.rs new file mode 100644 index 0000000000..eaa9a526d1 --- /dev/null +++ b/rls/src/main.rs @@ -0,0 +1,60 @@ +// 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. + +#![feature(rustc_private)] + +extern crate cargo; +#[macro_use] +extern crate derive_new; +extern crate env_logger; +extern crate hyper; +extern crate languageserver_types as ls_types; +#[macro_use] +extern crate log; +extern crate racer; +extern crate rls_analysis as analysis; +extern crate rls_vfs as vfs; +extern crate rls_span as span; +extern crate rls_data as data; +extern crate rustc_serialize; +extern crate rustfmt; +extern crate serde; +#[macro_use] +extern crate serde_derive; +extern crate serde_json; +extern crate toml; +extern crate url; +extern crate url_serde; + +use std::sync::Arc; + +mod build; +mod server; +mod actions; +mod lsp_data; +mod config; + +#[cfg(test)] +mod test; + +// Timeout = 1.5s (totally arbitrary). +const COMPILER_TIMEOUT: u64 = 1500; + +type Span = span::Span; + +pub fn main() { + env_logger::init().unwrap(); + + let analysis = Arc::new(analysis::AnalysisHost::new(analysis::Target::Debug)); + let vfs = Arc::new(vfs::Vfs::new()); + let build_queue = Arc::new(build::BuildQueue::new(vfs.clone())); + + server::run_server(analysis, vfs, build_queue); +} diff --git a/rls/src/server.rs b/rls/src/server.rs new file mode 100644 index 0000000000..e3a75c821e --- /dev/null +++ b/rls/src/server.rs @@ -0,0 +1,515 @@ +// 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. + +use analysis::AnalysisHost; +use vfs::Vfs; +use serde_json; + +use build::*; +use lsp_data::*; +use actions::ActionHandler; + +use std::fmt; +use std::io::{self, Read, Write, ErrorKind}; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; +use std::path::PathBuf; + +use config::Config; + +#[derive(Debug, Serialize)] +pub struct Ack {} + +#[derive(Debug, new)] +struct ParseError { + kind: ErrorKind, + message: &'static str, + id: Option, +} + +#[derive(Debug)] +enum ServerMessage { + Request(Request), + Notification(Notification) +} + +#[derive(Debug)] +struct Request { + id: usize, + method: Method +} + +#[derive(Debug)] +enum Notification { + Exit, + CancelRequest(CancelParams), + Change(DidChangeTextDocumentParams), + Open(DidOpenTextDocumentParams), + Save(DidSaveTextDocumentParams), +} + +/// Creates an public enum whose variants all contain a single serializable payload +/// with an automatic json to_string implementation +macro_rules! serializable_enum { + ($enum_name:ident, $($variant_name:ident($variant_type:ty)),*) => ( + + pub enum $enum_name { + $( + $variant_name($variant_type), + )* + } + + impl fmt::Display for $enum_name { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + let value = match *self { + $( + $enum_name::$variant_name(ref value) => serde_json::to_string(value), + )* + }.unwrap(); + + write!(f, "{}", value) + } + } + ) +} + +serializable_enum!(ResponseData, + Init(InitializeResult), + SymbolInfo(Vec), + CompletionItems(Vec), + WorkspaceEdit(WorkspaceEdit), + TextEdit([TextEdit; 1]), + Locations(Vec), + Highlights(Vec), + HoverSuccess(Hover), + Ack(Ack) +); + +// Generates the Method enum and parse_message function. +macro_rules! messages { + ( + methods { + // $method_arg is really a 0-1 repetition + $($method_str: pat => $method_name: ident $(($method_arg: ty))*;)* + } + notifications { + $($notif_str: pat => $notif_name: ident $(($notif_arg: ty))*;)* + } + $($other_str: pat => $other_expr: expr;)* + ) => { + #[derive(Debug)] + enum Method { + $($method_name$(($method_arg))*,)* + } + fn parse_message(input: &str) -> Result { + let ls_command: serde_json::Value = serde_json::from_str(input).unwrap(); + + let params = ls_command.get("params"); + + macro_rules! params_as { + ($ty: ty) => ({ + let method: $ty = + serde_json::from_value(params.unwrap().to_owned()).unwrap(); + method + }); + } + macro_rules! id { + () => ((ls_command.get("id").map(|id| id.as_u64().unwrap() as usize))); + } + + if let Some(v) = ls_command.get("method") { + if let Some(name) = v.as_str() { + match name { + $( + $method_str => { + let id = ls_command.get("id").unwrap().as_u64().unwrap() as usize; + Ok(ServerMessage::Request(Request{id: id, method: Method::$method_name$((params_as!($method_arg)))* })) + } + )* + $( + $notif_str => { + Ok(ServerMessage::Notification(Notification::$notif_name$((params_as!($notif_arg)))*)) + } + )* + $( + $other_str => $other_expr, + )* + } + } else { + Err(ParseError::new(ErrorKind::InvalidData, "Method is not a string", id!())) + } + } else { + Err(ParseError::new(ErrorKind::InvalidData, "Method not found", id!())) + } + } + }; +} + +messages! { + methods { + "shutdown" => Shutdown; + "initialize" => Initialize(InitializeParams); + "textDocument/hover" => Hover(TextDocumentPositionParams); + "textDocument/definition" => GotoDef(TextDocumentPositionParams); + "textDocument/references" => FindAllRef(ReferenceParams); + "textDocument/completion" => Complete(TextDocumentPositionParams); + "textDocument/documentHighlight" => Highlight(TextDocumentPositionParams); + // currently, we safely ignore this as a pass-through since we fully handle + // textDocument/completion. In the future, we may want to use this method as a + // way to more lazily fill out completion information + "completionItem/resolve" => CompleteResolve(CompletionItem); + "textDocument/documentSymbol" => Symbols(DocumentSymbolParams); + "textDocument/rename" => Rename(RenameParams); + "textDocument/formatting" => Reformat(DocumentFormattingParams); + "textDocument/rangeFormatting" => ReformatRange(DocumentRangeFormattingParams); + } + notifications { + "exit" => Exit; + "textDocument/didChange" => Change(DidChangeTextDocumentParams); + "textDocument/didOpen" => Open(DidOpenTextDocumentParams); + "textDocument/didSave" => Save(DidSaveTextDocumentParams); + "$/cancelRequest" => CancelRequest(CancelParams); + } + // TODO handle me + "$/setTraceNotification" => Err(ParseError::new(ErrorKind::InvalidData, "setTraceNotification", None)); + // TODO handle me + "workspace/didChangeConfiguration" => Err(ParseError::new(ErrorKind::InvalidData, "didChangeConfiguration", None)); + _ => Err(ParseError::new(ErrorKind::InvalidData, "Unknown command", id!())); +} + +pub struct LsService { + shut_down: AtomicBool, + msg_reader: Box, + output: Box, + handler: ActionHandler, +} + +#[derive(Eq, PartialEq, Debug, Clone, Copy)] +pub enum ServerStateChange { + Continue, + Break, +} + +impl LsService { + pub fn new(analysis: Arc, + vfs: Arc, + build_queue: Arc, + reader: Box, + output: Box) + -> Arc { + Arc::new(LsService { + shut_down: AtomicBool::new(false), + msg_reader: reader, + output: output, + handler: ActionHandler::new(analysis, vfs, build_queue), + }) + } + + pub fn run(this: Arc) { + while LsService::handle_message(this.clone()) == ServerStateChange::Continue {} + } + + fn init(&self, id: usize, init: InitializeParams) { + let root_path = init.root_path.map(PathBuf::from); + let unstable_features = if let Some(ref root_path) = root_path { + let config = Config::from_path(&root_path); + config.unstable_features + } else { + false + }; + + let result = InitializeResult { + capabilities: ServerCapabilities { + text_document_sync: Some(TextDocumentSyncKind::Incremental), + hover_provider: Some(true), + completion_provider: Some(CompletionOptions { + resolve_provider: Some(true), + trigger_characters: vec![".".to_string(), ":".to_string()], + }), + // TODO + signature_help_provider: Some(SignatureHelpOptions { + trigger_characters: Some(vec![]), + }), + definition_provider: Some(true), + references_provider: Some(true), + document_highlight_provider: Some(true), + document_symbol_provider: Some(true), + workspace_symbol_provider: Some(true), + code_action_provider: Some(false), + // TODO maybe? + code_lens_provider: None, + document_formatting_provider: Some(unstable_features), + document_range_formatting_provider: Some(unstable_features), + document_on_type_formatting_provider: None, // TODO: review this, maybe add? + rename_provider: Some(unstable_features), + } + }; + self.output.success(id, ResponseData::Init(result)); + if let Some(root_path) = root_path { + self.handler.init(root_path, &*self.output); + } + } + + pub fn handle_message(this: Arc) -> ServerStateChange { + let c = match this.msg_reader.read_message() { + Some(c) => c, + None => { + this.output.parse_error(); + return ServerStateChange::Break + }, + }; + + let this = this.clone(); + thread::spawn(move || { + // FIXME(45) refactor to generate this match. + let message = parse_message(&c); + { + let shut_down = this.shut_down.load(Ordering::SeqCst); + if shut_down { + if let Ok(ServerMessage::Notification(Notification::Exit)) = message { + } else { + // We're shutdown, ignore any messages other than 'exit'. This is not actually + // in the spec, I'm not sure we should do this, but it kinda makes sense. + return; + } + } + } + match message { + Ok(ServerMessage::Notification(method)) => { + match method { + Notification::Exit => { + trace!("exiting..."); + let shut_down = this.shut_down.load(Ordering::SeqCst); + ::std::process::exit(if shut_down { 0 } else { 1 }); + } + Notification::CancelRequest(params) => { + trace!("request to cancel {:?}", params.id); + } + Notification::Change(change) => { + trace!("notification(change): {:?}", change); + this.handler.on_change(change, &*this.output); + } + Notification::Open(open) => { + trace!("notification(open): {:?}", open); + this.handler.on_open(open, &*this.output); + } + Notification::Save(save) => { + trace!("notification(save): {:?}", save); + this.handler.on_save(save, &*this.output); + } + } + } + Ok(ServerMessage::Request(Request{id, method})) => { + match method { + Method::Initialize(init) => { + trace!("command(init): {:?}", init); + this.init(id, init); + } + Method::Shutdown => { + trace!("shutting down..."); + this.shut_down.store(true, Ordering::SeqCst); + + let out = &*this.output; + out.success(id, ResponseData::Ack(Ack {})); + } + Method::Hover(params) => { + trace!("command(hover): {:?}", params); + this.handler.hover(id, params, &*this.output); + } + Method::GotoDef(params) => { + trace!("command(goto): {:?}", params); + this.handler.goto_def(id, params, &*this.output); + } + Method::Complete(params) => { + trace!("command(complete): {:?}", params); + this.handler.complete(id, params, &*this.output); + } + Method::CompleteResolve(params) => { + trace!("command(complete): {:?}", params); + this.output.success(id, ResponseData::CompletionItems(vec![params])) + } + Method::Highlight(params) => { + trace!("command(highlight): {:?}", params); + this.handler.highlight(id, params, &*this.output); + } + Method::Symbols(params) => { + trace!("command(goto): {:?}", params); + this.handler.symbols(id, params, &*this.output); + } + Method::FindAllRef(params) => { + trace!("command(find_all_refs): {:?}", params); + this.handler.find_all_refs(id, params, &*this.output); + } + Method::Rename(params) => { + trace!("command(rename): {:?}", params); + this.handler.rename(id, params, &*this.output); + } + Method::Reformat(params) => { + // FIXME take account of options. + trace!("command(reformat): {:?}", params); + this.handler.reformat(id, params.text_document, &*this.output); + } + Method::ReformatRange(params) => { + // FIXME reformats the whole file, not just a range. + // FIXME take account of options. + trace!("command(reformat range): {:?}", params); + this.handler.reformat(id, params.text_document, &*this.output); + } + } + } + Err(e) => { + trace!("parsing invalid message: {:?}", e); + if let Some(id) = e.id { + this.output.failure(id, "Unsupported message"); + } + }, + } + }); + ServerStateChange::Continue + } +} + +pub trait MessageReader { + fn read_message(&self) -> Option; +} + +struct StdioMsgReader; + +impl MessageReader for StdioMsgReader { + fn read_message(&self) -> Option { + macro_rules! handle_err { + ($e: expr, $s: expr) => { + match $e { + Ok(x) => x, + Err(_) => { + debug!($s); + return None; + } + } + } + } + + // Read in the "Content-length: xx" part + let mut buffer = String::new(); + handle_err!(io::stdin().read_line(&mut buffer), "Could not read from stdin"); + + if buffer.is_empty() { + info!("Header is empty"); + return None; + } + + let res: Vec<&str> = buffer.split(' ').collect(); + + // Make sure we see the correct header + if res.len() != 2 { + info!("Header is malformed"); + return None; + } + + if res[0].to_lowercase() != "content-length:" { + info!("Header is missing 'content-length'"); + return None; + } + + let size = handle_err!(usize::from_str_radix(&res[1].trim(), 10), "Couldn't read size"); + trace!("reading: {} bytes", size); + + // Skip the new lines + let mut tmp = String::new(); + handle_err!(io::stdin().read_line(&mut tmp), "Could not read from stdin"); + + let mut content = vec![0; size]; + handle_err!(io::stdin().read_exact(&mut content), "Could not read from stdin"); + + let content = handle_err!(String::from_utf8(content), "Non-utf8 input"); + + Some(content) + } +} + +pub trait Output { + fn response(&self, output: String); + + fn parse_error(&self) { + self.response(r#"{"jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error"}, "id": null}"#.to_owned()); + } + + fn failure(&self, id: usize, message: &str) { + // For now this is a catch-all for any error back to the consumer of the RLS + const METHOD_NOT_FOUND: i64 = -32601; + + #[derive(Serialize)] + struct ResponseError { + code: i64, + message: String + } + + #[derive(Serialize)] + struct ResponseFailure { + jsonrpc: &'static str, + id: usize, + error: ResponseError, + } + + let rf = ResponseFailure { + jsonrpc: "2.0", + id: id, + error: ResponseError { + code: METHOD_NOT_FOUND, + message: message.to_owned(), + }, + }; + let output = serde_json::to_string(&rf).unwrap(); + self.response(output); + } + + fn success(&self, id: usize, data: ResponseData) { + // { + // jsonrpc: String, + // id: usize, + // result: String, + // } + let output = format!("{{\"jsonrpc\":\"2.0\",\"id\":{},\"result\":{}}}", id, data); + + self.response(output); + } + + fn notify(&self, message: &str) { + let output = serde_json::to_string( + &NotificationMessage::new(message.to_owned(), ()) + ).unwrap(); + self.response(output); + } +} + +struct StdioOutput; + +impl Output for StdioOutput { + fn response(&self, output: String) { + let o = format!("Content-Length: {}\r\n\r\n{}", output.len(), output); + + debug!("response: {:?}", o); + + print!("{}", o); + io::stdout().flush().unwrap(); + } +} + +pub fn run_server(analysis: Arc, vfs: Arc, build_queue: Arc) { + debug!("Language Server Starting up"); + let service = LsService::new(analysis, + vfs, + build_queue, + Box::new(StdioMsgReader), + Box::new(StdioOutput)); + LsService::run(service); + debug!("Server shutting down"); +} diff --git a/rls/src/test/mod.rs b/rls/src/test/mod.rs new file mode 100644 index 0000000000..a4a7d0f4df --- /dev/null +++ b/rls/src/test/mod.rs @@ -0,0 +1,567 @@ +// 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. + +// Utilities and infrastructure for testing. Tests in this module test the +// testing infrastructure *not* the RLS. + +mod types; + +use std::sync::{Arc, Mutex}; +use std::thread; +use std::time::{Duration, SystemTime}; +use env_logger; + +use analysis; +use build; +use server as ls_server; +use vfs; + +use self::types::src; + +use hyper::Url; +use serde_json; +use std::path::{Path, PathBuf}; + +const TEST_TIMEOUT_IN_SEC: u64 = 10; + +#[test] +fn test_goto_def() { + let (mut cache, _tc) = init_env("goto_def"); + + let source_file_path = Path::new("src").join("main.rs"); + + let root_path = format!("{}", serde_json::to_string(&cache.abs_path(Path::new("."))) + .expect("couldn't convert path to JSON")); + let url = Url::from_file_path(cache.abs_path(&source_file_path)).expect("couldn't convert file path to URL"); + let text_doc = format!("{{\"uri\":{}}}", serde_json::to_string(&url.as_str().to_owned()) + .expect("couldn't convert path to JSON")); + let messages = vec![Message::new("initialize", vec![("processId", "0".to_owned()), + ("capabilities", "null".to_owned()), + ("rootPath", root_path)]), + Message::new("textDocument/definition", + vec![("textDocument", text_doc), + ("position", cache.mk_ls_position(src(&source_file_path, 22, "world")))])]; + let (server, results) = mock_server(messages); + // Initialise and build. + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Continue); + expect_messages(results.clone(), &[ExpectedMessage::new(Some(42)).expect_contains("capabilities"), + ExpectedMessage::new(None).expect_contains("diagnosticsBegin"), + ExpectedMessage::new(None).expect_contains("diagnosticsEnd")]); + + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Continue); + // TODO structural checking of result, rather than looking for a string - src(&source_file_path, 12, "world") + expect_messages(results.clone(), &[ExpectedMessage::new(Some(42)).expect_contains("\"start\":{\"line\":20,\"character\":8}")]); +} + +#[test] +fn test_hover() { + let (mut cache, _tc) = init_env("hover"); + + let source_file_path = Path::new("src").join("main.rs"); + + let root_path = format!("{}", serde_json::to_string(&cache.abs_path(Path::new("."))) + .expect("couldn't convert path to JSON")); + + let url = Url::from_file_path(cache.abs_path(&source_file_path)).expect("couldn't convert file path to URL"); + let text_doc = format!("{{\"uri\":{}}}", serde_json::to_string(&url.as_str().to_owned()) + .expect("couldn't convert path to JSON")); + let messages = vec![Message::new("initialize", vec![("processId", "0".to_owned()), + ("capabilities", "null".to_owned()), + ("rootPath", root_path)]), + Message::new("textDocument/hover", + vec![("textDocument", text_doc), + ("position", cache.mk_ls_position(src(&source_file_path, 22, "world")))])]; + let (server, results) = mock_server(messages); + // Initialise and build. + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Continue); + expect_messages(results.clone(), &[ExpectedMessage::new(Some(42)).expect_contains("capabilities"), + ExpectedMessage::new(None).expect_contains("diagnosticsBegin"), + ExpectedMessage::new(None).expect_contains("diagnosticsEnd")]); + + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Continue); + expect_messages(results.clone(), &[ExpectedMessage::new(Some(42)).expect_contains("[{\"language\":\"rust\",\"value\":\"&str\"}]")]); +} + +#[test] +fn test_find_all_refs() { + let (mut cache, _tc) = init_env("find_all_refs"); + + let source_file_path = Path::new("src").join("main.rs"); + + let root_path = format!("{}", serde_json::to_string(&cache.abs_path(Path::new("."))) + .expect("couldn't convert path to JSON")); + let url = Url::from_file_path(cache.abs_path(&source_file_path)).expect("couldn't convert file path to URL"); + let text_doc = format!("{{\"uri\":{}}}", serde_json::to_string(&url.as_str().to_owned()) + .expect("couldn't convert path to JSON")); + let messages = vec![format!(r#"{{ + "jsonrpc": "2.0", + "method": "initialize", + "id": 0, + "params": {{ + "processId": "0", + "capabilities": null, + "rootPath": {} + }} + }}"#, root_path), format!(r#"{{ + "jsonrpc": "2.0", + "method": "textDocument/references", + "id": 42, + "params": {{ + "textDocument": {}, + "position": {}, + "context": {{ + "includeDeclaration": true + }} + }} + }}"#, text_doc, cache.mk_ls_position(src(&source_file_path, 10, "Bar")))]; + + let (server, results) = mock_raw_server(messages); + // Initialise and build. + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Continue); + expect_messages(results.clone(), &[ExpectedMessage::new(Some(0)).expect_contains("capabilities"), + ExpectedMessage::new(None).expect_contains("diagnosticsBegin"), + ExpectedMessage::new(None).expect_contains("diagnosticsEnd")]); + + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Continue); + expect_messages(results.clone(), &[ExpectedMessage::new(Some(42)).expect_contains(r#"{"start":{"line":9,"character":7},"end":{"line":9,"character":10}}"#) + .expect_contains(r#"{"start":{"line":15,"character":14},"end":{"line":15,"character":17}}"#) + .expect_contains(r#"{"start":{"line":23,"character":15},"end":{"line":23,"character":18}}"#)]); +} + +#[test] +fn test_find_all_refs_no_cfg_test() { + let (mut cache, _tc) = init_env("find_all_refs_no_cfg_test"); + + let source_file_path = Path::new("src").join("main.rs"); + + let root_path = format!("{}", serde_json::to_string(&cache.abs_path(Path::new("."))) + .expect("couldn't convert path to JSON")); + let url = Url::from_file_path(cache.abs_path(&source_file_path)).expect("couldn't convert file path to URL"); + let text_doc = format!("{{\"uri\":{}}}", serde_json::to_string(&url.as_str().to_owned()) + .expect("couldn't convert path to JSON")); + let messages = vec![format!(r#"{{ + "jsonrpc": "2.0", + "method": "initialize", + "id": 0, + "params": {{ + "processId": "0", + "capabilities": null, + "rootPath": {} + }} + }}"#, root_path), format!(r#"{{ + "jsonrpc": "2.0", + "method": "textDocument/references", + "id": 42, + "params": {{ + "textDocument": {}, + "position": {}, + "context": {{ + "includeDeclaration": true + }} + }} + }}"#, text_doc, cache.mk_ls_position(src(&source_file_path, 10, "Bar")))]; + + let (server, results) = mock_raw_server(messages); + // Initialise and build. + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Continue); + expect_messages(results.clone(), &[ExpectedMessage::new(Some(0)).expect_contains("capabilities"), + ExpectedMessage::new(None).expect_contains("diagnosticsBegin"), + ExpectedMessage::new(None).expect_contains("diagnosticsEnd")]); + + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Continue); + expect_messages(results.clone(), &[ExpectedMessage::new(Some(42)).expect_contains(r#"{"start":{"line":9,"character":7},"end":{"line":9,"character":10}}"#) + .expect_contains(r#"{"start":{"line":23,"character":15},"end":{"line":23,"character":18}}"#)]); +} + +#[test] +fn test_borrow_error() { + let (cache, _tc) = init_env("borrow_error"); + + let root_path = format!("{}", serde_json::to_string(&cache.abs_path(Path::new("."))) + .expect("couldn't convert path to JSON")); + let messages = vec![format!(r#"{{ + "jsonrpc": "2.0", + "method": "initialize", + "id": 0, + "params": {{ + "processId": "0", + "capabilities": null, + "rootPath": {} + }} + }}"#, root_path)]; + + let (server, results) = mock_raw_server(messages); + // Initialise and build. + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Continue); + expect_messages(results.clone(), &[ExpectedMessage::new(Some(0)).expect_contains("capabilities"), + ExpectedMessage::new(None).expect_contains("diagnosticsBegin"), + ExpectedMessage::new(None).expect_contains("\"secondaryRanges\":[{\"start\":{\"line\":2,\"character\":17},\"end\":{\"line\":2,\"character\":18},\"label\":\"first mutable borrow occurs here\"}"), + ExpectedMessage::new(None).expect_contains("diagnosticsEnd")]); +} + +#[test] +fn test_highlight() { + let (mut cache, _tc) = init_env("highlight"); + + let source_file_path = Path::new("src").join("main.rs"); + + let root_path = format!("{}", serde_json::to_string(&cache.abs_path(Path::new("."))) + .expect("couldn't convert path to JSON")); + let url = Url::from_file_path(cache.abs_path(&source_file_path)).expect("couldn't convert file path to URL"); + let text_doc = format!("{{\"uri\":{}}}", serde_json::to_string(&url.as_str().to_owned()) + .expect("couldn't convert path to JSON")); + let messages = vec![format!(r#"{{ + "jsonrpc": "2.0", + "method": "initialize", + "id": 0, + "params": {{ + "processId": "0", + "capabilities": null, + "rootPath": {} + }} + }}"#, root_path), format!(r#"{{ + "jsonrpc": "2.0", + "method": "textDocument/documentHighlight", + "id": 42, + "params": {{ + "textDocument": {}, + "position": {} + }} + }}"#, text_doc, cache.mk_ls_position(src(&source_file_path, 22, "world")))]; + + let (server, results) = mock_raw_server(messages); + // Initialise and build. + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Continue); + expect_messages(results.clone(), &[ExpectedMessage::new(Some(0)).expect_contains("capabilities"), + ExpectedMessage::new(None).expect_contains("diagnosticsBegin"), + ExpectedMessage::new(None).expect_contains("diagnosticsEnd")]); + + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Continue); + expect_messages(results.clone(), &[ExpectedMessage::new(Some(42)).expect_contains(r#"{"start":{"line":20,"character":8},"end":{"line":20,"character":13}}"#) + .expect_contains(r#"{"start":{"line":21,"character":27},"end":{"line":21,"character":32}}"#),]); +} + +#[test] +fn test_rename() { + let (mut cache, _tc) = init_env("rename"); + + let source_file_path = Path::new("src").join("main.rs"); + + let root_path = format!("{}", serde_json::to_string(&cache.abs_path(Path::new("."))) + .expect("couldn't convert path to JSON")); + let url = Url::from_file_path(cache.abs_path(&source_file_path)).expect("couldn't convert file path to URL"); + let text_doc = format!("{{\"uri\":{}}}", serde_json::to_string(&url.as_str().to_owned()) + .expect("couldn't convert path to JSON")); + let messages = vec![format!(r#"{{ + "jsonrpc": "2.0", + "method": "initialize", + "id": 0, + "params": {{ + "processId": "0", + "capabilities": null, + "rootPath": {} + }} + }}"#, root_path), format!(r#"{{ + "jsonrpc": "2.0", + "method": "textDocument/rename", + "id": 42, + "params": {{ + "textDocument": {}, + "position": {}, + "newName": "foo" + }} + }}"#, text_doc, cache.mk_ls_position(src(&source_file_path, 22, "world")))]; + + let (server, results) = mock_raw_server(messages); + // Initialise and build. + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Continue); + expect_messages(results.clone(), &[ExpectedMessage::new(Some(0)).expect_contains("capabilities"), + ExpectedMessage::new(None).expect_contains("diagnosticsBegin"), + ExpectedMessage::new(None).expect_contains("diagnosticsEnd")]); + + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Continue); + expect_messages(results.clone(), &[ExpectedMessage::new(Some(42)).expect_contains(r#"{"start":{"line":20,"character":8},"end":{"line":20,"character":13}}"#) + .expect_contains(r#"{"start":{"line":21,"character":27},"end":{"line":21,"character":32}}"#) + .expect_contains(r#"{"changes""#),]); +} + +#[test] +fn test_completion() { + let (mut cache, _tc) = init_env("completion"); + + let source_file_path = Path::new("src").join("main.rs"); + + let root_path = format!("{}", serde_json::to_string(&cache.abs_path(Path::new("."))) + .expect("couldn't convert path to JSON")); + let url = Url::from_file_path(cache.abs_path(&source_file_path)).expect("couldn't convert file path to URL"); + let text_doc = format!("{{\"uri\":{}}}", serde_json::to_string(&url.as_str().to_owned()) + .expect("couldn't convert path to JSON")); + let messages = vec![Message::new("initialize", vec![("processId", "0".to_owned()), + ("capabilities", "null".to_owned()), + ("rootPath", root_path)]), + Message::new("textDocument/completion", + vec![("textDocument", text_doc.to_owned()), + ("position", cache.mk_ls_position(src(&source_file_path, 22, "rld")))]), + Message::new("textDocument/completion", + vec![("textDocument", text_doc.to_owned()), + ("position", cache.mk_ls_position(src(&source_file_path, 25, "x)")))])]; + let (server, results) = mock_server(messages); + // Initialise and build. + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Continue); + expect_messages(results.clone(), &[ExpectedMessage::new(Some(42)).expect_contains("capabilities"), + ExpectedMessage::new(None).expect_contains("diagnosticsBegin"), + ExpectedMessage::new(None).expect_contains("diagnosticsEnd")]); + + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Continue); + expect_messages(results.clone(), &[ExpectedMessage::new(Some(42)).expect_contains("[{\"label\":\"world\",\"kind\":6,\"detail\":\"let world = \\\"world\\\";\"}]")]); + + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Continue); + expect_messages(results.clone(), &[ExpectedMessage::new(Some(42)).expect_contains("[{\"label\":\"x\",\"kind\":5,\"detail\":\"u64\"}]")]); +} + +#[test] +fn test_parse_error_on_malformed_input() { + let _ = env_logger::init(); + struct NoneMsgReader; + + impl ls_server::MessageReader for NoneMsgReader { + fn read_message(&self) -> Option { None } + } + + let analysis = Arc::new(analysis::AnalysisHost::new(analysis::Target::Debug)); + let vfs = Arc::new(vfs::Vfs::new()); + let build_queue = Arc::new(build::BuildQueue::new(vfs.clone())); + let reader = Box::new(NoneMsgReader); + let output = Box::new(RecordOutput::new()); + let results = output.output.clone(); + let server = ls_server::LsService::new(analysis, vfs, build_queue, reader, output); + + assert_eq!(ls_server::LsService::handle_message(server.clone()), + ls_server::ServerStateChange::Break); + + let error = results.lock().unwrap() + .pop().expect("no error response"); + assert!(error.contains(r#""code": -32700"#)) +} + +// Initialise and run the internals of an LS protocol RLS server. +fn mock_server(messages: Vec) -> (Arc, LsResultList) +{ + let analysis = Arc::new(analysis::AnalysisHost::new(analysis::Target::Debug)); + let vfs = Arc::new(vfs::Vfs::new()); + let build_queue = Arc::new(build::BuildQueue::new(vfs.clone())); + let reader = Box::new(MockMsgReader::new(messages)); + let output = Box::new(RecordOutput::new()); + let results = output.output.clone(); + (ls_server::LsService::new(analysis, vfs, build_queue, reader, output), results) +} + +// Initialise and run the internals of an LS protocol RLS server. +fn mock_raw_server(messages: Vec) -> (Arc, LsResultList) +{ + let analysis = Arc::new(analysis::AnalysisHost::new(analysis::Target::Debug)); + let vfs = Arc::new(vfs::Vfs::new()); + let build_queue = Arc::new(build::BuildQueue::new(vfs.clone())); + let reader = Box::new(MockRawMsgReader::new(messages)); + let output = Box::new(RecordOutput::new()); + let results = output.output.clone(); + (ls_server::LsService::new(analysis, vfs, build_queue, reader, output), results) +} + +struct MockMsgReader { + messages: Vec, + cur: Mutex, +} + +impl MockMsgReader { + fn new(messages: Vec) -> MockMsgReader { + MockMsgReader { + messages: messages, + cur: Mutex::new(0), + } + } +} + +struct MockRawMsgReader { + messages: Vec, + cur: Mutex, +} + +impl MockRawMsgReader { + fn new(messages: Vec) -> MockRawMsgReader { + MockRawMsgReader { + messages: messages, + cur: Mutex::new(0), + } + } +} + +// TODO should have a structural way of making params, rather than taking Strings +struct Message { + method: &'static str, + params: Vec<(&'static str, String)>, +} + +impl Message { + fn new(method: &'static str, params: Vec<(&'static str, String)>) -> Message { + Message { + method: method, + params: params, + } + } +} + +impl ls_server::MessageReader for MockMsgReader { + fn read_message(&self) -> Option { + // Note that we hold this lock until the end of the function, thus meaning + // that we must finish processing one message before processing the next. + let mut cur = self.cur.lock().unwrap(); + let index = *cur; + *cur += 1; + + if index >= self.messages.len() { + return None; + } + + let message = &self.messages[index]; + + let params = message.params.iter().map(|&(k, ref v)| format!("\"{}\":{}", k, v)).collect::>().join(","); + // TODO don't hardcode the id, we should use fresh ids and use them to look up responses + let result = format!("{{\"method\":\"{}\",\"id\":42,\"params\":{{{}}}}}", message.method, params); + // println!("read_message: `{}`", result); + + Some(result) + } +} + +impl ls_server::MessageReader for MockRawMsgReader { + fn read_message(&self) -> Option { + // Note that we hold this lock until the end of the function, thus meaning + // that we must finish processing one message before processing the next. + let mut cur = self.cur.lock().unwrap(); + let index = *cur; + *cur += 1; + + if index >= self.messages.len() { + return None; + } + + let message = &self.messages[index]; + + Some(message.clone()) + } +} + +type LsResultList = Arc>>; + +struct RecordOutput { + output: LsResultList, +} + +impl RecordOutput { + fn new() -> RecordOutput { + RecordOutput { + output: Arc::new(Mutex::new(vec![])), + } + } +} + +impl ls_server::Output for RecordOutput { + fn response(&self, output: String) { + let mut records = self.output.lock().unwrap(); + records.push(output); + } +} + +// Initialise the environment for a test. +fn init_env(project_dir: &str) -> (types::Cache, TestCleanup) { + let _ = env_logger::init(); + + let path = &Path::new("test_data").join(project_dir); + let tc = TestCleanup { path: path.to_owned() }; + (types::Cache::new(path), tc) +} + +#[derive(Clone, Debug)] +struct ExpectedMessage { + id: Option, + contains: Vec, +} + +impl ExpectedMessage { + fn new(id: Option) -> ExpectedMessage { + ExpectedMessage { + id: id, + contains: vec![], + } + } + + fn expect_contains(&mut self, s: &str) -> &mut ExpectedMessage { + self.contains.push(s.to_owned()); + self + } +} + +fn expect_messages(results: LsResultList, expected: &[&ExpectedMessage]) { + let start_clock = SystemTime::now(); + let mut results_count = results.lock().unwrap().len(); + while (results_count != expected.len()) && (start_clock.elapsed().unwrap().as_secs() < TEST_TIMEOUT_IN_SEC) { + thread::sleep(Duration::from_millis(100)); + results_count = results.lock().unwrap().len(); + } + + let mut results = results.lock().unwrap(); + + println!("expect_messages: results: {:?},\nexpected: {:?}", *results, expected); + assert_eq!(results.len(), expected.len()); + for (found, expected) in results.iter().zip(expected.iter()) { + let values: serde_json::Value = serde_json::from_str(found).unwrap(); + assert!(values.get("jsonrpc").expect("Missing jsonrpc field").as_str().unwrap() == "2.0", "Bad jsonrpc field"); + if let Some(id) = expected.id { + assert_eq!(values.get("id").expect("Missing id field").as_u64().unwrap(), id, "Unexpected id"); + } + for c in expected.contains.iter() { + found.find(c).expect(&format!("Could not find `{}` in `{}`", c, found)); + } + } + + *results = vec![]; +} + +struct TestCleanup { + path: PathBuf +} + +impl Drop for TestCleanup { + fn drop(&mut self) { + use std::fs; + + let target_path = self.path.join("target"); + if fs::metadata(&target_path).is_ok() { + fs::remove_dir_all(target_path).expect("failed to tidy up"); + } + } +} diff --git a/rls/src/test/types.rs b/rls/src/test/types.rs new file mode 100644 index 0000000000..0669cc63d0 --- /dev/null +++ b/rls/src/test/types.rs @@ -0,0 +1,92 @@ +// 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. + +use std::collections::HashMap; +use std::env; +use std::fs::File; +use std::path::{Path, PathBuf}; +use std::io::{BufRead, BufReader}; + +#[derive(Clone, Copy, Debug)] +pub struct Src<'a, 'b> { + pub file_name: &'a Path, + // 1 indexed + pub line: usize, + pub name: &'b str, +} + +pub fn src<'a, 'b>(file_name: &'a Path, line: usize, name: &'b str) -> Src<'a, 'b> { + Src { + file_name: file_name, + line: line, + name: name, + } +} + +pub struct Cache { + base_path: PathBuf, + files: HashMap>, +} + +impl Cache { + pub fn new(base_path: &Path) -> Cache { + let mut root_path = env::current_dir().expect("Could not find current working directory"); + root_path.push(base_path); + + Cache { + base_path: root_path, + files: HashMap::new(), + } + } + + pub fn mk_ls_position(&mut self, src: Src) -> String { + let line = self.get_line(src); + let col = line.find(src.name).expect(&format!("Line does not contain name {}", src.name)); + format!("{{\"line\":\"{}\",\"character\":\"{}\"}}", src.line - 1, char_of_byte_index(&line, col)) + } + + pub fn abs_path(&self, file_name: &Path) -> PathBuf { + let result = self.base_path.join(file_name).canonicalize().expect("Couldn't canonicalise path"); + let result = if cfg!(windows) { + // FIXME: If the \\?\ prefix is not stripped from the canonical path, the HTTP server tests fail. Why? + let result_string = result.to_str().expect("Path contains non-utf8 characters."); + PathBuf::from(&result_string[r"\\?\".len()..]) + } else { + result + }; + result + } + + fn get_line(&mut self, src: Src) -> String { + let base_path = &self.base_path; + let lines = self.files.entry(src.file_name.to_owned()).or_insert_with(|| { + let file_name = &base_path.join(src.file_name); + let file = File::open(file_name).expect(&format!("Couldn't find file: {:?}", file_name)); + let lines = BufReader::new(file).lines(); + lines.collect::, _>>().unwrap() + }); + + if src.line - 1 >= lines.len() { + panic!("Line {} not in file, found {} lines", src.line, lines.len()); + } + + lines[src.line - 1].to_owned() + } +} + +fn char_of_byte_index(s: &str, byte: usize) -> usize { + for (c, (b, _)) in s.char_indices().enumerate() { + if b == byte { + return c; + } + } + + panic!("Couldn't find byte {} in {:?}", byte, s); +} diff --git a/rls/test_data/borrow_error/Cargo.lock b/rls/test_data/borrow_error/Cargo.lock new file mode 100644 index 0000000000..bdaf24e7dc --- /dev/null +++ b/rls/test_data/borrow_error/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "borrow_error" +version = "0.1.0" + diff --git a/rls/test_data/borrow_error/Cargo.toml b/rls/test_data/borrow_error/Cargo.toml new file mode 100644 index 0000000000..79422de902 --- /dev/null +++ b/rls/test_data/borrow_error/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "borrow_error" +version = "0.1.0" +authors = ["Jonathan Turner "] + +[dependencies] diff --git a/rls/test_data/borrow_error/src/main.rs b/rls/test_data/borrow_error/src/main.rs new file mode 100644 index 0000000000..0e4d280cab --- /dev/null +++ b/rls/test_data/borrow_error/src/main.rs @@ -0,0 +1,5 @@ +fn main() { + let mut x = 3; + let y = &mut x; + let z = &mut x; +} diff --git a/rls/test_data/completion/Cargo.lock b/rls/test_data/completion/Cargo.lock new file mode 100644 index 0000000000..d0542659ff --- /dev/null +++ b/rls/test_data/completion/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "completion" +version = "0.1.0" + diff --git a/rls/test_data/completion/Cargo.toml b/rls/test_data/completion/Cargo.toml new file mode 100644 index 0000000000..52ea02018e --- /dev/null +++ b/rls/test_data/completion/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "completion" +version = "0.1.0" +authors = ["Nick Cameron "] + +[dependencies] diff --git a/rls/test_data/completion/src/main.rs b/rls/test_data/completion/src/main.rs new file mode 100644 index 0000000000..442dd8c70a --- /dev/null +++ b/rls/test_data/completion/src/main.rs @@ -0,0 +1,26 @@ +// 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. +struct Bar { + x: u64, +} + +#[test] +pub fn test_fn() { + let bar = Bar { x: 4 }; + println!("bar: {}", bar.x); +} + +pub fn main() { + let world = "world"; + println!("Hello, {}!", world); + + let bar2 = Bar { x: 5 }; + println!("bar2: {}", bar2.x); +} diff --git a/rls/test_data/find_all_refs/Cargo.lock b/rls/test_data/find_all_refs/Cargo.lock new file mode 100644 index 0000000000..385abded0f --- /dev/null +++ b/rls/test_data/find_all_refs/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "find_all_refs" +version = "0.1.0" + diff --git a/rls/test_data/find_all_refs/Cargo.toml b/rls/test_data/find_all_refs/Cargo.toml new file mode 100644 index 0000000000..f8f5382f67 --- /dev/null +++ b/rls/test_data/find_all_refs/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "find_all_refs" +version = "0.1.0" +authors = ["Nick Cameron "] + +[dependencies] diff --git a/rls/test_data/find_all_refs/src/main.rs b/rls/test_data/find_all_refs/src/main.rs new file mode 100644 index 0000000000..442dd8c70a --- /dev/null +++ b/rls/test_data/find_all_refs/src/main.rs @@ -0,0 +1,26 @@ +// 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. +struct Bar { + x: u64, +} + +#[test] +pub fn test_fn() { + let bar = Bar { x: 4 }; + println!("bar: {}", bar.x); +} + +pub fn main() { + let world = "world"; + println!("Hello, {}!", world); + + let bar2 = Bar { x: 5 }; + println!("bar2: {}", bar2.x); +} diff --git a/rls/test_data/find_all_refs_no_cfg_test/Cargo.lock b/rls/test_data/find_all_refs_no_cfg_test/Cargo.lock new file mode 100644 index 0000000000..eeaff79768 --- /dev/null +++ b/rls/test_data/find_all_refs_no_cfg_test/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "find_all_refs_no_cfg_test" +version = "0.1.0" + diff --git a/rls/test_data/find_all_refs_no_cfg_test/Cargo.toml b/rls/test_data/find_all_refs_no_cfg_test/Cargo.toml new file mode 100644 index 0000000000..a7e628f035 --- /dev/null +++ b/rls/test_data/find_all_refs_no_cfg_test/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "find_all_refs_no_cfg_test" +version = "0.1.0" +authors = ["Nick Cameron "] + +[dependencies] diff --git a/rls/test_data/find_all_refs_no_cfg_test/rls.toml b/rls/test_data/find_all_refs_no_cfg_test/rls.toml new file mode 100644 index 0000000000..25ea1c074a --- /dev/null +++ b/rls/test_data/find_all_refs_no_cfg_test/rls.toml @@ -0,0 +1 @@ +cfg_test = false diff --git a/rls/test_data/find_all_refs_no_cfg_test/src/main.rs b/rls/test_data/find_all_refs_no_cfg_test/src/main.rs new file mode 100644 index 0000000000..442dd8c70a --- /dev/null +++ b/rls/test_data/find_all_refs_no_cfg_test/src/main.rs @@ -0,0 +1,26 @@ +// 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. +struct Bar { + x: u64, +} + +#[test] +pub fn test_fn() { + let bar = Bar { x: 4 }; + println!("bar: {}", bar.x); +} + +pub fn main() { + let world = "world"; + println!("Hello, {}!", world); + + let bar2 = Bar { x: 5 }; + println!("bar2: {}", bar2.x); +} diff --git a/rls/test_data/goto_def/Cargo.lock b/rls/test_data/goto_def/Cargo.lock new file mode 100644 index 0000000000..cd39559711 --- /dev/null +++ b/rls/test_data/goto_def/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "goto_def" +version = "0.1.0" + diff --git a/rls/test_data/goto_def/Cargo.toml b/rls/test_data/goto_def/Cargo.toml new file mode 100644 index 0000000000..1f3cbe45f1 --- /dev/null +++ b/rls/test_data/goto_def/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "goto_def" +version = "0.1.0" +authors = ["Nick Cameron "] + +[dependencies] diff --git a/rls/test_data/goto_def/src/main.rs b/rls/test_data/goto_def/src/main.rs new file mode 100644 index 0000000000..442dd8c70a --- /dev/null +++ b/rls/test_data/goto_def/src/main.rs @@ -0,0 +1,26 @@ +// 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. +struct Bar { + x: u64, +} + +#[test] +pub fn test_fn() { + let bar = Bar { x: 4 }; + println!("bar: {}", bar.x); +} + +pub fn main() { + let world = "world"; + println!("Hello, {}!", world); + + let bar2 = Bar { x: 5 }; + println!("bar2: {}", bar2.x); +} diff --git a/rls/test_data/highlight/Cargo.lock b/rls/test_data/highlight/Cargo.lock new file mode 100644 index 0000000000..34127b1692 --- /dev/null +++ b/rls/test_data/highlight/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "highlight" +version = "0.1.0" + diff --git a/rls/test_data/highlight/Cargo.toml b/rls/test_data/highlight/Cargo.toml new file mode 100644 index 0000000000..59713edcb8 --- /dev/null +++ b/rls/test_data/highlight/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "highlight" +version = "0.1.0" +authors = ["Nick Cameron "] + +[dependencies] diff --git a/rls/test_data/highlight/src/main.rs b/rls/test_data/highlight/src/main.rs new file mode 100644 index 0000000000..442dd8c70a --- /dev/null +++ b/rls/test_data/highlight/src/main.rs @@ -0,0 +1,26 @@ +// 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. +struct Bar { + x: u64, +} + +#[test] +pub fn test_fn() { + let bar = Bar { x: 4 }; + println!("bar: {}", bar.x); +} + +pub fn main() { + let world = "world"; + println!("Hello, {}!", world); + + let bar2 = Bar { x: 5 }; + println!("bar2: {}", bar2.x); +} diff --git a/rls/test_data/hover/Cargo.lock b/rls/test_data/hover/Cargo.lock new file mode 100644 index 0000000000..637886c623 --- /dev/null +++ b/rls/test_data/hover/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "hover" +version = "0.1.0" + diff --git a/rls/test_data/hover/Cargo.toml b/rls/test_data/hover/Cargo.toml new file mode 100644 index 0000000000..0c80b3d462 --- /dev/null +++ b/rls/test_data/hover/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hover" +version = "0.1.0" +authors = ["Nick Cameron "] + +[dependencies] diff --git a/rls/test_data/hover/src/main.rs b/rls/test_data/hover/src/main.rs new file mode 100644 index 0000000000..442dd8c70a --- /dev/null +++ b/rls/test_data/hover/src/main.rs @@ -0,0 +1,26 @@ +// 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. +struct Bar { + x: u64, +} + +#[test] +pub fn test_fn() { + let bar = Bar { x: 4 }; + println!("bar: {}", bar.x); +} + +pub fn main() { + let world = "world"; + println!("Hello, {}!", world); + + let bar2 = Bar { x: 5 }; + println!("bar2: {}", bar2.x); +} diff --git a/rls/test_data/rename/Cargo.lock b/rls/test_data/rename/Cargo.lock new file mode 100644 index 0000000000..856ffdb4f6 --- /dev/null +++ b/rls/test_data/rename/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "rename" +version = "0.1.0" + diff --git a/rls/test_data/rename/Cargo.toml b/rls/test_data/rename/Cargo.toml new file mode 100644 index 0000000000..7d78964179 --- /dev/null +++ b/rls/test_data/rename/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rename" +version = "0.1.0" +authors = ["Nick Cameron "] + +[dependencies] diff --git a/rls/test_data/rename/rls.toml b/rls/test_data/rename/rls.toml new file mode 100644 index 0000000000..a5e1c6cd5f --- /dev/null +++ b/rls/test_data/rename/rls.toml @@ -0,0 +1 @@ +unstable_features = true \ No newline at end of file diff --git a/rls/test_data/rename/src/main.rs b/rls/test_data/rename/src/main.rs new file mode 100644 index 0000000000..442dd8c70a --- /dev/null +++ b/rls/test_data/rename/src/main.rs @@ -0,0 +1,26 @@ +// 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. +struct Bar { + x: u64, +} + +#[test] +pub fn test_fn() { + let bar = Bar { x: 4 }; + println!("bar: {}", bar.x); +} + +pub fn main() { + let world = "world"; + println!("Hello, {}!", world); + + let bar2 = Bar { x: 5 }; + println!("bar2: {}", bar2.x); +} diff --git a/src/Cargo.lock b/src/Cargo.lock index b34007db8a..f4c35719f3 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -8,7 +8,7 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -27,7 +27,7 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "core 0.0.0", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", ] @@ -48,6 +48,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "arena" version = "0.0.0" +[[package]] +name = "atty" +version = "0.2.2" +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.21 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "0.5.0" @@ -55,7 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "0.7.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -63,13 +73,13 @@ name = "bootstrap" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -77,7 +87,7 @@ dependencies = [ name = "build-manifest" version = "0.1.0" dependencies = [ - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -94,25 +104,25 @@ version = "0.1.0" [[package]] name = "clap" -version = "2.20.5" +version = "2.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cmake" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -130,17 +140,17 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "core 0.0.0", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "compiletest" version = "0.0.0" dependencies = [ - "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -152,14 +162,6 @@ name = "dtoa" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "env_logger" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "env_logger" version = "0.4.2" @@ -186,7 +188,7 @@ name = "flate" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -195,7 +197,7 @@ version = "0.0.0" [[package]] name = "gcc" -version = "0.3.43" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -213,15 +215,15 @@ version = "0.0.0" [[package]] name = "handlebars" -version = "0.25.1" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (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.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -241,7 +243,7 @@ dependencies = [ [[package]] name = "lazy_static" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -260,10 +262,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "linkchecker" version = "0.1.0" -[[package]] -name = "log" -version = "0.0.0" - [[package]] name = "log" version = "0.3.7" @@ -271,12 +269,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mdbook" -version = "0.0.18" +version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)", + "handlebars 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -360,6 +358,14 @@ dependencies = [ "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pulldown-cmark" +version = "0.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "qemu-test-client" version = "0.1.0" @@ -385,7 +391,7 @@ name = "regex" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -397,12 +403,29 @@ name = "regex-syntax" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rls-data" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rls-span" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustbook" version = "0.1.0" dependencies = [ - "clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)", - "mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", + "mdbook 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -412,7 +435,7 @@ dependencies = [ "arena 0.0.0", "fmt_macros 0.0.0", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_math 0.0.0", @@ -435,7 +458,7 @@ dependencies = [ [[package]] name = "rustc-serialize" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -444,7 +467,7 @@ version = "0.0.0" dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -452,7 +475,7 @@ dependencies = [ name = "rustc_back" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax 0.0.0", ] @@ -466,7 +489,7 @@ name = "rustc_borrowck" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -480,8 +503,7 @@ name = "rustc_const_eval" version = "0.0.0" dependencies = [ "arena 0.0.0", - "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_math 0.0.0", @@ -503,7 +525,7 @@ dependencies = [ name = "rustc_data_structures" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", ] @@ -512,8 +534,9 @@ name = "rustc_driver" version = "0.0.0" dependencies = [ "arena 0.0.0", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro_plugin 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -552,7 +575,7 @@ name = "rustc_incremental" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "serialize 0.0.0", @@ -564,7 +587,7 @@ dependencies = [ name = "rustc_lint" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -577,7 +600,7 @@ name = "rustc_llvm" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_bitflags 0.0.0", ] @@ -587,7 +610,7 @@ version = "0.0.0" dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -596,7 +619,7 @@ name = "rustc_metadata" version = "0.0.0" dependencies = [ "flate 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -615,7 +638,7 @@ name = "rustc_mir" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_eval 0.0.0", @@ -631,7 +654,7 @@ version = "0.0.0" dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -639,7 +662,7 @@ dependencies = [ name = "rustc_passes" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", @@ -678,7 +701,7 @@ name = "rustc_resolve" version = "0.0.0" dependencies = [ "arena 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", @@ -689,9 +712,11 @@ dependencies = [ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "serialize 0.0.0", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -701,11 +726,10 @@ name = "rustc_trans" version = "0.0.0" dependencies = [ "flate 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", - "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -723,7 +747,7 @@ version = "0.0.0" dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -733,10 +757,9 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "fmt_macros 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", - "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -751,11 +774,12 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "build_helper 0.1.0", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.0.0", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", - "rustc_const_eval 0.0.0", "rustc_data_structures 0.0.0", "rustc_driver 0.0.0", "rustc_errors 0.0.0", @@ -799,7 +823,7 @@ dependencies = [ "collections 0.0.0", "compiler_builtins 0.0.0", "core 0.0.0", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", "panic_abort 0.0.0", "panic_unwind 0.0.0", @@ -828,7 +852,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "syntax" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_bitflags 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -841,7 +865,7 @@ name = "syntax_ext" version = "0.0.0" dependencies = [ "fmt_macros 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", @@ -904,7 +928,7 @@ name = "toml" version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -940,7 +964,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "vec_map" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -959,35 +983,38 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0638fd549427caa90c499814196d1b9e3725eb4d15d7339d6de073a680ed0ca2" +"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" +"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" -"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7db281b0520e97fbd15cd615dcd8f8bcad0c26f5f7d5effe705f090f39e9a758" -"checksum cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "e1acc68a3f714627af38f9f5d09706a28584ba60dfe2cca68f40bf779f941b25" +"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" +"checksum clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e17a4a72ffea176f77d6e2db609c6c919ef221f23862c9915e687fb54d833485" +"checksum cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d68987ed4c516dcc3e7913659bfa4076f5182eea4a7e0038bb060953e76ac" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" -"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" -"checksum gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)" = "c07c758b972368e703a562686adb39125707cc1ef3399da8c019fc6c2498a75d" +"checksum gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "40899336fb50db0c78710f53e87afc54d8c7266fb76262fecc78ca1a7f09deae" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" -"checksum handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b2249f6f0dc5a3bb2b3b1a8f797dfccbc4b053344d773d654ad565e51427d335" +"checksum handlebars 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)" = "663e1728d8037fb0d4e13bcd1b1909fb5d913690a9929eb385922df157c2ff8f" "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7291b1dd97d331f752620b02dfdbc231df7fc01bf282a00769e1cdb963c460dc" +"checksum lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4732c563b9a21a406565c4747daa7b46742f082911ae4753f390dc9ec7ee1a97" "checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" "checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" -"checksum mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "06a68e8738e42b38a02755d3ce5fa12d559e17acb238e4326cbc3cc056e65280" +"checksum mdbook 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "2598843aeda0c5bb2e8e4d714564f1c3fc40f7844157e34563bf96ae3866b56e" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" "checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3" "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842" "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8" +"checksum pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ab1e588ef8efd702c7ed9d2bd774db5e6f4d878bb5a1a9f371828fbdff6973" "checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" -"checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b" +"checksum rls-data 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af1dfff00189fd7b78edb9af131b0de703676c04fa8126aed77fd2c586775a4d" +"checksum rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8656f7b850ac85fb204ef94318c641bbb15a32766e12f9a589a23e4c0fbc38db" +"checksum rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "684ce48436d6465300c9ea783b6b14c4361d6b8dcbb1375b486a69cc19e2dfb0" "checksum serde 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)" = "a702319c807c016e51f672e5c77d6f0b46afddd744b5e437d6b8436b888b458f" "checksum serde_json 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)" = "dbc45439552eb8fb86907a2c41c1fd0ef97458efb87ff7f878db466eb581824e" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" @@ -1000,7 +1027,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" -"checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f" +"checksum vec_map 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8cdc8b93bd0198ed872357fb2e667f7125646b1762f16d60b2c96350d361897" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 2f7757fb1d..1ce99eb893 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -4,10 +4,6 @@ This is an in-progress README which is targeted at helping to explain how Rust is bootstrapped and in general some of the technical details of the build system. -> **Note**: This build system is currently under active development and is not -> intended to be the primarily used one just yet. The makefiles are currently -> the ones that are still "guaranteed to work" as much as possible at least. - ## Using rustbuild The rustbuild build system has a primary entry point, a top level `x.py` script: diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index a996240f61..62b7f6cb72 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -94,6 +94,13 @@ fn main() { cmd.arg("-Cprefer-dynamic"); } + // Pass the `rustbuild` feature flag to crates which rustbuild is + // building. See the comment in bootstrap/lib.rs where this env var is + // set for more details. + if env::var_os("RUSTBUILD_UNSTABLE").is_some() { + cmd.arg("--cfg").arg("rustbuild"); + } + // Help the libc crate compile by assisting it in finding the MUSL // native libraries. if let Some(s) = env::var_os("MUSL_ROOT") { @@ -182,7 +189,7 @@ fn main() { if env::var("RUSTC_RPATH") == Ok("true".to_string()) { let rpath = if target.contains("apple") { - // Note that we need to take one extra step on OSX to also pass + // Note that we need to take one extra step on macOS to also pass // `-Wl,-instal_name,@rpath/...` to get things to work right. To // do that we pass a weird flag to the compiler to get it to do // so. Note that this is definitely a hack, and we should likely diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index e9ca430f15..3a1a9c3e40 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -40,6 +40,14 @@ fn main() { .arg(sysroot) .env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + + // Pass the `rustbuild` feature flag to crates which rustbuild is + // building. See the comment in bootstrap/lib.rs where this env var is + // set for more details. + if env::var_os("RUSTBUILD_UNSTABLE").is_some() { + cmd.arg("--cfg").arg("rustbuild"); + } + 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 b326f95e50..6cd9496b7a 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -160,18 +160,16 @@ class RustBuild(object): def download_stage0(self): cache_dst = os.path.join(self.build_dir, "cache") rustc_cache = os.path.join(cache_dst, self.stage0_rustc_date()) - cargo_cache = os.path.join(cache_dst, self.stage0_cargo_rev()) if not os.path.exists(rustc_cache): os.makedirs(rustc_cache) - if not os.path.exists(cargo_cache): - os.makedirs(cargo_cache) + + channel = self.stage0_rustc_channel() if self.rustc().startswith(self.bin_root()) and \ (not os.path.exists(self.rustc()) or self.rustc_out_of_date()): self.print_what_it_means_to_bootstrap() if os.path.exists(self.bin_root()): shutil.rmtree(self.bin_root()) - channel = self.stage0_rustc_channel() filename = "rust-std-{}-{}.tar.gz".format(channel, self.build) url = "https://static.rust-lang.org/dist/" + self.stage0_rustc_date() tarball = os.path.join(rustc_cache, filename) @@ -192,18 +190,26 @@ class RustBuild(object): with open(self.rustc_stamp(), 'w') as f: f.write(self.stage0_rustc_date()) + if "pc-windows-gnu" in self.build: + filename = "rust-mingw-{}-{}.tar.gz".format(channel, self.build) + url = "https://static.rust-lang.org/dist/" + self.stage0_rustc_date() + tarball = os.path.join(rustc_cache, filename) + if not os.path.exists(tarball): + get("{}/{}".format(url, filename), tarball, verbose=self.verbose) + unpack(tarball, self.bin_root(), match="rust-mingw", verbose=self.verbose) + if self.cargo().startswith(self.bin_root()) and \ (not os.path.exists(self.cargo()) or self.cargo_out_of_date()): self.print_what_it_means_to_bootstrap() - filename = "cargo-nightly-{}.tar.gz".format(self.build) - url = "https://s3.amazonaws.com/rust-lang-ci/cargo-builds/" + self.stage0_cargo_rev() - tarball = os.path.join(cargo_cache, filename) + filename = "cargo-{}-{}.tar.gz".format('0.18.0', self.build) + url = "https://static.rust-lang.org/dist/" + self.stage0_rustc_date() + tarball = os.path.join(rustc_cache, filename) if not os.path.exists(tarball): get("{}/{}".format(url, filename), tarball, verbose=self.verbose) unpack(tarball, self.bin_root(), match="cargo", verbose=self.verbose) self.fix_executable(self.bin_root() + "/bin/cargo") with open(self.cargo_stamp(), 'w') as f: - f.write(self.stage0_cargo_rev()) + f.write(self.stage0_rustc_date()) def fix_executable(self, fname): # If we're on NixOS we need to change the path to the dynamic loader @@ -258,9 +264,6 @@ class RustBuild(object): print("warning: failed to call patchelf: %s" % e) return - def stage0_cargo_rev(self): - return self._cargo_rev - def stage0_rustc_date(self): return self._rustc_date @@ -283,7 +286,7 @@ class RustBuild(object): if not os.path.exists(self.cargo_stamp()) or self.clean: return True with open(self.cargo_stamp(), 'r') as f: - return self.stage0_cargo_rev() != f.read() + return self.stage0_rustc_date() != f.read() def bin_root(self): return os.path.join(self.build_dir, self.build, "stage0") @@ -401,14 +404,6 @@ class RustBuild(object): raise Exception(err) sys.exit(err) - # Darwin's `uname -s` lies and always returns i386. We have to use - # sysctl instead. - if ostype == 'Darwin' and cputype == 'i686': - args = ['sysctl', 'hw.optional.x86_64'] - sysctl = subprocess.check_output(args).decode(default_encoding) - if ': 1' in sysctl: - cputype = 'x86_64' - # The goal here is to come up with the same triple as LLVM would, # at least for the subset of platforms we're willing to target. if ostype == 'Linux': @@ -469,10 +464,10 @@ class RustBuild(object): cputype = 'i686' elif cputype in {'xscale', 'arm'}: cputype = 'arm' - elif cputype in {'armv6l', 'armv7l', 'armv8l'}: + elif cputype == 'armv6l': cputype = 'arm' ostype += 'eabihf' - elif cputype == 'armv7l': + elif cputype in {'armv7l', 'armv8l'}: cputype = 'armv7' ostype += 'eabihf' elif cputype == 'aarch64': @@ -578,7 +573,6 @@ def bootstrap(): data = stage0_data(rb.rust_root) rb._rustc_channel, rb._rustc_date = data['rustc'].split('-', 1) - rb._cargo_rev = data['cargo'] # Fetch/build the bootstrap rb.build = rb.build_triple() @@ -598,16 +592,19 @@ def bootstrap(): def main(): start_time = time() + help_triggered = ('-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1) try: bootstrap() - print("Build completed successfully in %s" % format_build_time(time() - start_time)) + if not help_triggered: + print("Build completed successfully in %s" % format_build_time(time() - start_time)) except (SystemExit, KeyboardInterrupt) as e: if hasattr(e, 'code') and isinstance(e.code, int): exit_code = e.code else: exit_code = 1 print(e) - print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time)) + if not help_triggered: + print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time)) sys.exit(exit_code) if __name__ == '__main__': diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index ef5bffebc7..966bb4dbfb 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -23,12 +23,12 @@ use build_helper::output; use Build; // The version number -pub const CFG_RELEASE_NUM: &'static str = "1.17.0"; +pub const CFG_RELEASE_NUM: &'static str = "1.18.0"; // An optional number to put after the label, e.g. '.2' -> '-beta.2' // Be sure to make this starts with a dot to conform to semver pre-release // versions (section 9) -pub const CFG_PRERELEASE_VERSION: &'static str = ".3"; +pub const CFG_PRERELEASE_VERSION: &'static str = ".4"; pub struct GitInfo { inner: Option, diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 68b3623a53..f8f641060c 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -176,7 +176,7 @@ pub fn compiletest(build: &Build, cmd.arg("--docck-python").arg(build.python()); if build.config.build.ends_with("apple-darwin") { - // Force /usr/bin/python on OSX for LLDB tests because we're loading the + // 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"); @@ -285,6 +285,16 @@ pub fn docs(build: &Build, compiler: &Compiler) { 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. + use std::ffi::OsStr; + let path: &OsStr = p.as_ref(); + if let Some(path) = path.to_str() { + if path.contains("nostarch") { + continue; + } + } + println!("doc tests for: {}", p.display()); markdown_test(build, compiler, &p); } @@ -576,7 +586,7 @@ fn android_copy_libs(build: &Build, compiler: &Compiler, target: &str) { .arg(ADB_TEST_DIR)); let target_dir = format!("{}/{}", ADB_TEST_DIR, target); - build.run(Command::new("adb").args(&["shell", "mkdir", &target_dir[..]])); + build.run(Command::new("adb").args(&["shell", "mkdir", &target_dir])); for f in t!(build.sysroot_libdir(compiler, target).read_dir()) { let f = t!(f); diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index a66ed46fe4..308a0ab307 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -22,9 +22,9 @@ use std::path::Path; use Build; pub fn clean(build: &Build) { - rm_rf(build, "tmp".as_ref()); - rm_rf(build, &build.out.join("tmp")); - rm_rf(build, &build.out.join("dist")); + rm_rf("tmp".as_ref()); + rm_rf(&build.out.join("tmp")); + rm_rf(&build.out.join("dist")); for host in build.config.host.iter() { let entries = match build.out.join(host).read_dir() { @@ -38,32 +38,31 @@ pub fn clean(build: &Build) { continue } let path = t!(entry.path().canonicalize()); - rm_rf(build, &path); + rm_rf(&path); } } } -fn rm_rf(build: &Build, path: &Path) { - if !path.exists() { - return - } - if path.is_file() { - return do_op(path, "remove file", |p| fs::remove_file(p)); - } - - for file in t!(fs::read_dir(path)) { - let file = t!(file).path(); +fn rm_rf(path: &Path) { + match path.symlink_metadata() { + Err(e) => { + if e.kind() == ErrorKind::NotFound { + return; + } + panic!("failed to get metadata for file {}: {}", path.display(), e); + }, + Ok(metadata) => { + if metadata.file_type().is_file() || metadata.file_type().is_symlink() { + do_op(path, "remove file", |p| fs::remove_file(p)); + return; + } - if file.is_dir() { - rm_rf(build, &file); - } else { - // On windows we can't remove a readonly file, and git will - // often clone files as readonly. As a result, we have some - // special logic to remove readonly files on windows. - do_op(&file, "remove file", |p| fs::remove_file(p)); - } - } - do_op(path, "remove dir", |p| fs::remove_dir(p)); + for file in t!(fs::read_dir(path)) { + rm_rf(&t!(file).path()); + } + do_op(path, "remove dir", |p| fs::remove_dir(p)); + }, + }; } fn do_op(path: &Path, desc: &str, mut f: F) @@ -71,9 +70,12 @@ fn do_op(path: &Path, desc: &str, mut f: F) { match f(path) { Ok(()) => {} + // On windows we can't remove a readonly file, and git will often clone files as readonly. + // As a result, we have some special logic to remove readonly files on windows. + // This is also the reason that we can't use things like fs::remove_dir_all(). Err(ref e) if cfg!(windows) && e.kind() == ErrorKind::PermissionDenied => { - let mut p = t!(path.metadata()).permissions(); + let mut p = t!(path.symlink_metadata()).permissions(); p.set_readonly(false); t!(fs::set_permissions(path, p)); f(path).unwrap_or_else(|e| { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index af1f43eb4c..cd87b27d4f 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -151,6 +151,7 @@ pub fn build_startup_objects(build: &Build, for_compiler: &Compiler, target: &st if !up_to_date(src_file, dst_file) { let mut cmd = Command::new(&compiler_path); build.run(cmd.env("RUSTC_BOOTSTRAP", "1") + .arg("--cfg").arg(format!("stage{}", compiler.stage)) .arg("--target").arg(target) .arg("--emit=obj") .arg("--out-dir").arg(dst_dir) @@ -258,7 +259,7 @@ pub fn rustc(build: &Build, target: &str, compiler: &Compiler) { cargo.env("CFG_LLVM_ROOT", s); } // Building with a static libstdc++ is only supported on linux right now, - // not for MSVC or OSX + // not for MSVC or macOS if build.config.llvm_static_stdcpp && !target.contains("windows") && !target.contains("apple") { @@ -275,6 +276,7 @@ pub fn rustc(build: &Build, target: &str, compiler: &Compiler) { cargo.env("CFG_DEFAULT_AR", s); } build.run(&mut cargo); + update_mtime(build, &librustc_stamp(build, compiler, target)); } /// Same as `std_link`, only for librustc @@ -305,6 +307,12 @@ fn libtest_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp") } +/// Cargo's output path for librustc in a given stage, compiled by a particular +/// compiler for the specified target. +fn librustc_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { + build.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp") +} + fn compiler_file(compiler: &Path, file: &str) -> PathBuf { let out = output(Command::new(compiler) .arg(format!("-print-file-name={}", file))); @@ -407,6 +415,23 @@ fn add_to_sysroot(out_dir: &Path, sysroot_dst: &Path) { } } +/// Build a tool in `src/tools` +/// +/// This will build the specified tool with the specified `host` compiler in +/// `stage` into the normal cargo output directory. +pub fn maybe_clean_tools(build: &Build, stage: u32, target: &str, mode: Mode) { + let compiler = Compiler::new(stage, &build.config.build); + + let stamp = match mode { + Mode::Libstd => libstd_stamp(build, &compiler, target), + Mode::Libtest => libtest_stamp(build, &compiler, target), + Mode::Librustc => librustc_stamp(build, &compiler, target), + _ => panic!(), + }; + let out_dir = build.cargo_out(&compiler, Mode::Tool, target); + build.clear_if_dirty(&out_dir, &stamp); +} + /// Build a tool in `src/tools` /// /// This will build the specified tool with the specified `host` compiler in @@ -416,15 +441,6 @@ pub fn tool(build: &Build, stage: u32, target: &str, tool: &str) { let compiler = Compiler::new(stage, &build.config.build); - // FIXME: need to clear out previous tool and ideally deps, may require - // isolating output directories or require a pseudo shim step to - // clear out all the info. - // - // Maybe when libstd is compiled it should clear out the rustc of the - // corresponding stage? - // let out_dir = build.cargo_out(stage, &host, Mode::Librustc, target); - // build.clear_if_dirty(&out_dir, &libstd_stamp(build, stage, &host, target)); - let mut cargo = build.cargo(&compiler, Mode::Tool, target, "build"); let mut dir = build.src.join(tool); if !dir.exists() { diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index dcd49c51e3..34fbc33d98 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -23,7 +23,7 @@ use std::process; use num_cpus; use rustc_serialize::Decodable; use toml::{Parser, Decoder, Value}; -use util::push_exe_path; +use util::{exe, push_exe_path}; /// Global configuration for the entire build and/or bootstrap. /// @@ -570,6 +570,12 @@ impl Config { .or_insert(Target::default()); target.ndk = Some(parse_configure_path(value)); } + "CFG_X86_64_LINUX_ANDROID_NDK" if value.len() > 0 => { + let target = "x86_64-linux-android".to_string(); + let target = self.target_config.entry(target) + .or_insert(Target::default()); + target.ndk = Some(parse_configure_path(value)); + } "CFG_LOCAL_RUST_ROOT" if value.len() > 0 => { let path = parse_configure_path(value); self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"])); @@ -580,10 +586,10 @@ impl Config { self.python = Some(path); } "CFG_ENABLE_CCACHE" if value == "1" => { - self.ccache = Some("ccache".to_string()); + self.ccache = Some(exe("ccache", &self.build)); } "CFG_ENABLE_SCCACHE" if value == "1" => { - self.ccache = Some("sccache".to_string()); + self.ccache = Some(exe("sccache", &self.build)); } "CFG_CONFIGURE_ARGS" if value.len() > 0 => { self.configure_args = value.split_whitespace() diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 5a00e90f37..fad7902204 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -88,11 +88,11 @@ # for each target triple. #target = ["x86_64-unknown-linux-gnu"] # defaults to just the build triple -# Instead of downloading the src/nightlies.txt version of Cargo specified, use +# Instead of downloading the src/stage0.txt version of Cargo specified, use # this Cargo binary instead to build all Rust code #cargo = "/path/to/bin/cargo" -# Instead of downloading the src/nightlies.txt version of the compiler +# Instead of downloading the src/stage0.txt version of the compiler # specified, use this rustc binary instead as the stage0 snapshot compiler. #rustc = "/path/to/bin/rustc" diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 9119b00d6d..4328c4e3f1 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -39,6 +39,8 @@ use util::{cp_r, libdir, is_dylib, cp_filtered, copy, exe}; fn pkgname(build: &Build, component: &str) -> String { if component == "cargo" { format!("{}-{}", component, build.cargo_package_vers()) + } else if component == "rls" { + format!("{}-{}", component, build.package_vers(&build.release_num("rls"))) } else { assert!(component.starts_with("rust")); format!("{}-{}", component, build.rust_package_vers()) @@ -315,19 +317,12 @@ pub fn rust_src_location(build: &Build) -> PathBuf { /// Creates a tarball of save-analysis metadata, if available. pub fn analysis(build: &Build, compiler: &Compiler, target: &str) { + assert!(build.config.extended); println!("Dist analysis"); - if build.config.channel != "nightly" { - println!("\tskipping - not on nightly channel"); - return; - } if compiler.host != build.config.build { - println!("\tskipping - not a build host"); - return - } - if compiler.stage != 2 { - println!("\tskipping - not stage2"); - return + println!("\tskipping, not a build host"); + return; } // Package save-analysis from stage1 if not doing a full bootstrap, as the @@ -397,6 +392,7 @@ pub fn rust_src(build: &Build) { "man", "src", "cargo", + "rls", ]; let filter_fn = move |path: &Path| { @@ -543,7 +539,7 @@ pub fn cargo(build: &Build, stage: u32, target: &str) { let src = build.src.join("cargo"); let etc = src.join("src/etc"); - let release_num = build.cargo_release_num(); + let release_num = build.release_num("cargo"); let name = pkgname(build, "cargo"); let version = build.cargo_info.version(build, &release_num); @@ -597,6 +593,55 @@ pub fn cargo(build: &Build, stage: u32, target: &str) { build.run(&mut cmd); } +pub fn rls(build: &Build, stage: u32, target: &str) { + assert!(build.config.extended); + println!("Dist RLS stage{} ({})", stage, target); + let compiler = Compiler::new(stage, &build.config.build); + + let src = build.src.join("rls"); + let release_num = build.release_num("rls"); + let name = pkgname(build, "rls"); + let version = build.rls_info.version(build, &release_num); + + let tmp = tmpdir(build); + let image = tmp.join("rls-image"); + drop(fs::remove_dir_all(&image)); + t!(fs::create_dir_all(&image)); + + // Prepare the image directory + let rls = build.cargo_out(&compiler, Mode::Tool, target) + .join(exe("rls", target)); + install(&rls, &image.join("bin"), 0o755); + let doc = image.join("share/doc/rls"); + install(&src.join("README.md"), &doc, 0o644); + install(&src.join("LICENSE-MIT"), &doc, 0o644); + install(&src.join("LICENSE-APACHE"), &doc, 0o644); + + // Prepare the overlay + let overlay = tmp.join("rls-overlay"); + drop(fs::remove_dir_all(&overlay)); + t!(fs::create_dir_all(&overlay)); + install(&src.join("README.md"), &overlay, 0o644); + install(&src.join("LICENSE-MIT"), &overlay, 0o644); + install(&src.join("LICENSE-APACHE"), &overlay, 0o644); + t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes())); + + // Generate the installer tarball + let mut cmd = Command::new("sh"); + cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh"))) + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=RLS-ready-to-serve.") + .arg(format!("--image-dir={}", sanitize_sh(&image))) + .arg(format!("--work-dir={}", sanitize_sh(&tmpdir(build)))) + .arg(format!("--output-dir={}", sanitize_sh(&distdir(build)))) + .arg(format!("--non-installed-overlay={}", sanitize_sh(&overlay))) + .arg(format!("--package-name={}-{}", name, target)) + .arg("--component-name=rls") + .arg("--legacy-manifest-dirs=rustlib,cargo"); + build.run(&mut cmd); +} + /// Creates a combined installer for the specified target in the provided stage. pub fn extended(build: &Build, stage: u32, target: &str) { println!("Dist extended stage{} ({})", stage, target); @@ -608,6 +653,12 @@ pub fn extended(build: &Build, stage: u32, target: &str) { let cargo_installer = dist.join(format!("{}-{}.tar.gz", pkgname(build, "cargo"), target)); + let rls_installer = dist.join(format!("{}-{}.tar.gz", + pkgname(build, "rls"), + target)); + let analysis_installer = dist.join(format!("{}-{}.tar.gz", + pkgname(build, "rust-analysis"), + target)); let docs_installer = dist.join(format!("{}-{}.tar.gz", pkgname(build, "rust-docs"), target)); @@ -635,9 +686,11 @@ pub fn extended(build: &Build, stage: u32, target: &str) { // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering // the std files during uninstall. To do this ensure that rustc comes // before rust-std in the list below. - let mut input_tarballs = format!("{},{},{},{}", + let mut input_tarballs = format!("{},{},{},{},{},{}", sanitize_sh(&rustc_installer), sanitize_sh(&cargo_installer), + sanitize_sh(&rls_installer), + sanitize_sh(&analysis_installer), sanitize_sh(&docs_installer), sanitize_sh(&std_installer)); if target.contains("pc-windows-gnu") { @@ -950,7 +1003,8 @@ pub fn hash_and_sign(build: &Build) { cmd.arg(distdir(build)); cmd.arg(today.trim()); cmd.arg(build.rust_package_vers()); - cmd.arg(build.package_vers(&build.cargo_release_num())); + cmd.arg(build.package_vers(&build.release_num("cargo"))); + cmd.arg(build.package_vers(&build.release_num("rls"))); cmd.arg(addr); t!(fs::create_dir_all(distdir(build))); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index db8ed579ce..baee1ada50 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -53,6 +53,82 @@ pub fn rustbook(build: &Build, target: &str, name: &str) { .arg(out)); } +/// Build the book and associated stuff. +/// +/// We need to build: +/// +/// * Book (first edition) +/// * Book (second edition) +/// * Index page +/// * Redirect pages +pub fn book(build: &Build, target: &str, name: &str) { + // build book first edition + rustbook(build, target, &format!("{}/first-edition", name)); + + // build book second edition + rustbook(build, target, &format!("{}/second-edition", name)); + + // build the index page + let index = format!("{}/index.md", name); + println!("Documenting book index ({})", target); + invoke_rustdoc(build, target, &index); + + // build the redirect pages + println!("Documenting book redirect pages ({})", target); + for file in t!(fs::read_dir(build.src.join("src/doc/book/redirects"))) { + let file = t!(file); + let path = file.path(); + let path = path.to_str().unwrap(); + + invoke_rustdoc(build, target, path); + } +} + +fn invoke_rustdoc(build: &Build, target: &str, markdown: &str) { + let out = build.doc_out(target); + + let compiler = Compiler::new(0, &build.config.build); + + let path = build.src.join("src/doc").join(markdown); + + let rustdoc = build.rustdoc(&compiler); + + let favicon = build.src.join("src/doc/favicon.inc"); + let footer = build.src.join("src/doc/footer.inc"); + + let version_input = build.src.join("src/doc/version_info.html.template"); + let version_info = out.join("version_info.html"); + + if !up_to_date(&version_input, &version_info) { + let mut info = String::new(); + t!(t!(File::open(&version_input)).read_to_string(&mut info)); + let info = info.replace("VERSION", &build.rust_release()) + .replace("SHORT_HASH", build.rust_info.sha_short().unwrap_or("")) + .replace("STAMP", build.rust_info.sha().unwrap_or("")); + t!(t!(File::create(&version_info)).write_all(info.as_bytes())); + } + + let mut cmd = Command::new(&rustdoc); + + build.add_rustc_lib_path(&compiler, &mut cmd); + + let out = out.join("book"); + + t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css"))); + + cmd.arg("--html-after-content").arg(&footer) + .arg("--html-before-content").arg(&version_info) + .arg("--html-in-header").arg(&favicon) + .arg("--markdown-playground-url") + .arg("https://play.rust-lang.org/") + .arg("-o").arg(&out) + .arg(&path) + .arg("--markdown-css") + .arg("rust.css"); + + build.run(&mut cmd); +} + /// Generates all standalone documentation as compiled by the rustdoc in `stage` /// for the `target` into `out`. /// diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index b55f3d710c..a1466d68a1 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -18,7 +18,7 @@ use std::fs; use std::path::PathBuf; use std::process; -use getopts::{Matches, Options}; +use getopts::Options; use Build; use config::Config; @@ -75,7 +75,22 @@ pub enum Subcommand { impl Flags { pub fn parse(args: &[String]) -> Flags { + let mut extra_help = String::new(); + let mut subcommand_help = format!("\ +Usage: x.py [options] [...] + +Subcommands: + build Compile either the compiler or libraries + test Build and run some test suites + bench Build and run some benchmarks + doc Build documentation + clean Clean out build directories + dist Build and/or install distribution artifacts + +To learn more about a subcommand, run `./x.py -h`"); + let mut opts = Options::new(); + // Options common to all subcommands opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)"); opts.optflag("i", "incremental", "use incremental compilation"); opts.optopt("", "config", "TOML configuration file for build", "FILE"); @@ -89,21 +104,83 @@ impl Flags { opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); opts.optflag("h", "help", "print this help message"); - let usage = |n, opts: &Options| -> ! { - let command = args.get(0).map(|s| &**s); - let brief = format!("Usage: x.py {} [options] [...]", - command.unwrap_or("")); + // fn usage() + let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! { + println!("{}", opts.usage(subcommand_help)); + if !extra_help.is_empty() { + println!("{}", extra_help); + } + process::exit(exit_code); + }; + + // We can't use getopt to parse the options until we have completed specifying which + // options are valid, but under the current implementation, some options are conditional on + // the subcommand. Therefore we must manually identify the subcommand first, so that we can + // complete the definition of the options. Then we can use the getopt::Matches object from + // there on out. + let mut possible_subcommands = args.iter().collect::>(); + possible_subcommands.retain(|&s| + (s == "build") + || (s == "test") + || (s == "bench") + || (s == "doc") + || (s == "clean") + || (s == "dist")); + let subcommand = match possible_subcommands.first() { + Some(s) => s, + None => { + // No subcommand -- show the general usage and subcommand help + println!("{}\n", subcommand_help); + process::exit(0); + } + }; - println!("{}", opts.usage(&brief)); - match command { - Some("build") => { - println!("\ + // Some subcommands get extra options + match subcommand.as_str() { + "test" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, + "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, + "dist" => { opts.optflag("", "install", "run installer as well"); }, + _ => { }, + }; + + // Done specifying what options are possible, so do the getopts parsing + let matches = opts.parse(&args[..]).unwrap_or_else(|e| { + // Invalid argument/option format + println!("\n{}\n", e); + usage(1, &opts, &subcommand_help, &extra_help); + }); + // Extra sanity check to make sure we didn't hit this crazy corner case: + // + // ./x.py --frobulate clean build + // ^-- option ^ ^- actual subcommand + // \_ arg to option could be mistaken as subcommand + let mut pass_sanity_check = true; + match matches.free.get(0) { + Some(check_subcommand) => { + if &check_subcommand != subcommand { + pass_sanity_check = false; + } + }, + None => { + pass_sanity_check = false; + } + } + if !pass_sanity_check { + println!("{}\n", subcommand_help); + println!("Sorry, I couldn't figure out which subcommand you were trying to specify.\n\ + You may need to move some options to after the subcommand.\n"); + process::exit(1); + } + // Extra help text for some commands + match subcommand.as_str() { + "build" => { + subcommand_help.push_str("\n Arguments: - This subcommand accepts a number of positional arguments of directories to - the crates and/or artifacts to compile. For example: + This subcommand accepts a number of paths to directories to the crates + and/or artifacts to compile. For example: ./x.py build src/libcore - ./x.py build src/libproc_macro + ./x.py build src/libcore src/libproc_macro ./x.py build src/libstd --stage 1 If no arguments are passed then the complete artifacts for that stage are @@ -114,15 +191,13 @@ Arguments: For a quick build with a usable compile, you can pass: - ./x.py build --stage 1 src/libtest -"); - } - - Some("test") => { - println!("\ + ./x.py build --stage 1 src/libtest"); + } + "test" => { + subcommand_help.push_str("\n Arguments: - This subcommand accepts a number of positional arguments of directories to - tests that should be compiled and run. For example: + This subcommand accepts a number of paths to directories to tests that + should be compiled and run. For example: ./x.py test src/test/run-pass ./x.py test src/libstd --test-args hash_map @@ -132,139 +207,90 @@ Arguments: compiled and tested. ./x.py test - ./x.py test --stage 1 -"); - } - - Some("doc") => { - println!("\ + ./x.py test --stage 1"); + } + "doc" => { + subcommand_help.push_str("\n Arguments: - This subcommand accepts a number of positional arguments of directories of - documentation to build. For example: + This subcommand accepts a number of paths to directories of documentation + to build. For example: ./x.py doc src/doc/book ./x.py doc src/doc/nomicon - ./x.py doc src/libstd + ./x.py doc src/doc/book src/libstd If no arguments are passed then everything is documented: ./x.py doc - ./x.py doc --stage 1 -"); - } - - _ => {} + ./x.py doc --stage 1"); } - - if let Some(command) = command { - if command == "build" || - command == "dist" || - command == "doc" || - command == "test" || - command == "bench" || - command == "clean" { - println!("Available invocations:"); - if args.iter().any(|a| a == "-v") { - let flags = Flags::parse(&["build".to_string()]); - let mut config = Config::default(); - config.build = flags.build.clone(); - let mut build = Build::new(flags, config); - metadata::build(&mut build); - step::build_rules(&build).print_help(command); - } else { - println!(" ... elided, run `./x.py {} -h -v` to see", - command); - } - - println!(""); - } - } - -println!("\ -Subcommands: - build Compile either the compiler or libraries - test Build and run some test suites - bench Build and run some benchmarks - doc Build documentation - clean Clean out build directories - dist Build and/or install distribution artifacts - -To learn more about a subcommand, run `./x.py -h` -"); - - process::exit(n); + _ => { } }; - if args.len() == 0 { - println!("a command must be passed"); - usage(1, &opts); - } - let parse = |opts: &Options| { - let m = opts.parse(&args[1..]).unwrap_or_else(|e| { - println!("failed to parse options: {}", e); - usage(1, opts); - }); - if m.opt_present("h") { - usage(0, opts); + // 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::>(); + + + // All subcommands can have an optional "Available paths" section + if matches.opt_present("verbose") { + let flags = Flags::parse(&["build".to_string()]); + let mut config = Config::default(); + config.build = flags.build.clone(); + let mut build = Build::new(flags, config); + metadata::build(&mut build); + let maybe_rules_help = step::build_rules(&build).get_help(subcommand); + if maybe_rules_help.is_some() { + extra_help.push_str(maybe_rules_help.unwrap().as_str()); } - return m - }; + } else { + extra_help.push_str(format!("Run `./x.py {} -h -v` to see a list of available paths.", + subcommand).as_str()); + } - let cwd = t!(env::current_dir()); - let remaining_as_path = |m: &Matches| { - m.free.iter().map(|p| cwd.join(p)).collect::>() - }; + // User passed in -h/--help? + if matches.opt_present("help") { + usage(0, &opts, &subcommand_help, &extra_help); + } - let m: Matches; - let cmd = match &args[0][..] { + let cmd = match subcommand.as_str() { "build" => { - m = parse(&opts); - Subcommand::Build { paths: remaining_as_path(&m) } - } - "doc" => { - m = parse(&opts); - Subcommand::Doc { paths: remaining_as_path(&m) } + Subcommand::Build { paths: paths } } "test" => { - opts.optmulti("", "test-args", "extra arguments", "ARGS"); - m = parse(&opts); Subcommand::Test { - paths: remaining_as_path(&m), - test_args: m.opt_strs("test-args"), + paths: paths, + test_args: matches.opt_strs("test-args"), } } "bench" => { - opts.optmulti("", "test-args", "extra arguments", "ARGS"); - m = parse(&opts); Subcommand::Bench { - paths: remaining_as_path(&m), - test_args: m.opt_strs("test-args"), + paths: paths, + test_args: matches.opt_strs("test-args"), } } + "doc" => { + Subcommand::Doc { paths: paths } + } "clean" => { - m = parse(&opts); - if m.free.len() > 0 { - println!("clean takes no arguments"); - usage(1, &opts); + if paths.len() > 0 { + println!("\nclean takes no arguments\n"); + usage(1, &opts, &subcommand_help, &extra_help); } Subcommand::Clean } "dist" => { - opts.optflag("", "install", "run installer as well"); - m = parse(&opts); Subcommand::Dist { - paths: remaining_as_path(&m), - install: m.opt_present("install"), + paths: paths, + install: matches.opt_present("install"), } } - "--help" => usage(0, &opts), - cmd => { - println!("unknown command: {}", cmd); - usage(1, &opts); + _ => { + usage(1, &opts, &subcommand_help, &extra_help); } }; - let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| { + let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| { if fs::metadata("config.toml").is_ok() { Some(PathBuf::from("config.toml")) } else { @@ -272,31 +298,29 @@ To learn more about a subcommand, run `./x.py -h` } }); - let mut stage = m.opt_str("stage").map(|j| j.parse().unwrap()); - - let incremental = m.opt_present("i"); + let mut stage = matches.opt_str("stage").map(|j| j.parse().unwrap()); - if incremental { + if matches.opt_present("incremental") { if stage.is_none() { stage = Some(1); } } Flags { - verbose: m.opt_count("v"), + verbose: matches.opt_count("verbose"), stage: stage, - on_fail: m.opt_str("on-fail"), - keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()), - build: m.opt_str("build").unwrap_or_else(|| { + on_fail: matches.opt_str("on-fail"), + keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()), + build: matches.opt_str("build").unwrap_or_else(|| { env::var("BUILD").unwrap() }), - host: split(m.opt_strs("host")), - target: split(m.opt_strs("target")), + host: split(matches.opt_strs("host")), + target: split(matches.opt_strs("target")), config: cfg_file, - src: m.opt_str("src").map(PathBuf::from), - jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()), + src: matches.opt_str("src").map(PathBuf::from), + jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()), cmd: cmd, - incremental: incremental, + incremental: matches.opt_present("incremental"), } } } diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index ba8442ebd8..d508616e4b 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -49,8 +49,12 @@ pub fn install(build: &Build, stage: u32, host: &str) { install_sh(&build, "docs", "rust-docs", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); } - install_sh(&build, "std", "rust-std", stage, host, &prefix, - &docdir, &libdir, &mandir, &empty_dir); + + for target in build.config.target.iter() { + install_sh(&build, "std", "rust-std", stage, target, &prefix, + &docdir, &libdir, &mandir, &empty_dir); + } + install_sh(&build, "rustc", "rustc", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); t!(fs::remove_dir_all(&empty_dir)); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 39cfdfdd6f..5e046f4167 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -151,6 +151,7 @@ pub struct Build { out: PathBuf, rust_info: channel::GitInfo, cargo_info: channel::GitInfo, + rls_info: channel::GitInfo, local_rebuild: bool, // Probed tools at runtime @@ -181,7 +182,7 @@ struct Crate { /// /// These entries currently correspond to the various output directories of the /// build system, with each mod generating output in a different directory. -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Eq)] pub enum Mode { /// This cargo is going to build the standard library, placing output in the /// "stageN-std" directory. @@ -234,6 +235,7 @@ impl Build { }; let rust_info = channel::GitInfo::new(&src); let cargo_info = channel::GitInfo::new(&src.join("cargo")); + let rls_info = channel::GitInfo::new(&src.join("rls")); let src_is_git = src.join(".git").exists(); Build { @@ -246,6 +248,7 @@ impl Build { rust_info: rust_info, cargo_info: cargo_info, + rls_info: rls_info, local_rebuild: local_rebuild, cc: HashMap::new(), cxx: HashMap::new(), @@ -496,7 +499,7 @@ impl Build { // For other crates, however, we know that we've already got a standard // library up and running, so we can use the normal compiler to compile // build scripts in that situation. - if let Mode::Libstd = mode { + if mode == Mode::Libstd { cargo.env("RUSTC_SNAPSHOT", &self.rustc) .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir()); } else { @@ -504,6 +507,27 @@ impl Build { .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler)); } + // There are two invariants we try must maintain: + // * stable crates cannot depend on unstable crates (general Rust rule), + // * crates that end up in the sysroot must be unstable (rustbuild rule). + // + // In order to do enforce the latter, we pass the env var + // `RUSTBUILD_UNSTABLE` down the line for any crates which will end up + // in the sysroot. We read this in bootstrap/bin/rustc.rs and if it is + // set, then we pass the `rustbuild` feature to rustc when building the + // the crate. + // + // In turn, crates that can be used here should recognise the `rustbuild` + // feature and opt-in to `rustc_private`. + // + // We can't always pass `rustbuild` because crates which are outside of + // the comipiler, libs, and tests are stable and we don't want to make + // their deps unstable (since this would break the first invariant + // above). + if mode != Mode::Tool { + cargo.env("RUSTBUILD_UNSTABLE", "1"); + } + // Ignore incremental modes except for stage0, since we're // not guaranteeing correctness acros builds if the compiler // is changing under your feet.` @@ -529,7 +553,7 @@ impl Build { .env(format!("CFLAGS_{}", target), self.cflags(target).join(" ")); } - if self.config.channel == "nightly" && compiler.is_final_stage(self) { + if self.config.extended && compiler.is_final_stage(self) { cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string()); } @@ -851,7 +875,7 @@ impl Build { .filter(|s| !s.starts_with("-O") && !s.starts_with("/O")) .collect::>(); - // If we're compiling on OSX then we add a few unconditional flags + // If we're compiling on macOS then we add a few unconditional flags // indicating that we want libc++ (more filled out than libstdc++) and // we want to compile for 10.7. This way we can ensure that // LLVM/jemalloc/etc are all properly compiled. @@ -1001,7 +1025,7 @@ impl Build { /// Returns the value of `package_vers` above for Cargo fn cargo_package_vers(&self) -> String { - self.package_vers(&self.cargo_release_num()) + self.package_vers(&self.release_num("cargo")) } /// Returns the `version` string associated with this compiler for Rust @@ -1013,10 +1037,11 @@ impl Build { self.rust_info.version(self, channel::CFG_RELEASE_NUM) } - /// Returns the `a.b.c` version that Cargo is at. - fn cargo_release_num(&self) -> String { + /// Returns the `a.b.c` version that the given package is at. + fn release_num(&self, package: &str) -> String { let mut toml = String::new(); - t!(t!(File::open(self.src.join("cargo/Cargo.toml"))).read_to_string(&mut toml)); + let toml_file_name = self.src.join(&format!("{}/Cargo.toml", package)); + t!(t!(File::open(toml_file_name)).read_to_string(&mut toml)); for line in toml.lines() { let prefix = "version = \""; let suffix = "\""; @@ -1025,7 +1050,7 @@ impl Build { } } - panic!("failed to find version in cargo's Cargo.toml") + panic!("failed to find version in {}'s Cargo.toml", package) } /// Returns whether unstable features should be enabled for the compiler diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 6cc1ca8d02..3a95aec388 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -18,6 +18,7 @@ //! LLVM and compiler-rt are essentially just wired up to everything else to //! ensure that they're always in place if needed. +use std::env; use std::fs::{self, File}; use std::io::{Read, Write}; use std::path::Path; @@ -145,6 +146,10 @@ pub fn llvm(build: &Build, target: &str) { cfg.define("CMAKE_CXX_FLAGS", build.cflags(target).join(" ")); } + if env::var_os("SCCACHE_ERROR_LOG").is_some() { + cfg.env("RUST_LOG", "sccache=info"); + } + // FIXME: we don't actually need to build all LLVM tools and all LLVM // libraries here, e.g. we just want a few components and a few // tools. Figure out how to filter them down and only build the right @@ -222,9 +227,24 @@ pub fn openssl(build: &Build, target: &str) { let tarball = out.join(&name); if !tarball.exists() { let tmp = tarball.with_extension("tmp"); - build.run(Command::new("curl") - .arg("-o").arg(&tmp) - .arg(format!("https://www.openssl.org/source/{}", name))); + // originally from https://www.openssl.org/source/... + let url = format!("https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/{}", + name); + let mut ok = false; + for _ in 0..3 { + let status = Command::new("curl") + .arg("-o").arg(&tmp) + .arg(&url) + .status() + .expect("failed to spawn curl"); + if status.success() { + ok = true; + break + } + } + if !ok { + panic!("failed to download openssl source") + } let mut shasum = if target.contains("apple") { let mut cmd = Command::new("shasum"); cmd.arg("-a").arg("256"); @@ -286,7 +306,7 @@ pub fn openssl(build: &Build, target: &str) { println!("Configuring openssl for {}", target); build.run_quiet(&mut configure); println!("Building openssl for {}", target); - build.run_quiet(Command::new("make").current_dir(&obj)); + build.run_quiet(Command::new("make").arg("-j1").current_dir(&obj)); println!("Installing openssl for {}", target); build.run_quiet(Command::new("make").arg("install").current_dir(&obj)); diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 251362a76c..d1b235f469 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -151,10 +151,10 @@ pub fn check(build: &mut Build) { } for target in build.config.target.iter() { - // Can't compile for iOS unless we're on OSX + // Can't compile for iOS unless we're on macOS if target.contains("apple-ios") && !build.config.build.contains("apple-darwin") { - panic!("the iOS target is only supported on OSX"); + panic!("the iOS target is only supported on macOS"); } // Make sure musl-root is valid if specified diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 6b047c62d9..17902a39df 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -26,7 +26,7 @@ //! along with the actual implementation elsewhere. You can find more comments //! about how to define rules themselves below. -use std::collections::{BTreeMap, HashSet}; +use std::collections::{BTreeMap, HashSet, HashMap}; use std::mem; use check::{self, TestKind}; @@ -137,7 +137,9 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { while let Some(krate) = list.pop() { let default = krate == name; let krate = &build.crates[krate]; - let path = krate.path.strip_prefix(&build.src).unwrap(); + let path = krate.path.strip_prefix(&build.src) + // This handles out of tree paths + .unwrap_or(&krate.path); ret.push((krate, path.to_str().unwrap(), default)); for dep in krate.deps.iter() { if visited.insert(dep) && dep != "build_helper" { @@ -533,34 +535,44 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { // // Tools used during the build system but not shipped rules.build("tool-rustbook", "src/tools/rustbook") - .dep(|s| s.name("librustc")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("librustc-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "rustbook")); rules.build("tool-error-index", "src/tools/error_index_generator") - .dep(|s| s.name("librustc")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("librustc-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "error_index_generator")); rules.build("tool-tidy", "src/tools/tidy") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "tidy")); rules.build("tool-linkchecker", "src/tools/linkchecker") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "linkchecker")); rules.build("tool-cargotest", "src/tools/cargotest") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "cargotest")); rules.build("tool-compiletest", "src/tools/compiletest") - .dep(|s| s.name("libtest")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libtest-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "compiletest")); rules.build("tool-build-manifest", "src/tools/build-manifest") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "build-manifest")); rules.build("tool-qemu-test-server", "src/tools/qemu-test-server") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "qemu-test-server")); rules.build("tool-qemu-test-client", "src/tools/qemu-test-client") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "qemu-test-client")); rules.build("tool-cargo", "cargo") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .dep(|s| s.stage(0).host(s.target).name("openssl")) .dep(move |s| { // Cargo depends on procedural macros, which requires a full host @@ -570,6 +582,36 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .host(&build.config.build) }) .run(move |s| compile::tool(build, s.stage, s.target, "cargo")); + rules.build("tool-rls", "rls") + .host(true) + .dep(|s| s.name("librustc-tool")) + .dep(|s| s.stage(0).host(s.target).name("openssl")) + .dep(move |s| { + // rls, like cargo, uses procedural macros + s.name("librustc-link") + .target(&build.config.build) + .host(&build.config.build) + }) + .run(move |s| compile::tool(build, s.stage, s.target, "rls")); + + // "pseudo rule" which represents completely cleaning out the tools dir in + // one stage. This needs to happen whenever a dependency changes (e.g. + // libstd, libtest, librustc) and all of the tool compilations above will + // be sequenced after this rule. + rules.build("maybe-clean-tools", "path/to/nowhere") + .after("librustc-tool") + .after("libtest-tool") + .after("libstd-tool"); + + rules.build("librustc-tool", "path/to/nowhere") + .dep(|s| s.name("librustc")) + .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Librustc)); + rules.build("libtest-tool", "path/to/nowhere") + .dep(|s| s.name("libtest")) + .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Libtest)); + rules.build("libstd-tool", "path/to/nowhere") + .dep(|s| s.name("libstd")) + .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Libstd)); // ======================================================================== // Documentation targets @@ -581,7 +623,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .stage(0) }) .default(build.config.docs) - .run(move |s| doc::rustbook(build, s.target, "book")); + .run(move |s| doc::book(build, s.target, "book")); rules.doc("doc-nomicon", "src/doc/nomicon") .dep(move |s| { s.name("tool-rustbook") @@ -690,10 +732,15 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|s| s.name("default:doc")) .run(move |s| dist::docs(build, s.stage, s.target)); rules.dist("dist-analysis", "analysis") + .default(build.config.extended) .dep(|s| s.name("dist-std")) - .default(true) .only_host_build(true) .run(move |s| dist::analysis(build, &s.compiler(), s.target)); + rules.dist("dist-rls", "rls") + .host(true) + .only_host_build(true) + .dep(|s| s.name("tool-rls")) + .run(move |s| dist::rls(build, s.stage, s.target)); rules.dist("install", "path/to/nowhere") .dep(|s| s.name("default:dist")) .run(move |s| install::install(build, s.stage, s.target)); @@ -711,6 +758,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|d| d.name("dist-mingw")) .dep(|d| d.name("dist-docs")) .dep(|d| d.name("dist-cargo")) + .dep(|d| d.name("dist-rls")) + .dep(|d| d.name("dist-analysis")) .run(move |s| dist::extended(build, s.stage, s.target)); rules.dist("dist-sign", "hash-and-sign") @@ -811,6 +860,11 @@ struct Rule<'a> { /// Whether this rule is only for the build triple, not anything in hosts or /// targets. only_build: bool, + + /// A list of "order only" dependencies. This rules does not actually + /// depend on these rules, but if they show up in the dependency graph then + /// this rule must be executed after all these rules. + after: Vec<&'a str>, } #[derive(PartialEq)] @@ -834,6 +888,7 @@ impl<'a> Rule<'a> { host: false, only_host_build: false, only_build: false, + after: Vec::new(), } } } @@ -853,6 +908,11 @@ impl<'a, 'b> RuleBuilder<'a, 'b> { self } + fn after(&mut self, step: &'a str) -> &mut Self { + self.rule.after.push(step); + self + } + fn run(&mut self, f: F) -> &mut Self where F: Fn(&Step<'a>) + 'a, { @@ -978,26 +1038,25 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? } } - pub fn print_help(&self, command: &str) { + pub fn get_help(&self, command: &str) -> Option { let kind = match command { "build" => Kind::Build, "doc" => Kind::Doc, "test" => Kind::Test, "bench" => Kind::Bench, "dist" => Kind::Dist, - _ => return, + _ => return None, }; let rules = self.rules.values().filter(|r| r.kind == kind); let rules = rules.filter(|r| !r.path.contains("nowhere")); let mut rules = rules.collect::>(); rules.sort_by_key(|r| r.path); - println!("Available paths:\n"); + let mut help_string = String::from("Available paths:\n"); for rule in rules { - print!(" ./x.py {} {}", command, rule.path); - - println!(""); + help_string.push_str(format!(" ./x.py {} {}\n", command, rule.path).as_str()); } + Some(help_string) } /// Construct the top-level build steps that we're going to be executing, @@ -1137,31 +1196,52 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? /// From the top level targets `steps` generate a topological ordering of /// all steps needed to run those steps. fn expand(&self, steps: &[Step<'a>]) -> Vec> { + // First up build a graph of steps and their dependencies. The `nodes` + // map is a map from step to a unique number. The `edges` map is a + // map from these unique numbers to a list of other numbers, + // representing dependencies. + let mut nodes = HashMap::new(); + nodes.insert(Step::noop(), 0); + let mut edges = HashMap::new(); + edges.insert(0, HashSet::new()); + for step in steps { + self.build_graph(step.clone(), &mut nodes, &mut edges); + } + + // Now that we've built up the actual dependency graph, draw more + // dependency edges to satisfy the `after` dependencies field for each + // rule. + self.satisfy_after_deps(&nodes, &mut edges); + + // And finally, perform a topological sort to return a list of steps to + // execute. let mut order = Vec::new(); - let mut added = HashSet::new(); - added.insert(Step::noop()); - for step in steps.iter().cloned() { - self.fill(step, &mut order, &mut added); + let mut visited = HashSet::new(); + visited.insert(0); + let idx_to_node = nodes.iter().map(|p| (*p.1, p.0)).collect::>(); + for idx in 0..nodes.len() { + self.topo_sort(idx, &idx_to_node, &edges, &mut visited, &mut order); } return order } - /// Performs topological sort of dependencies rooted at the `step` - /// specified, pushing all results onto the `order` vector provided. + /// Builds the dependency graph rooted at `step`. /// - /// In other words, when this method returns, the `order` vector will - /// contain a list of steps which if executed in order will eventually - /// complete the `step` specified as well. - /// - /// The `added` set specified here is the set of steps that are already - /// present in `order` (and hence don't need to be added again). - fn fill(&self, - step: Step<'a>, - order: &mut Vec>, - added: &mut HashSet>) { - if !added.insert(step.clone()) { - return + /// The `nodes` and `edges` maps are filled out according to the rule + /// described by `step.name`. + fn build_graph(&self, + step: Step<'a>, + nodes: &mut HashMap, usize>, + edges: &mut HashMap>) -> usize { + use std::collections::hash_map::Entry; + + let idx = nodes.len(); + match nodes.entry(step.clone()) { + Entry::Vacant(e) => { e.insert(idx); } + Entry::Occupied(e) => return *e.get(), } + + let mut deps = Vec::new(); for dep in self.rules[step.name].deps.iter() { let dep = dep(&step); if dep.name.starts_with("default:") { @@ -1173,13 +1253,61 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? let host = self.build.config.host.iter().any(|h| h == dep.target); let rules = self.rules.values().filter(|r| r.default); for rule in rules.filter(|r| r.kind == kind && (!r.host || host)) { - self.fill(dep.name(rule.name), order, added); + deps.push(self.build_graph(dep.name(rule.name), nodes, edges)); } } else { - self.fill(dep, order, added); + deps.push(self.build_graph(dep, nodes, edges)); + } + } + + edges.entry(idx).or_insert(HashSet::new()).extend(deps); + return idx + } + + /// Given a dependency graph with a finished list of `nodes`, fill out more + /// dependency `edges`. + /// + /// This is the step which satisfies all `after` listed dependencies in + /// `Rule` above. + fn satisfy_after_deps(&self, + nodes: &HashMap, usize>, + edges: &mut HashMap>) { + // Reverse map from the name of a step to the node indices that it + // appears at. + let mut name_to_idx = HashMap::new(); + for (step, &idx) in nodes { + name_to_idx.entry(step.name).or_insert(Vec::new()).push(idx); + } + + for (step, idx) in nodes { + if *step == Step::noop() { + continue } + for after in self.rules[step.name].after.iter() { + // This is the critical piece of an `after` dependency. If the + // dependency isn't actually in our graph then no edge is drawn, + // only if it's already present do we draw the edges. + if let Some(idxs) = name_to_idx.get(after) { + edges.get_mut(idx).unwrap() + .extend(idxs.iter().cloned()); + } + } + } + } + + fn topo_sort(&self, + cur: usize, + nodes: &HashMap>, + edges: &HashMap>, + visited: &mut HashSet, + order: &mut Vec>) { + if !visited.insert(cur) { + return + } + for dep in edges[&cur].iter() { + self.topo_sort(*dep, nodes, edges, visited, order); } - order.push(step); + order.push(nodes[&cur].clone()); } } diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 52f74ba90d..6f3a7e091e 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -152,18 +152,13 @@ For targets: `powerpc-unknown-linux-gnu` - Path and misc options > Patches origin = Bundled, then local - Path and misc options > Local patch directory = /tmp/patches - Target options > Target Architecture = powerpc -- Target options > Emit assembly for CPU = power4 -- (+) -- Target options > Tune for CPU = power6 -- (+) +- Target options > Emit assembly for CPU = powerpc -- pure 32-bit PowerPC - Operating System > Target OS = linux - Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel - C-library > glibc version = 2.12.2 -- ~RHEL6 glibc - C compiler > gcc version = 4.9.3 -- C compiler > Core gcc extra config = --with-cpu-32=power4 --with-cpu=default32 -- (+) -- C compiler > gcc extra config = --with-cpu-32=power4 --with-cpu=default32 -- (+) - C compiler > C++ = ENABLE -- to cross compile LLVM -(+) These CPU options match the configuration of the toolchains in RHEL6. - ## `powerpc64-linux-gnu.config` For targets: `powerpc64-unknown-linux-gnu` diff --git a/src/ci/docker/arm-android/Dockerfile b/src/ci/docker/arm-android/Dockerfile index 4c89ce1253..04ca6d76c5 100644 --- a/src/ci/docker/arm-android/Dockerfile +++ b/src/ci/docker/arm-android/Dockerfile @@ -13,7 +13,7 @@ RUN dpkg --add-architecture i386 && \ cmake \ unzip \ expect \ - openjdk-9-jre \ + openjdk-9-jre-headless \ sudo \ libstdc++6:i386 \ xz-utils \ diff --git a/src/ci/docker/arm-android/start-emulator.sh b/src/ci/docker/arm-android/start-emulator.sh index 24c477d87f..4a73637e9d 100755 --- a/src/ci/docker/arm-android/start-emulator.sh +++ b/src/ci/docker/arm-android/start-emulator.sh @@ -10,7 +10,9 @@ # except according to those terms. set -ex -ANDROID_EMULATOR_FORCE_32BIT=true \ - nohup nohup emulator @arm-18 -no-window -partition-size 2047 \ - 0<&- &>/dev/null & + +# Setting SHELL to a file instead on a symlink helps android +# emulator identify the system +export SHELL=/bin/bash +nohup nohup emulator @arm-18 -no-window -partition-size 2047 0<&- &>/dev/null & exec "$@" diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile index 7c19844100..02d4eaf534 100644 --- a/src/ci/docker/cross/Dockerfile +++ b/src/ci/docker/cross/Dockerfile @@ -74,6 +74,7 @@ ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ 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 \ diff --git a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile b/src/ci/docker/dist-aarch64-linux/Dockerfile similarity index 79% rename from src/ci/docker/dist-armv7-aarch64-linux/Dockerfile rename to src/ci/docker/dist-aarch64-linux/Dockerfile index 955bba681b..d9a5429d2b 100644 --- a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile +++ b/src/ci/docker/dist-aarch64-linux/Dockerfile @@ -27,10 +27,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ pkg-config -RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ - chmod +x /usr/local/bin/sccache - RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ dpkg -i dumb-init_*.deb && \ rm dumb-init_*.deb @@ -60,24 +56,22 @@ RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools USER rustbuild WORKDIR /tmp -COPY armv7-linux-gnueabihf.config /tmp/ -COPY armv7-linux-gnueabihf.config aarch64-linux-gnu.config build-toolchains.sh /tmp/ +COPY aarch64-linux-gnu.config build-toolchains.sh /tmp/ RUN ./build-toolchains.sh USER root +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnueabi/bin -ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-gcc \ AR_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-ar \ - CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-g++ \ - CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \ - AR_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-ar \ - CXX_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-g++ + CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-g++ -ENV HOSTS=armv7-unknown-linux-gnueabihf -ENV HOSTS=$HOSTS,aarch64-unknown-linux-gnu +ENV HOSTS=aarch64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-armv7-aarch64-linux/aarch64-linux-gnu.config b/src/ci/docker/dist-aarch64-linux/aarch64-linux-gnu.config similarity index 100% rename from src/ci/docker/dist-armv7-aarch64-linux/aarch64-linux-gnu.config rename to src/ci/docker/dist-aarch64-linux/aarch64-linux-gnu.config diff --git a/src/ci/docker/dist-aarch64-linux/build-toolchains.sh b/src/ci/docker/dist-aarch64-linux/build-toolchains.sh new file mode 100755 index 0000000000..94f785c96f --- /dev/null +++ b/src/ci/docker/dist-aarch64-linux/build-toolchains.sh @@ -0,0 +1,37 @@ +#!/bin/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 + +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 + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir build +cd build +cp ../aarch64-linux-gnu.config .config +ct-ng oldconfig +hide_output ct-ng build +cd .. +rm -rf build diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile index 31f4b8b777..28cc885ed3 100644 --- a/src/ci/docker/dist-android/Dockerfile +++ b/src/ci/docker/dist-android/Dockerfile @@ -36,15 +36,18 @@ RUN curl -o /usr/local/bin/sccache \ chmod +x /usr/local/bin/sccache ENV TARGETS=arm-linux-androideabi +ENV TARGETS=$TARGETS,armv7-linux-androideabi ENV TARGETS=$TARGETS,i686-linux-android ENV TARGETS=$TARGETS,aarch64-linux-android -ENV TARGETS=$TARGETS,armv7-linux-androideabi +ENV TARGETS=$TARGETS,x86_64-linux-android ENV RUST_CONFIGURE_ARGS \ --target=$TARGETS \ + --enable-extended \ --arm-linux-androideabi-ndk=/android/ndk-arm-9 \ --armv7-linux-androideabi-ndk=/android/ndk-arm-9 \ --i686-linux-android-ndk=/android/ndk-x86-9 \ - --aarch64-linux-android-ndk=/android/ndk-aarch64 + --aarch64-linux-android-ndk=/android/ndk-arm64-21 \ + --x86_64-linux-android-ndk=/android/ndk-x86_64-21 ENV SCRIPT python2.7 ../x.py dist --target $TARGETS diff --git a/src/ci/docker/dist-android/install-ndk.sh b/src/ci/docker/dist-android/install-ndk.sh index 19c1b94e78..d3a2d31754 100644 --- a/src/ci/docker/dist-android/install-ndk.sh +++ b/src/ci/docker/dist-android/install-ndk.sh @@ -25,7 +25,7 @@ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ --platform=android-21 \ --toolchain=aarch64-linux-android-4.9 \ - --install-dir=/android/ndk-aarch64 \ + --install-dir=/android/ndk-arm64-21 \ --ndk-dir=/android/android-ndk-r11c \ --arch=arm64 bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ @@ -34,5 +34,11 @@ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ --install-dir=/android/ndk-x86-9 \ --ndk-dir=/android/android-ndk-r11c \ --arch=x86 +bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ + --platform=android-21 \ + --toolchain=x86_64-4.9 \ + --install-dir=/android/ndk-x86_64-21 \ + --ndk-dir=/android/android-ndk-r11c \ + --arch=x86_64 rm -rf ./android-ndk-r11c-linux-x86_64.zip ./android-ndk-r11c diff --git a/src/ci/docker/dist-arm-linux/Dockerfile b/src/ci/docker/dist-arm-linux/Dockerfile index d78effa7bd..7162aa0efc 100644 --- a/src/ci/docker/dist-arm-linux/Dockerfile +++ b/src/ci/docker/dist-arm-linux/Dockerfile @@ -27,10 +27,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ pkg-config -RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ - chmod +x /usr/local/bin/sccache - RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ dpkg -i dumb-init_*.deb && \ rm dumb-init_*.deb @@ -60,23 +56,22 @@ RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools USER rustbuild WORKDIR /tmp -COPY arm-linux-gnueabihf.config arm-linux-gnueabi.config build-toolchains.sh /tmp/ +COPY arm-linux-gnueabi.config build-toolchains.sh /tmp/ RUN ./build-toolchains.sh USER root +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin -ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \ AR_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-ar \ - CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++ \ - CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \ - AR_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-ar \ - CXX_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-g++ + CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++ ENV HOSTS=arm-unknown-linux-gnueabi -ENV HOSTS=$HOSTS,arm-unknown-linux-gnueabihf ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-arm-linux/build-toolchains.sh b/src/ci/docker/dist-arm-linux/build-toolchains.sh index ed1406bd7c..f78ecf9381 100755 --- a/src/ci/docker/dist-arm-linux/build-toolchains.sh +++ b/src/ci/docker/dist-arm-linux/build-toolchains.sh @@ -35,11 +35,3 @@ ct-ng oldconfig hide_output ct-ng build cd .. rm -rf build - -mkdir build -cd build -cp ../arm-linux-gnueabihf.config .config -ct-ng oldconfig -hide_output ct-ng build -cd .. -rm -rf build diff --git a/src/ci/docker/dist-armhf-linux/Dockerfile b/src/ci/docker/dist-armhf-linux/Dockerfile new file mode 100644 index 0000000000..8fa1cbe492 --- /dev/null +++ b/src/ci/docker/dist-armhf-linux/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY arm-linux-gnueabihf.config build-toolchains.sh /tmp/ +RUN ./build-toolchains.sh + +USER root + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin + +ENV CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \ + AR_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-ar \ + CXX_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-g++ + +ENV HOSTS=arm-unknown-linux-gnueabihf + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-arm-linux/arm-linux-gnueabihf.config b/src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config similarity index 100% rename from src/ci/docker/dist-arm-linux/arm-linux-gnueabihf.config rename to src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config diff --git a/src/ci/docker/dist-armhf-linux/build-toolchains.sh b/src/ci/docker/dist-armhf-linux/build-toolchains.sh new file mode 100755 index 0000000000..df1134d548 --- /dev/null +++ b/src/ci/docker/dist-armhf-linux/build-toolchains.sh @@ -0,0 +1,37 @@ +#!/bin/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 + +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 + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir build +cd build +cp ../arm-linux-gnueabihf.config .config +ct-ng oldconfig +hide_output ct-ng build +cd .. +rm -rf build diff --git a/src/ci/docker/dist-armv7-linux/Dockerfile b/src/ci/docker/dist-armv7-linux/Dockerfile new file mode 100644 index 0000000000..9fcd827fc9 --- /dev/null +++ b/src/ci/docker/dist-armv7-linux/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY build-toolchains.sh armv7-linux-gnueabihf.config /tmp/ +RUN ./build-toolchains.sh + +USER root + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin + +ENV CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \ + AR_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-ar \ + CXX_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-g++ + +ENV HOSTS=armv7-unknown-linux-gnueabihf + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-armv7-aarch64-linux/armv7-linux-gnueabihf.config b/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config similarity index 100% rename from src/ci/docker/dist-armv7-aarch64-linux/armv7-linux-gnueabihf.config rename to src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config diff --git a/src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh b/src/ci/docker/dist-armv7-linux/build-toolchains.sh similarity index 88% rename from src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh rename to src/ci/docker/dist-armv7-linux/build-toolchains.sh index ebd5ef4cfc..2d395fee79 100755 --- a/src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh +++ b/src/ci/docker/dist-armv7-linux/build-toolchains.sh @@ -35,11 +35,3 @@ ct-ng oldconfig hide_output ct-ng build cd .. rm -rf build - -mkdir build -cd build -cp ../aarch64-linux-gnu.config .config -ct-ng oldconfig -hide_output ct-ng build -cd .. -rm -rf build diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile index 4a401bbb30..294460ed76 100644 --- a/src/ci/docker/dist-fuchsia/Dockerfile +++ b/src/ci/docker/dist-fuchsia/Dockerfile @@ -44,5 +44,5 @@ ENV \ ENV TARGETS=x86_64-unknown-fuchsia ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia -ENV RUST_CONFIGURE_ARGS --target=$TARGETS +ENV RUST_CONFIGURE_ARGS --target=$TARGETS --enable-extended ENV SCRIPT python2.7 ../x.py dist --target $TARGETS diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile index d2727cbdb3..1ef3e569cb 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile +++ b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile @@ -31,7 +31,8 @@ RUN curl -o /usr/local/bin/sccache \ ENV RUST_CONFIGURE_ARGS \ --target=i686-unknown-linux-musl,i586-unknown-linux-gnu \ - --musl-root-i686=/musl-i686 + --musl-root-i686=/musl-i686 \ + --enable-extended # Newer binutils broke things on some vms/distros (i.e., linking against # unknown relocs disabled by the following flag), so we need to go out of our 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 index a50a25c791..ad285a57a8 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh +++ b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh @@ -15,11 +15,14 @@ set -ex export CFLAGS="-fPIC -Wa,-mrelax-relocations=no" export CXXFLAGS="-Wa,-mrelax-relocations=no" -MUSL=musl-1.1.14 +MUSL=musl-1.1.16 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - cd $MUSL -CFLAGS="$CFLAGS -m32" ./configure --prefix=/musl-i686 --disable-shared --target=i686 -make -j10 +CC=gcc \ + CFLAGS="$CFLAGS -m32" \ + ./configure --prefix=/musl-i686 --disable-shared \ + --target=i686 +make AR=ar RANLIB=ranlib -j10 make install cd .. diff --git a/src/ci/docker/dist-freebsd/Dockerfile b/src/ci/docker/dist-i686-freebsd/Dockerfile similarity index 77% rename from src/ci/docker/dist-freebsd/Dockerfile rename to src/ci/docker/dist-i686-freebsd/Dockerfile index 9e0ce28aaa..3b81216c64 100644 --- a/src/ci/docker/dist-freebsd/Dockerfile +++ b/src/ci/docker/dist-i686-freebsd/Dockerfile @@ -17,7 +17,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config COPY build-toolchain.sh /tmp/ -RUN /tmp/build-toolchain.sh x86_64 RUN /tmp/build-toolchain.sh i686 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ @@ -30,15 +29,11 @@ RUN curl -o /usr/local/bin/sccache \ chmod +x /usr/local/bin/sccache ENV \ - AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \ - CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc \ - CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-g++ \ AR_i686_unknown_freebsd=i686-unknown-freebsd10-ar \ CC_i686_unknown_freebsd=i686-unknown-freebsd10-gcc \ CXX_i686_unknown_freebsd=i686-unknown-freebsd10-g++ -ENV HOSTS=x86_64-unknown-freebsd -ENV HOSTS=$HOSTS,i686-unknown-freebsd +ENV HOSTS=i686-unknown-freebsd ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-freebsd/build-toolchain.sh b/src/ci/docker/dist-i686-freebsd/build-toolchain.sh similarity index 100% rename from src/ci/docker/dist-freebsd/build-toolchain.sh rename to src/ci/docker/dist-i686-freebsd/build-toolchain.sh diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile similarity index 98% rename from src/ci/docker/dist-x86-linux/Dockerfile rename to src/ci/docker/dist-i686-linux/Dockerfile index d9b4197c08..c25c770136 100644 --- a/src/ci/docker/dist-x86-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -12,6 +12,7 @@ RUN yum upgrade -y && yum install -y \ curl \ bzip2 \ gcc \ + gcc-c++ \ make \ glibc-devel \ perl \ @@ -85,7 +86,6 @@ RUN curl -o /usr/local/bin/sccache \ chmod +x /usr/local/bin/sccache ENV HOSTS=i686-unknown-linux-gnu -ENV HOSTS=$HOSTS,x86_64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ --host=$HOSTS \ diff --git a/src/ci/docker/dist-x86-linux/build-binutils.sh b/src/ci/docker/dist-i686-linux/build-binutils.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-binutils.sh rename to src/ci/docker/dist-i686-linux/build-binutils.sh diff --git a/src/ci/docker/dist-x86-linux/build-cmake.sh b/src/ci/docker/dist-i686-linux/build-cmake.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-cmake.sh rename to src/ci/docker/dist-i686-linux/build-cmake.sh diff --git a/src/ci/docker/dist-x86-linux/build-curl.sh b/src/ci/docker/dist-i686-linux/build-curl.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-curl.sh rename to src/ci/docker/dist-i686-linux/build-curl.sh diff --git a/src/ci/docker/dist-x86-linux/build-gcc.sh b/src/ci/docker/dist-i686-linux/build-gcc.sh similarity index 79% rename from src/ci/docker/dist-x86-linux/build-gcc.sh rename to src/ci/docker/dist-i686-linux/build-gcc.sh index 06198eb0c9..ab2562538d 100755 --- a/src/ci/docker/dist-x86-linux/build-gcc.sh +++ b/src/ci/docker/dist-i686-linux/build-gcc.sh @@ -13,12 +13,14 @@ set -ex source shared.sh -curl https://ftp.gnu.org/gnu/gcc/gcc-4.7.4/gcc-4.7.4.tar.bz2 | tar xjf - -cd gcc-4.7.4 +GCC=4.8.5 + +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +cd gcc-$GCC ./contrib/download_prerequisites mkdir ../gcc-build cd ../gcc-build -hide_output ../gcc-4.7.4/configure \ +hide_output ../gcc-$GCC/configure \ --prefix=/rustroot \ --enable-languages=c,c++ hide_output make -j10 @@ -27,5 +29,5 @@ ln -nsf gcc /rustroot/bin/cc cd .. rm -rf gcc-build -rm -rf gcc-4.7.4 -yum erase -y gcc binutils +rm -rf gcc-$GCC +yum erase -y gcc gcc-c++ binutils diff --git a/src/ci/docker/dist-x86-linux/build-git.sh b/src/ci/docker/dist-i686-linux/build-git.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-git.sh rename to src/ci/docker/dist-i686-linux/build-git.sh diff --git a/src/ci/docker/dist-x86-linux/build-headers.sh b/src/ci/docker/dist-i686-linux/build-headers.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-headers.sh rename to src/ci/docker/dist-i686-linux/build-headers.sh diff --git a/src/ci/docker/dist-x86-linux/build-openssl.sh b/src/ci/docker/dist-i686-linux/build-openssl.sh similarity index 86% rename from src/ci/docker/dist-x86-linux/build-openssl.sh rename to src/ci/docker/dist-i686-linux/build-openssl.sh index 64b1abf82a..27cd064f90 100755 --- a/src/ci/docker/dist-x86-linux/build-openssl.sh +++ b/src/ci/docker/dist-i686-linux/build-openssl.sh @@ -12,9 +12,10 @@ set -ex source shared.sh -VERSION=1.0.2j +VERSION=1.0.2k +URL=https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/openssl-$VERSION.tar.gz -curl https://www.openssl.org/source/openssl-$VERSION.tar.gz | tar xzf - +curl $URL | tar xzf - cd openssl-$VERSION hide_output ./config --prefix=/rustroot shared -fPIC diff --git a/src/ci/docker/dist-x86-linux/build-python.sh b/src/ci/docker/dist-i686-linux/build-python.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-python.sh rename to src/ci/docker/dist-i686-linux/build-python.sh diff --git a/src/ci/docker/dist-x86-linux/shared.sh b/src/ci/docker/dist-i686-linux/shared.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/shared.sh rename to src/ci/docker/dist-i686-linux/shared.sh diff --git a/src/ci/docker/dist-mips-linux/Dockerfile b/src/ci/docker/dist-mips-linux/Dockerfile index 4a6e3e2d19..33cca06110 100644 --- a/src/ci/docker/dist-mips-linux/Dockerfile +++ b/src/ci/docker/dist-mips-linux/Dockerfile @@ -13,7 +13,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ gdb \ xz-utils \ g++-mips-linux-gnu \ - g++-mipsel-linux-gnu \ libssl-dev \ pkg-config @@ -27,7 +26,6 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] ENV HOSTS=mips-unknown-linux-gnu -ENV HOSTS=$HOSTS,mipsel-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-mips64-linux/Dockerfile b/src/ci/docker/dist-mips64-linux/Dockerfile index aca994fea9..157de83abb 100644 --- a/src/ci/docker/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/dist-mips64-linux/Dockerfile @@ -13,7 +13,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ gdb \ xz-utils \ g++-mips64-linux-gnuabi64 \ - g++-mips64el-linux-gnuabi64 \ libssl-dev \ pkg-config @@ -27,7 +26,6 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] ENV HOSTS=mips64-unknown-linux-gnuabi64 -ENV HOSTS=$HOSTS,mips64el-unknown-linux-gnuabi64 ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-mips64el-linux/Dockerfile b/src/ci/docker/dist-mips64el-linux/Dockerfile new file mode 100644 index 0000000000..739d5ff6ac --- /dev/null +++ b/src/ci/docker/dist-mips64el-linux/Dockerfile @@ -0,0 +1,31 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils \ + g++-mips64el-linux-gnuabi64 \ + libssl-dev \ + pkg-config + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +ENV HOSTS=mips64el-unknown-linux-gnuabi64 + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-mipsel-linux/Dockerfile b/src/ci/docker/dist-mipsel-linux/Dockerfile new file mode 100644 index 0000000000..9339063bc1 --- /dev/null +++ b/src/ci/docker/dist-mipsel-linux/Dockerfile @@ -0,0 +1,31 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils \ + g++-mipsel-linux-gnu \ + libssl-dev \ + pkg-config + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +ENV HOSTS=mipsel-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-powerpc-linux/Dockerfile b/src/ci/docker/dist-powerpc-linux/Dockerfile index 0fbb770f6a..92342caed2 100644 --- a/src/ci/docker/dist-powerpc-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc-linux/Dockerfile @@ -27,10 +27,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ pkg-config -RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ - chmod +x /usr/local/bin/sccache - RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ dpkg -i dumb-init_*.deb && \ rm dumb-init_*.deb @@ -66,6 +62,10 @@ RUN ./build-powerpc-toolchain.sh USER root +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + ENV PATH=$PATH:/x-tools/powerpc-unknown-linux-gnu/bin ENV \ diff --git a/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config b/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config index 26e2de863a..984a0a0304 100644 --- a/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config +++ b/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config @@ -101,8 +101,8 @@ CT_ARCH_SUPPORTS_WITH_FLOAT=y CT_ARCH_DEFAULT_BE=y CT_ARCH_DEFAULT_32=y CT_ARCH_ABI="" -CT_ARCH_CPU="power4" -CT_ARCH_TUNE="power6" +CT_ARCH_CPU="powerpc" +CT_ARCH_TUNE="" CT_ARCH_BE=y # CT_ARCH_LE is not set CT_ARCH_32=y @@ -391,8 +391,8 @@ CT_CC_GCC_HAS_LIBSANITIZER=y CT_CC_GCC_VERSION="4.9.3" # CT_CC_LANG_FORTRAN is not set CT_CC_GCC_ENABLE_CXX_FLAGS="" -CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="--with-cpu-32=power4 --with-cpu=default32" -CT_CC_GCC_EXTRA_CONFIG_ARRAY="--with-cpu-32=power4 --with-cpu=default32" +CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" +CT_CC_GCC_EXTRA_CONFIG_ARRAY="" CT_CC_GCC_EXTRA_ENV_ARRAY="" CT_CC_GCC_STATIC_LIBSTDCXX=y # CT_CC_GCC_SYSTEM_ZLIB is not set diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile index b44537b221..182dfd93cc 100644 --- a/src/ci/docker/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile @@ -25,11 +25,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ wget \ xz-utils \ libssl-dev \ - pkg-config - -RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ - chmod +x /usr/local/bin/sccache + pkg-config RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ dpkg -i dumb-init_*.deb && \ @@ -66,22 +62,18 @@ RUN ./build-powerpc64-toolchain.sh USER root -RUN apt-get install -y --no-install-recommends rpm2cpio cpio -COPY build-powerpc64le-toolchain.sh /tmp/ -RUN ./build-powerpc64le-toolchain.sh +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin ENV \ AR_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-ar \ CC_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-gcc \ - CXX_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-g++ \ - AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \ - CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ - CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ + CXX_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-g++ ENV HOSTS=powerpc64-unknown-linux-gnu -ENV HOSTS=$HOSTS,powerpc64le-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-powerpc64le-linux/Dockerfile b/src/ci/docker/dist-powerpc64le-linux/Dockerfile new file mode 100644 index 0000000000..6b9f964d5a --- /dev/null +++ b/src/ci/docker/dist-powerpc64le-linux/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +USER root + +RUN apt-get install -y --no-install-recommends rpm2cpio cpio +COPY shared.sh build-powerpc64le-toolchain.sh /tmp/ +RUN ./build-powerpc64le-toolchain.sh + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV \ + AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \ + CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ + CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ + +ENV HOSTS=powerpc64le-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh b/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh similarity index 100% rename from src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh rename to src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh diff --git a/src/ci/docker/dist-powerpc64le-linux/shared.sh b/src/ci/docker/dist-powerpc64le-linux/shared.sh new file mode 100644 index 0000000000..97e6d2908c --- /dev/null +++ b/src/ci/docker/dist-powerpc64le-linux/shared.sh @@ -0,0 +1,25 @@ +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh deleted file mode 100755 index 654b458ea4..0000000000 --- a/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh +++ /dev/null @@ -1,120 +0,0 @@ -#!/bin/bash -# Copyright 2016 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -# ignore-tidy-linelength - -set -ex - -BINUTILS=2.25.1 -GCC=5.3.0 - -# First up, build binutils -mkdir binutils -cd binutils -curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf - -mkdir binutils-build -cd binutils-build -../binutils-$BINUTILS/configure \ - --target=x86_64-unknown-netbsd -make -j10 -make install -cd ../.. -rm -rf binutils - -# Next, download the NetBSD libc and relevant header files -mkdir netbsd -# originally from: -# https://ftp.netbsd.org/pub/NetBSD/NetBSD-7.0/amd64/binary/sets/base.tgz -curl https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-01-16-netbsd-base.tgz | \ - tar xzf - -C netbsd ./usr/include ./usr/lib ./lib -# originally from: -# https://ftp.netbsd.org/pub/NetBSD/NetBSD-7.0/amd64/binary/sets/comp.tgz -curl https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-01-16-netbsd-comp.tgz | \ - tar xzf - -C netbsd ./usr/include ./usr/lib - -dst=/usr/local/x86_64-unknown-netbsd -cp -r netbsd/usr/include $dst -cp netbsd/usr/lib/crt0.o $dst/lib -cp netbsd/usr/lib/crti.o $dst/lib -cp netbsd/usr/lib/crtn.o $dst/lib -cp netbsd/usr/lib/crtbeginS.o $dst/lib -cp netbsd/usr/lib/crtendS.o $dst/lib -cp netbsd/usr/lib/crtbegin.o $dst/lib -cp netbsd/usr/lib/crtend.o $dst/lib -cp netbsd/usr/lib/gcrt0.o $dst/lib -cp netbsd/usr/lib/libc.a $dst/lib -cp netbsd/usr/lib/libc_p.a $dst/lib -cp netbsd/usr/lib/libc_pic.a $dst/lib -cp netbsd/lib/libc.so.12.193.1 $dst/lib -cp netbsd/lib/libutil.so.7.21 $dst/lib -cp netbsd/usr/lib/libm.a $dst/lib -cp netbsd/usr/lib/libm_p.a $dst/lib -cp netbsd/usr/lib/libm_pic.a $dst/lib -cp netbsd/lib/libm.so.0.11 $dst/lib -cp netbsd/usr/lib/librt.so.1.1 $dst/lib -cp netbsd/usr/lib/libpthread.a $dst/lib -cp netbsd/usr/lib/libpthread_p.a $dst/lib -cp netbsd/usr/lib/libpthread_pic.a $dst/lib -cp netbsd/usr/lib/libpthread.so.1.2 $dst/lib - -ln -s libc.so.12.193.1 $dst/lib/libc.so -ln -s libc.so.12.193.1 $dst/lib/libc.so.12 -ln -s libm.so.0.11 $dst/lib/libm.so -ln -s libm.so.0.11 $dst/lib/libm.so.0 -ln -s libutil.so.7.21 $dst/lib/libutil.so -ln -s libutil.so.7.21 $dst/lib/libutil.so.7 -ln -s libpthread.so.1.2 $dst/lib/libpthread.so -ln -s libpthread.so.1.2 $dst/lib/libpthread.so.1 -ln -s librt.so.1.1 $dst/lib/librt.so - -rm -rf netbsd - -# Finally, download and build gcc to target NetBSD -mkdir gcc -cd gcc -curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - -cd gcc-$GCC -./contrib/download_prerequisites - -# Originally from -# ftp://ftp.netbsd.org/pub/pkgsrc/pkgsrc-2016Q4/pkgsrc/lang/gcc5/patches/patch-libstdc%2B%2B-v3_config_os_bsd_netbsd_ctype__base.h -PATCHES="https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-01-13-netbsd-patch1.patch" - -# Originally from -# ftp://ftp.netbsd.org/pub/pkgsrc/pkgsrc-2016Q4/pkgsrc/lang/gcc5/patches/patch-libstdc%2B%2B-v3_config_os_bsd_netbsd_ctype__configure__char.cc -PATCHES="$PATCHES https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-01-13-netbsd-patch2.patch" - -for patch in $PATCHES; do - curl $patch | patch -Np0 -done - -mkdir ../gcc-build -cd ../gcc-build -../gcc-$GCC/configure \ - --enable-languages=c,c++ \ - --target=x86_64-unknown-netbsd \ - --disable-libcilkrts \ - --disable-multilib \ - --disable-nls \ - --disable-libgomp \ - --disable-libquadmath \ - --disable-libssp \ - --disable-libvtv \ - --disable-libcilkrt \ - --disable-libada \ - --disable-libsanitizer \ - --disable-libquadmath-support \ - --disable-lto -make -j10 -make install - -cd ../.. -rm -rf gcc diff --git a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile b/src/ci/docker/dist-s390x-linux/Dockerfile similarity index 86% rename from src/ci/docker/dist-s390x-linux-netbsd/Dockerfile rename to src/ci/docker/dist-s390x-linux/Dockerfile index 41faef652b..7c94f713e1 100644 --- a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile +++ b/src/ci/docker/dist-s390x-linux/Dockerfile @@ -27,10 +27,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ pkg-config -RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ - chmod +x /usr/local/bin/sccache - RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ dpkg -i dumb-init_*.deb && \ rm dumb-init_*.deb @@ -66,21 +62,18 @@ RUN ./build-s390x-toolchain.sh USER root -COPY build-netbsd-toolchain.sh /tmp/ -RUN ./build-netbsd-toolchain.sh +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin ENV \ - AR_x86_64_unknown_netbsd=x86_64-unknown-netbsd-ar \ - CC_x86_64_unknown_netbsd=x86_64-unknown-netbsd-gcc \ - CXX_x86_64_unknown_netbsd=x86_64-unknown-netbsd-g++ \ CC_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-gcc \ AR_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-ar \ CXX_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-g++ -ENV HOSTS=x86_64-unknown-netbsd -ENV HOSTS=$HOSTS,s390x-unknown-linux-gnu +ENV HOSTS=s390x-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh b/src/ci/docker/dist-s390x-linux/build-s390x-toolchain.sh similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh rename to src/ci/docker/dist-s390x-linux/build-s390x-toolchain.sh diff --git a/src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch b/src/ci/docker/dist-s390x-linux/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch rename to src/ci/docker/dist-s390x-linux/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch diff --git a/src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config b/src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config rename to src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config diff --git a/src/ci/docker/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/dist-x86_64-freebsd/Dockerfile new file mode 100644 index 0000000000..a2939c8c48 --- /dev/null +++ b/src/ci/docker/dist-x86_64-freebsd/Dockerfile @@ -0,0 +1,39 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + bzip2 \ + xz-utils \ + wget \ + libssl-dev \ + pkg-config + +COPY build-toolchain.sh /tmp/ +RUN /tmp/build-toolchain.sh x86_64 + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV \ + AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \ + CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc \ + CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-g++ + +ENV HOSTS=x86_64-unknown-freebsd + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh b/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh new file mode 100755 index 0000000000..5642e6fc93 --- /dev/null +++ b/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +ARCH=$1 +BINUTILS=2.25.1 +GCC=5.3.0 + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir binutils +cd binutils + +# First up, build binutils +curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf - +mkdir binutils-build +cd binutils-build +hide_output ../binutils-$BINUTILS/configure \ + --target=$ARCH-unknown-freebsd10 +hide_output make -j10 +hide_output make install +cd ../.. +rm -rf binutils + +# Next, download the FreeBSD libc and relevant header files + +mkdir freebsd +case "$ARCH" in + x86_64) + URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.2-RELEASE/base.txz + ;; + i686) + URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/10.2-RELEASE/base.txz + ;; +esac +curl $URL | tar xJf - -C freebsd ./usr/include ./usr/lib ./lib + +dst=/usr/local/$ARCH-unknown-freebsd10 + +cp -r freebsd/usr/include $dst/ +cp freebsd/usr/lib/crt1.o $dst/lib +cp freebsd/usr/lib/Scrt1.o $dst/lib +cp freebsd/usr/lib/crti.o $dst/lib +cp freebsd/usr/lib/crtn.o $dst/lib +cp freebsd/usr/lib/libc.a $dst/lib +cp freebsd/usr/lib/libutil.a $dst/lib +cp freebsd/usr/lib/libutil_p.a $dst/lib +cp freebsd/usr/lib/libm.a $dst/lib +cp freebsd/usr/lib/librt.so.1 $dst/lib +cp freebsd/usr/lib/libexecinfo.so.1 $dst/lib +cp freebsd/lib/libc.so.7 $dst/lib +cp freebsd/lib/libm.so.5 $dst/lib +cp freebsd/lib/libutil.so.9 $dst/lib +cp freebsd/lib/libthr.so.3 $dst/lib/libpthread.so + +ln -s libc.so.7 $dst/lib/libc.so +ln -s libm.so.5 $dst/lib/libm.so +ln -s librt.so.1 $dst/lib/librt.so +ln -s libutil.so.9 $dst/lib/libutil.so +ln -s libexecinfo.so.1 $dst/lib/libexecinfo.so +rm -rf freebsd + +# Finally, download and build gcc to target FreeBSD +mkdir gcc +cd gcc +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +cd gcc-$GCC +./contrib/download_prerequisites + +mkdir ../gcc-build +cd ../gcc-build +hide_output ../gcc-$GCC/configure \ + --enable-languages=c,c++ \ + --target=$ARCH-unknown-freebsd10 \ + --disable-multilib \ + --disable-nls \ + --disable-libgomp \ + --disable-libquadmath \ + --disable-libssp \ + --disable-libvtv \ + --disable-libcilkrts \ + --disable-libada \ + --disable-libsanitizer \ + --disable-libquadmath-support \ + --disable-lto +hide_output make -j10 +hide_output make install +cd ../.. +rm -rf gcc diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile new file mode 100644 index 0000000000..e835e8d2f7 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -0,0 +1,101 @@ +FROM centos:5 + +WORKDIR /build + +# Centos 5 is EOL and is no longer available from the usual mirrors, so switch +# to http://vault.centos.org/ +RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf +RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo +RUN sed -i 's|#\(baseurl.*\)mirror.centos.org/centos/$releasever|\1vault.centos.org/5.11|' /etc/yum.repos.d/*.repo + +RUN yum upgrade -y && yum install -y \ + curl \ + bzip2 \ + gcc \ + gcc-c++ \ + make \ + glibc-devel \ + perl \ + zlib-devel \ + file \ + xz \ + which \ + pkgconfig \ + wget \ + autoconf \ + gettext + +ENV PATH=/rustroot/bin:$PATH +ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib +ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig +WORKDIR /tmp +COPY shared.sh build-binutils.sh /tmp/ + +# We need a build of openssl which supports SNI to download artifacts from +# static.rust-lang.org. This'll be used to link into libcurl below (and used +# later as well), so build a copy of OpenSSL with dynamic libraries into our +# generic root. +COPY build-openssl.sh /tmp/ +RUN ./build-openssl.sh + +# The `curl` binary on CentOS doesn't support SNI which is needed for fetching +# some https urls we have, so install a new version of libcurl + curl which is +# using the openssl we just built previously. +# +# Note that we also disable a bunch of optional features of curl that we don't +# really need. +COPY build-curl.sh /tmp/ +RUN ./build-curl.sh + +# binutils < 2.22 has a bug where the 32-bit executables it generates +# immediately segfault in Rust, so we need to install our own binutils. +# +# See https://github.com/rust-lang/rust/issues/20440 for more info +RUN ./build-binutils.sh + +# Need a newer version of gcc than centos has to compile LLVM nowadays +COPY build-gcc.sh /tmp/ +RUN ./build-gcc.sh + +# CentOS 5.5 has Python 2.4 by default, but LLVM needs 2.7+ +COPY build-python.sh /tmp/ +RUN ./build-python.sh + +# Apparently CentOS 5.5 desn't have `git` in yum, but we're gonna need it for +# cloning, so download and build it here. +COPY build-git.sh /tmp/ +RUN ./build-git.sh + +# libssh2 (a dependency of Cargo) requires cmake 2.8.11 or higher but CentOS +# only has 2.6.4, so build our own +COPY build-cmake.sh /tmp/ +RUN ./build-cmake.sh + +# for sanitizers, we need kernel headers files newer than the ones CentOS ships +# with so we install newer ones here +COPY build-headers.sh /tmp/ +RUN ./build-headers.sh + +RUN curl -Lo /rustroot/dumb-init \ + https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64 && \ + chmod +x /rustroot/dumb-init +ENTRYPOINT ["/rustroot/dumb-init", "--"] + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV HOSTS=x86_64-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS \ + --host=$HOSTS \ + --enable-extended \ + --enable-sanitizers +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS + +# This is the only builder which will create source tarballs +ENV DIST_SRC 1 + +# When we build cargo in this container, we don't want it to use the system +# libcurl, instead it should compile its own. +ENV LIBCURL_NO_PKG_CONFIG 1 diff --git a/src/ci/docker/dist-x86_64-linux/build-binutils.sh b/src/ci/docker/dist-x86_64-linux/build-binutils.sh new file mode 100755 index 0000000000..80aa1f2a01 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-binutils.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +source shared.sh + +curl https://ftp.gnu.org/gnu/binutils/binutils-2.25.1.tar.bz2 | tar xfj - + +mkdir binutils-build +cd binutils-build +hide_output ../binutils-2.25.1/configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf binutils-build +rm -rf binutils-2.25.1 diff --git a/src/ci/docker/dist-x86_64-linux/build-cmake.sh b/src/ci/docker/dist-x86_64-linux/build-cmake.sh new file mode 100755 index 0000000000..82e46455cb --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-cmake.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +curl https://cmake.org/files/v3.6/cmake-3.6.3.tar.gz | tar xzf - + +mkdir cmake-build +cd cmake-build +hide_output ../cmake-3.6.3/configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf cmake-build +rm -rf cmake-3.6.3 diff --git a/src/ci/docker/dist-x86_64-linux/build-curl.sh b/src/ci/docker/dist-x86_64-linux/build-curl.sh new file mode 100755 index 0000000000..b7d22755a5 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-curl.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +VERSION=7.51.0 + +curl http://cool.haxx.se/download/curl-$VERSION.tar.bz2 | tar xjf - + +mkdir curl-build +cd curl-build +hide_output ../curl-$VERSION/configure \ + --prefix=/rustroot \ + --with-ssl=/rustroot \ + --disable-sspi \ + --disable-gopher \ + --disable-smtp \ + --disable-smb \ + --disable-imap \ + --disable-pop3 \ + --disable-tftp \ + --disable-telnet \ + --disable-manual \ + --disable-dict \ + --disable-rtsp \ + --disable-ldaps \ + --disable-ldap +hide_output make -j10 +hide_output make install + +cd .. +rm -rf curl-build +rm -rf curl-$VERSION +yum erase -y curl diff --git a/src/ci/docker/dist-x86_64-linux/build-gcc.sh b/src/ci/docker/dist-x86_64-linux/build-gcc.sh new file mode 100755 index 0000000000..ab2562538d --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-gcc.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +source shared.sh + +GCC=4.8.5 + +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +cd gcc-$GCC +./contrib/download_prerequisites +mkdir ../gcc-build +cd ../gcc-build +hide_output ../gcc-$GCC/configure \ + --prefix=/rustroot \ + --enable-languages=c,c++ +hide_output make -j10 +hide_output make install +ln -nsf gcc /rustroot/bin/cc + +cd .. +rm -rf gcc-build +rm -rf gcc-$GCC +yum erase -y gcc gcc-c++ binutils diff --git a/src/ci/docker/dist-x86_64-linux/build-git.sh b/src/ci/docker/dist-x86_64-linux/build-git.sh new file mode 100755 index 0000000000..92fa66b496 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-git.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +curl https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf - + +cd git-2.10.0 +make configure +hide_output ./configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf git-2.10.0 diff --git a/src/ci/docker/dist-x86_64-linux/build-headers.sh b/src/ci/docker/dist-x86_64-linux/build-headers.sh new file mode 100755 index 0000000000..4ce38fd920 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-headers.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x + +cd linux-3.2.84 +hide_output make mrproper +hide_output make INSTALL_HDR_PATH=dest headers_install + +find dest/include \( -name .install -o -name ..install.cmd \) -delete +yes | cp -fr dest/include/* /usr/include + +cd .. +rm -rf linux-3.2.84 diff --git a/src/ci/docker/dist-x86_64-linux/build-openssl.sh b/src/ci/docker/dist-x86_64-linux/build-openssl.sh new file mode 100755 index 0000000000..27cd064f90 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-openssl.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +VERSION=1.0.2k +URL=https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/openssl-$VERSION.tar.gz + +curl $URL | tar xzf - + +cd openssl-$VERSION +hide_output ./config --prefix=/rustroot shared -fPIC +hide_output make -j10 +hide_output make install +cd .. +rm -rf openssl-$VERSION + +# Make the system cert collection available to the new install. +ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/ diff --git a/src/ci/docker/dist-x86_64-linux/build-python.sh b/src/ci/docker/dist-x86_64-linux/build-python.sh new file mode 100755 index 0000000000..a7a450f3c8 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-python.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +curl https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tgz | \ + tar xzf - + +mkdir python-build +cd python-build + +# Gotta do some hackery to tell python about our custom OpenSSL build, but other +# than that fairly normal. +CFLAGS='-I /rustroot/include' LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \ + hide_output ../Python-2.7.12/configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf python-build +rm -rf Python-2.7.12 diff --git a/src/ci/docker/dist-x86_64-linux/shared.sh b/src/ci/docker/dist-x86_64-linux/shared.sh new file mode 100644 index 0000000000..97e6d2908c --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/shared.sh @@ -0,0 +1,25 @@ +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile index a41c0cca3b..f462ccbb91 100644 --- a/src/ci/docker/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/dist-x86_64-musl/Dockerfile @@ -31,7 +31,8 @@ RUN curl -o /usr/local/bin/sccache \ ENV RUST_CONFIGURE_ARGS \ --target=x86_64-unknown-linux-musl \ - --musl-root-x86_64=/musl-x86_64 + --musl-root-x86_64=/musl-x86_64 \ + --enable-extended # Newer binutils broke things on some vms/distros (i.e., linking against # unknown relocs disabled by the following flag), so we need to go out of our diff --git a/src/ci/docker/dist-x86_64-musl/build-musl.sh b/src/ci/docker/dist-x86_64-musl/build-musl.sh index 86bb259c85..776da00939 100644 --- a/src/ci/docker/dist-x86_64-musl/build-musl.sh +++ b/src/ci/docker/dist-x86_64-musl/build-musl.sh @@ -15,7 +15,7 @@ set -ex export CFLAGS="-fPIC -Wa,-mrelax-relocations=no" export CXXFLAGS="-Wa,-mrelax-relocations=no" -MUSL=musl-1.1.14 +MUSL=musl-1.1.16 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - cd $MUSL ./configure --prefix=/musl-x86_64 --disable-shared diff --git a/src/ci/docker/dist-x86_64-netbsd/Dockerfile b/src/ci/docker/dist-x86_64-netbsd/Dockerfile new file mode 100644 index 0000000000..a1dd9a3724 --- /dev/null +++ b/src/ci/docker/dist-x86_64-netbsd/Dockerfile @@ -0,0 +1,78 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY build-netbsd-toolchain.sh /tmp/ +RUN ./build-netbsd-toolchain.sh + +USER root + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV PATH=$PATH:/x-tools/x86_64-unknown-netbsd/bin + +ENV \ + AR_x86_64_unknown_netbsd=x86_64--netbsd-ar \ + CC_x86_64_unknown_netbsd=x86_64--netbsd-gcc-sysroot \ + CXX_x86_64_unknown_netbsd=x86_64--netbsd-g++-sysroot + +ENV HOSTS=x86_64-unknown-netbsd + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS 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 new file mode 100755 index 0000000000..ea335a2497 --- /dev/null +++ b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh @@ -0,0 +1,83 @@ +#!/bin/bash +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +# ignore-tidy-linelength + +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 + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir netbsd +cd netbsd + +mkdir -p /x-tools/x86_64-unknown-netbsd/sysroot + +URL=https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror + +# Originally from ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-$BSD/source/sets/*.tgz +curl $URL/2017-03-17-netbsd-src.tgz | tar xzf - +curl $URL/2017-03-17-netbsd-gnusrc.tgz | tar xzf - +curl $URL/2017-03-17-netbsd-sharesrc.tgz | tar xzf - +curl $URL/2017-03-17-netbsd-syssrc.tgz | tar xzf - + +# Originally from ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-$BSD/amd64/binary/sets/*.tgz +curl $URL/2017-03-17-netbsd-base.tgz | \ + tar xzf - -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib ./lib +curl $URL/2017-03-17-netbsd-comp.tgz | \ + tar xzf - -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib + +cd usr/src + +# The options, in order, do the following +# * this is an unpriviledged build +# * output to a predictable location +# * disable various uneeded 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 + +cd ../.. + +rm -rf usr + +cat > /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-gcc-sysroot <<'EOF' +#!/bin/bash +exec /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-gcc --sysroot=/x-tools/x86_64-unknown-netbsd/sysroot "$@" +EOF + +cat > /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-g++-sysroot <<'EOF' +#!/bin/bash +exec /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-g++ --sysroot=/x-tools/x86_64-unknown-netbsd/sysroot "$@" +EOF + +GCC_SHA1=`sha1sum -b /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-gcc | cut -d' ' -f1` +GPP_SHA1=`sha1sum -b /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-g++ | cut -d' ' -f1` + +echo "# $GCC_SHA1" >> /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-gcc-sysroot +echo "# $GPP_SHA1" >> /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-g++-sysroot + +chmod +x /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-gcc-sysroot +chmod +x /x-tools/x86_64-unknown-netbsd/bin/x86_64--netbsd-g++-sysroot diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index b5a713dc38..59b93b784b 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -38,8 +38,6 @@ if [ "$SCCACHE_BUCKET" != "" ]; then args="$args --env AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" args="$args --env AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" args="$args --env SCCACHE_ERROR_LOG=/tmp/sccache/sccache.log" - args="$args --env SCCACHE_LOG_LEVEL=debug" - args="$args --env RUST_LOG=sccache=debug" args="$args --volume $objdir/tmp:/tmp/sccache" else mkdir -p $HOME/.cache/sccache @@ -58,6 +56,7 @@ exec docker \ --env DEPLOY_ALT=$DEPLOY_ALT \ --env LOCAL_USER_ID=`id -u` \ --volume "$HOME/.cargo:/cargo" \ + --volume "$HOME/rustsrc:$HOME/rustsrc" \ --privileged \ --rm \ rust-ci \ diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh new file mode 100755 index 0000000000..1db2135eb6 --- /dev/null +++ b/src/ci/init_repo.sh @@ -0,0 +1,86 @@ +#!/bin/bash +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -o errexit +set -o pipefail +set -o nounset + +set -o xtrace + +ci_dir=$(cd $(dirname $0) && pwd) +. "$ci_dir/shared.sh" + +REPO_DIR="$1" +CACHE_DIR="$2" + +cache_src_dir="$CACHE_DIR/src" +# If the layout of the cache directory changes, bump the number here +# (and anywhere else this file is referenced) so the cache is wiped +cache_valid_file="$CACHE_DIR/cache_valid1" + +if [ ! -d "$REPO_DIR" -o ! -d "$REPO_DIR/.git" ]; then + echo "Error: $REPO_DIR does not exist or is not a git repo" + exit 1 +fi +cd $REPO_DIR +if [ ! -d "$CACHE_DIR" ]; then + echo "Error: $CACHE_DIR does not exist or is not an absolute path" + exit 1 +fi + +# Wipe the cache if it's not valid, or mark it as invalid while we update it +if [ ! -f "$cache_valid_file" ]; then + rm -rf "$CACHE_DIR" + mkdir "$CACHE_DIR" +else + # Ignore errors while gathering information about the possible brokenness + # of the git repo since our gathered info will tell us something is wrong + set +o errexit + stat_lines=$(cd "$cache_src_dir" && git status --porcelain | wc -l) + stat_ec=$(cd "$cache_src_dir" && git status >/dev/null 2>&1; echo $?) + set -o errexit + if [ ! -d "$cache_src_dir/.git" -o $stat_lines != 0 -o $stat_ec != 0 ]; then + # Something is badly wrong - the cache valid file is here, but something + # about the git repo is fishy. Nuke it all, just in case + echo "WARNING: $cache_valid_file exists but bad repo: l:$stat_lines, ec:$stat_ec" + rm -rf "$CACHE_DIR" + mkdir "$CACHE_DIR" + else + rm "$cache_valid_file" + fi +fi + +# Update the cache (a pristine copy of the rust source master) +if [ ! -d "$cache_src_dir/.git" ]; then + retry sh -c "rm -rf $cache_src_dir && mkdir -p $cache_src_dir && \ + git clone https://github.com/rust-lang/rust.git $cache_src_dir" +fi +retry sh -c "cd $cache_src_dir && git reset --hard && git pull" +retry sh -c "cd $cache_src_dir && \ + git submodule deinit -f . && git submodule sync && git submodule update --init" + +# Cache was updated without errors, mark it as valid +touch "$cache_valid_file" + +# Update the submodules of the repo we're in, using the pristine repo as +# a cache for any object files +# No, `git submodule foreach` won't work: +# 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 [ ! -d "$cache_src_dir/$module" ]; then + echo "WARNING: $module not found in pristine repo" + retry sh -c "git submodule deinit -f $module && git submodule update --init $module" + continue + fi + retry sh -c "git submodule deinit -f $module && \ + git submodule update --init --reference $cache_src_dir/$module $module" +done diff --git a/src/ci/run.sh b/src/ci/run.sh index 228880f660..745adfc4a5 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -24,7 +24,6 @@ ci_dir=`cd $(dirname $0) && pwd` source "$ci_dir/shared.sh" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache" -RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-quiet-tests" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-manage-submodules" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-locked-deps" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-cargo-openssl-static" diff --git a/src/ci/shared.sh b/src/ci/shared.sh index ecd9b7e98a..f2e13fc73a 100644 --- a/src/ci/shared.sh +++ b/src/ci/shared.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/false # 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. @@ -9,13 +9,16 @@ # option. This file may not be copied, modified, or distributed # except according to those terms. +# This file is intended to be sourced with `. shared.sh` or +# `source shared.sh`, hence the invalid shebang and not being +# marked as an executable file in git. + # See http://unix.stackexchange.com/questions/82598 function retry { + echo "Attempting with retry:" "$@" local n=1 local max=5 - local delay=15 while true; do - echo "Attempting:" "$@" "$@" && break || { if [[ $n -lt $max ]]; then ((n++)) diff --git a/src/compiler-rt/lib/builtins/int_lib.h b/src/compiler-rt/lib/builtins/int_lib.h index a5b145ac17..a02e85b741 100644 --- a/src/compiler-rt/lib/builtins/int_lib.h +++ b/src/compiler-rt/lib/builtins/int_lib.h @@ -86,7 +86,7 @@ * Presumably it's any version of GCC, and targeting an arch that * does not have dedicated bit counting instructions. */ -#if (defined(__sparc64__) || defined(__sparcv9) || defined(__mips_n64) || defined(__mips_o64) || defined(__riscv__) \ +#if (defined(__sparc64__) || defined(__mips_n64) || defined(__mips_o64) || defined(__riscv__) \ || (defined(_MIPS_SIM) && ((_MIPS_SIM == _ABI64) || (_MIPS_SIM == _ABIO64)))) si_int __clzsi2(si_int); si_int __ctzsi2(si_int); diff --git a/src/doc/book/.github/ISSUE_TEMPLATE.md b/src/doc/book/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..c2f85ce98c --- /dev/null +++ b/src/doc/book/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,26 @@ +## What to expect when you file an issue here + +### First edition + +The first edition of the book is no longer being actively worked on. + +Issues for the first edition of the book are worthwhile if you are planning to +submit a pull request, and want to discuss it first. But as we aren't actively +working on the first edition, general bugs will be closed. + +### Second edition + +For the second edition, we are currently working with No Starch Press to bring +it to print. Chapters go through a number of stages in the editing process, and +once they've gotten to the layout stage, they're effectively frozen. + +For chapters that have gotten to the layout stage, we will likely only be +accepting changes that correct factual errors or major problems and not, for +example, minor wording changes. + +Scroll all the way to the right on https://github.com/rust-lang/book/projects/1 +to see which chapters have been frozen. + +Please see CONTRIBUTING.md for more details. + +Thank you for reading, you may now delete this text! diff --git a/src/doc/book/.github/PULL_REQUEST_TEMPLATE.md b/src/doc/book/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..a778d6c7e5 --- /dev/null +++ b/src/doc/book/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,24 @@ +## What to expect when you open a pull request here + +### First edition + +The first edition is no longer being actively worked on. We accept pull +requests for the first edition, but prefer small tweaks to large changes, as +larger work should be spent improving the second edition. + +### Second edition + +For the second edition, we are currently working with No Starch Press to bring +it to print. Chapters go through a number of stages in the editing process, and +once they've gotten to the layout stage, they're effectively frozen. + +For chapters that have gotten to the layout stage, we will likely only be +accepting changes that correct factual errors or major problems and not, for +example, minor wording changes. + +Scroll all the way to the right on https://github.com/rust-lang/book/projects/1 +to see which chapters have been frozen. + +Please see CONTRIBUTING.md for more details. + +Thank you for reading, you may now delete this text! diff --git a/src/doc/book/.travis.yml b/src/doc/book/.travis.yml new file mode 100644 index 0000000000..1fda254b45 --- /dev/null +++ b/src/doc/book/.travis.yml @@ -0,0 +1,22 @@ +sudo: false +language: rust +cache: cargo +rust: + - nightly-2017-04-11 +branches: + only: + - master +addons: + apt: + packages: + - aspell + - aspell-en +before_script: + - (cargo install mdbook --git https://github.com/azerupi/mdBook.git --force || true) +script: + - bash ci/build.sh +after_success: + - test $TRAVIS_PULL_REQUEST == "false" && test $TRAVIS_BRANCH == "master" && bash ci/deploy.sh +env: + global: + secure: BcBxhhCR2EgnZzllxXT3x2NNjAU1sjAwwjZ0lg6VqTetxh+ENHzjDsX4+mrBPXmm2vU7qZSivOHX+TEHHTUQOjHDyRdYg4PaPJxQBQ3/8hw/OEO7LwMo0FKhuixXKlBSBbhBIWomvJnGA7iRQqMabQqQyys1dYI3mb1ck8WMNwFe2ZaEe12nbvzTr0EGFRZ3bJhR0nDmvXlm2XIbwRnSfMSnWAIb/ksKEpwFfCRNwx4dMZkJzOii+rnFaNWO1KIUh4V1+Jo8GR24/2Bd/3HqAxDP+6kAYOcB1hKQuHnVOdVx0B7LUxe6Pgwq98EXaNmpgrq7YUpwwrPEExr6k9UzBkcTcz0X+U9tvaqcvDD1qlQZORdtbOPMvYVkE7uxu/d+/s6CyIaUKIb/RLrqMtdwIye0tYvdVQ8xr4h1tszCR//PwfAaK4BzPCgLPyXpHeJklPjyvKiedVyfOQywpGNRaZN2phQ8RFEN7XXw2PI1+AEZue27nWrDnCR17ExKKWdithPbIrFfi40bn03YuIgq91LURyqM6KE71IU6gNjQlRyko+F0M7W/tbELYZCOw3erctY70JBbWG3KtqW/3sXF6GoGYE4z0v206NmxwndlQ/fd3Vh05toAIqAR+Vx6lebHF7NG4Ki4b7ReuodNMjrDYo28o0EiVapQcXhU1G0FU4o= diff --git a/src/doc/book/CONTRIBUTING.md b/src/doc/book/CONTRIBUTING.md new file mode 100644 index 0000000000..d80c4e330a --- /dev/null +++ b/src/doc/book/CONTRIBUTING.md @@ -0,0 +1,96 @@ +# Contributing + +## First edition + +The first edition of the book is no longer actively being worked on, since +we're concentrating our efforts on bringing the second edition to print. We +will accept pull requests for small tweaks to the first edition; any larger +work should be spent improving the second edition. Issues will likely be closed +unless they are also issues in the second edition. + +## Second edition + +We're currently working with No Starch Press to bring the second edition of the +book to print. Each chapter goes through [a number of stages][project]: + +[project]: https://github.com/rust-lang/book/projects/1 + +* We write and edit a chapter's initial content +* No Starch provides a round of edits and questions +* We revise, clarify, and check those edits +* A Technical Reviewer checks for the accuracy of technical details +* No Starch copyedits the chapter for spelling, grammar, wording, consistency +* We revise, clarify, and check the copyedits +* The chapter goes to layout, at which point only minor changes should be made + +### Corrections and Modifications + +We would love issues and pull requests to the Markdown files in the src +directory, up until the chapter goes to layout with No Starch. At that point, +we will likely only be accepting changes that correct factual errors or major +problems and not, for example, minor wording changes. + +You can check which chapters have gone to layout and are frozen on the [project +page][project] by scrolling all the way to the right to find the column titled +**Frozen**. + +### Review + +Our [open pull requests][pulls] are new chapters or edits that we're currently +working on. We would love if you would read through those and make comments for +any suggestions or corrections! + +[pulls]: https://github.com/rust-lang/book/pulls + +### Translations + +We'd especially love help translating the second edition of the book! See the +[Translations] label to join in efforts that are currently in progress. Open +a new issue to start working on a new language! We're waiting on [mdbook +support] for multiple languages before we merge any in, but feel free to +start! The chapters in [the frozen column] of the project won't see major +changes, so if you start with those, you won't have to redo work :) + +[Translations]: https://github.com/rust-lang/book/issues?q=is%3Aopen+is%3Aissue+label%3ATranslations +[mdbook support]: https://github.com/azerupi/mdBook/issues/5 +[the frozen column]: https://github.com/rust-lang/book/projects/1 + +### Help wanted + +If you're looking for ways to help that don't involve large amounts of reading +or writing, check out the [open issues with the E-help-wanted +label][help-wanted]. These might be small fixes to the text Rust code, frontend +code, or shell scripts that would help us be more efficient or enhance the book +in some way! + +[help-wanted]: https://github.com/rust-lang/book/issues?q=is%3Aopen+is%3Aissue+label%3AE-help-wanted + +### Post-publication + +After the second edition of the book goes to print, here are our intentions for +changes: + +* The online version should stay fairly close to the printed version. For + example, you should be able to look at listing 10-3 in the book and find + listing 10-3 in the online version and copy-paste the code if you want to + play with it. Major changes to correct errors should get documented in + errata. +* There are multiple efforts starting to translate the online book into + other languages. It would help the translations stay in sync if we're not + constantly changing the text. +* Someday there might be a third edition, once there are enough large, new + features in Rust to warrant such a thing. We don't have any schedule in mind + for that though, nor have we decided if it would be modifications to the + second edition or a ground-up rewrite. Until we have plans for that, we won't + be accepting pull requests that aren't fixing errors, for example, changing + the way something is worded. +* New features added to Rust will be documented in the ["Newest Features" + Appendix][new] per [RFC 1636][rfc]. We'd love pull requests adding new + sections! These sections may be incorporated into the book at some point, but + we have no timeline for doing so. Incorporating these sections might be what + the third edition ends up being, we're not sure yet. + +[new]: https://github.com/rust-lang/book/blob/master/second-edition/src/appendix-07-newest-features.md +[rfc]: https://github.com/rust-lang/rfcs/pull/1636#issuecomment-247325313 + +This repository is under the same license as Rust itself, MIT/Apache2. diff --git a/src/doc/book/COPYRIGHT b/src/doc/book/COPYRIGHT new file mode 100644 index 0000000000..19559fa295 --- /dev/null +++ b/src/doc/book/COPYRIGHT @@ -0,0 +1,290 @@ +Short version for non-lawyers: + +The Rust Project is dual-licensed under Apache 2.0 and MIT +terms. + + +Longer version: + +The Rust Project is copyright 2010, The Rust Project +Developers. + +Licensed under the Apache License, Version 2.0 + or the MIT +license , +at your option. All files in the project carrying such +notice may not be copied, modified, or distributed except +according to those terms. + + +The Rust Project includes packages written by third parties. +The following third party packages are included, and carry +their own copyright notices and license terms: + +* The src/rt/miniz.c file, carrying an implementation of + RFC1950/RFC1951 DEFLATE, by Rich Geldreich + . All uses of this file are + permitted by the embedded "unlicense" notice + (effectively: public domain with warranty disclaimer). + +* LLVM. Code for this package is found in src/llvm. + + Copyright (c) 2003-2013 University of Illinois at + Urbana-Champaign. All rights reserved. + + Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal with the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: + + * Redistributions of source code must retain the + above copyright notice, this list of conditions + and the following disclaimers. + + * Redistributions in binary form must reproduce the + above copyright notice, this list of conditions + and the following disclaimers in the documentation + and/or other materials provided with the + distribution. + + * Neither the names of the LLVM Team, University of + Illinois at Urbana-Champaign, nor the names of its + contributors may be used to endorse or promote + products derived from this Software without + specific prior written permission. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT + OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS WITH THE SOFTWARE. + +* Additional libraries included in LLVM carry separate + BSD-compatible licenses. See src/llvm/LICENSE.txt for + details. + +* compiler-rt, in src/compiler-rt is dual licensed under + LLVM's license and MIT: + + Copyright (c) 2009-2014 by the contributors listed in + CREDITS.TXT + + All rights reserved. + + Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal with the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: + + * Redistributions of source code must retain the + above copyright notice, this list of conditions + and the following disclaimers. + + * Redistributions in binary form must reproduce the + above copyright notice, this list of conditions + and the following disclaimers in the documentation + and/or other materials provided with the + distribution. + + * Neither the names of the LLVM Team, University of + Illinois at Urbana-Champaign, nor the names of its + contributors may be used to endorse or promote + products derived from this Software without + specific prior written permission. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT + OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS WITH THE SOFTWARE. + + ======================================================== + + Copyright (c) 2009-2014 by the contributors listed in + CREDITS.TXT + + Permission is hereby granted, free of charge, to any + person obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the + Software without restriction, including without + limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice + shall be included in all copies or substantial portions + of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + +* Portions of the FFI code for interacting with the native ABI + is derived from the Clay programming language, which carries + the following license. + + Copyright (C) 2008-2010 Tachyon Technologies. + All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, are permitted provided that the + following conditions are met: + + 1. Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + + 2. Redistributions in binary form must reproduce the + above copyright notice, this list of conditions and + the following disclaimer in the documentation and/or + other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. + +* libbacktrace, under src/libbacktrace: + + Copyright (C) 2012-2014 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + + Redistribution and use in source and binary forms, with + or without modification, are permitted provided that the + following conditions are met: + + (1) Redistributions of source code must retain the + above copyright notice, this list of conditions and + the following disclaimer. + + (2) Redistributions in binary form must reproduce + the above copyright notice, this list of conditions + and the following disclaimer in the documentation + and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. */ + +* jemalloc, under src/jemalloc: + + Copyright (C) 2002-2014 Jason Evans + . All rights reserved. + Copyright (C) 2007-2012 Mozilla Foundation. + All rights reserved. + Copyright (C) 2009-2014 Facebook, Inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright notice(s), + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice(s), + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + OF SUCH DAMAGE. + +* Additional copyright may be retained by contributors other + than Mozilla, the Rust Project Developers, or the parties + enumerated in this file. Such copyright can be determined + on a case-by-case basis by examining the author of each + portion of a file in the revision-control commit records + of the project, or by consulting representative comments + claiming copyright ownership for a file. + + For example, the text: + + "Copyright (c) 2011 Google Inc." + + appears in some files, and these files thereby denote + that their author and copyright-holder is Google Inc. + + In all such cases, the absence of explicit licensing text + indicates that the contributor chose to license their work + for distribution under identical terms to those Mozilla + has chosen for the collective work, enumerated at the top + of this file. The only difference is the retention of + copyright itself, held by the contributor. diff --git a/src/doc/book/LICENSE-APACHE b/src/doc/book/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/src/doc/book/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/doc/book/LICENSE-MIT b/src/doc/book/LICENSE-MIT new file mode 100644 index 0000000000..25597d5838 --- /dev/null +++ b/src/doc/book/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2010 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/doc/book/README.md b/src/doc/book/README.md new file mode 100644 index 0000000000..3bec4b5086 --- /dev/null +++ b/src/doc/book/README.md @@ -0,0 +1,127 @@ +# The Rust Programming Language + +[![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”. + +The second edition is a rewrite that will be printed by NoStarch Press, +available around October 2017. + +[You can read it 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. + +[html]: http://rust-lang.github.io/book/ + +[The first edition is still available to read online][first]. + +[first]: https://doc.rust-lang.org/book/ + +## Requirements + +Building the book requires [mdBook] >= v0.0.13. To get it: + +[mdBook]: https://github.com/azerupi/mdBook + +```bash +$ cargo install mdbook +``` + +## Building + +To build the book, first `cd` into either the `first-edition` or +`second-edition` directory depending on which edition of the book you would +like to build. Then type: + +```bash +$ mdbook build +``` + +The output will be in the `book` subdirectory. To check it out, open it in +your web browser. + +_Firefox:_ +```bash +$ firefox book/index.html # Linux +$ open -a "Firefox" book/index.html # OS X +$ Start-Process "firefox.exe" .\book\index.html # Windows (PowerShell) +$ start firefox.exe .\book\index.html # Windows (Cmd) +``` + +_Chrome:_ +```bash +$ google-chrome book/index.html # Linux +$ open -a "Google Chrome" book/index.html # OS X +$ Start-Process "chrome.exe" .\book\index.html # Windows (PowerShell) +$ start chrome.exe .\book\index.html # Windows (Cmd) +``` + +To run the tests: + +```bash +$ mdbook test +``` + +## Contributing + +We'd love your help! Please see [CONTRIBUTING.md][contrib] to learn about the +kinds of contributions we're looking for. + +[contrib]: https://github.com/rust-lang/book/blob/master/CONTRIBUTING.md + +### Translations + +We'd especially love help translating the second edition of the book! See the +[Translations] label to join in efforts that are currently in progress. Open +a new issue to start working on a new language! We're waiting on [mdbook +support] for multiple languages before we merge any in, but feel free to +start! The chapters in [the frozen column] of the project won't see major +changes, so if you start with those, you won't have to redo work :) + +[Translations]: https://github.com/rust-lang/book/issues?q=is%3Aopen+is%3Aissue+label%3ATranslations +[mdbook support]: https://github.com/azerupi/mdBook/issues/5 +[the frozen column]: https://github.com/rust-lang/book/projects/1 + +## No Starch + +As the second edition of the book will be published by No Starch, we first +iterate here, then ship the text off to No Starch. Then they do editing, and we +fold it back in. + +As such, there’s a directory, *nostarch*, which corresponds to the text in No +Starch’s system. + +When we've started working with No Starch in a word doc, we will also check +those into the repo in the *nostarch/odt* directory. To extract the text from +the word doc as markdown in order to backport changes to the online book: + +1. Open the doc file in LibreOffice +1. Accept all tracked changes +1. Save as Microsoft Word 2007-2013 XML (.docx) in the *tmp* directory +1. Run `./doc-to-md.sh` +1. Inspect changes made to the markdown file in the *nostarch* directory and + copy the changes to the *src* directory as appropriate. + +## Graphviz dot + +This is mostly for Carol's reference because she keeps having to look it up. + +We're using [Graphviz](http://graphviz.org/) for some of the diagrams in the +book. The source for those files live in the `dot` directory. To turn a `dot` +file, for example, `dot/trpl04-01.dot` into an `svg`, run: + +```bash +$ dot dot/trpl04-01.dot -Tsvg > src/img/trpl04-01.svg +``` + +In the generated SVG, remove the width and the height attributes from the `svg` +element and set the `viewBox` attribute to `0.00 0.00 1000.00 1000.00` or other +values that don't cut off the image. + +## Spellchecking + +To scan source files for spelling errors, you can use the `spellcheck.sh` +script. It needs a dictionary of valid words, which is provided in +`dictionary.txt`. If the script produces a false positive (say, you used word +`BTreeMap` which the script considers invalid), you need to add this word to +`dictionary.txt` (keep the sorted order for consistency). diff --git a/src/doc/book/ci/build.sh b/src/doc/book/ci/build.sh new file mode 100644 index 0000000000..dfe69bf6c7 --- /dev/null +++ b/src/doc/book/ci/build.sh @@ -0,0 +1,29 @@ +# 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 -e + +export PATH=$PATH:/home/travis/.cargo/bin; + +# feature check +cd ci/stable-check + +cargo run -- ../../first-edition/src +cargo run -- ../../second-edition/src + +cd ../.. + +# tests for the second edition + +cd second-edition +bash spellcheck.sh list +mdbook test +mdbook build +cargo run --bin lfp src diff --git a/src/doc/book/ci/deploy.sh b/src/doc/book/ci/deploy.sh new file mode 100644 index 0000000000..50a8fab353 --- /dev/null +++ b/src/doc/book/ci/deploy.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -o errexit -o nounset + +export PATH=$PATH:/home/travis/.cargo/bin; + +rev=$(git rev-parse --short HEAD) + +# make a scratch directory, this will correspond to +# https://rust-lang.github.io/book +mkdir book + +# build the index page into it +rustdoc index.md -o book/ + +# build the first edition into it +mdbook build first-edition +mv first-edition/book book/first-edition/ + + +# build the second edition into it +mdbook build second-edition +mv second-edition/book book/second-edition/ + +# move into the book dir and push it + +cd book + +git init +git config user.name "Steve Klabnik" +git config user.email "steve@steveklabnik.com" + +git remote add upstream "https://$GH_TOKEN@github.com/rust-lang/book.git" +git fetch upstream +git reset upstream/gh-pages + +touch . + +git add -A . +git commit -m "rebuild pages at ${rev}" +git push -q upstream HEAD:gh-pages > /dev/null 2>&1 diff --git a/src/doc/book/ci/stable-check/Cargo.lock b/src/doc/book/ci/stable-check/Cargo.lock new file mode 100644 index 0000000000..9a3b307c96 --- /dev/null +++ b/src/doc/book/ci/stable-check/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "stable-check" +version = "0.1.0" + diff --git a/src/doc/book/ci/stable-check/Cargo.toml b/src/doc/book/ci/stable-check/Cargo.toml new file mode 100644 index 0000000000..691722a0b2 --- /dev/null +++ b/src/doc/book/ci/stable-check/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "stable-check" +version = "0.1.0" +authors = ["steveklabnik "] + +[dependencies] diff --git a/src/doc/book/ci/stable-check/src/main.rs b/src/doc/book/ci/stable-check/src/main.rs new file mode 100644 index 0000000000..fafc1015fd --- /dev/null +++ b/src/doc/book/ci/stable-check/src/main.rs @@ -0,0 +1,53 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::error::Error; +use std::env; +use std::fs; +use std::fs::File; +use std::io::prelude::*; +use std::path::Path; + +fn main() { + let arg = env::args().nth(1).unwrap_or_else(|| { + println!("Please pass a src directory as the first argument"); + std::process::exit(1); + }); + + match check_directory(&Path::new(&arg)) { + Ok(()) => println!("passed!"), + Err(e) => { + println!("Error: {}", e); + std::process::exit(1); + } + } + +} + +fn check_directory(dir: &Path) -> Result<(), Box> { + for entry in fs::read_dir(dir)? { + let entry = entry?; + let path = entry.path(); + + if path.is_dir() { + continue; + } + + let mut file = File::open(&path)?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + + if contents.contains("#![feature") { + return Err(From::from(format!("Feature flag found in {:?}", path))); + } + } + + Ok(()) +} diff --git a/src/doc/book/first-edition/book.toml b/src/doc/book/first-edition/book.toml new file mode 100644 index 0000000000..f3ae80a39d --- /dev/null +++ b/src/doc/book/first-edition/book.toml @@ -0,0 +1,2 @@ +title = "The Rust Programming Language" +author = "The Rust Project Developers" diff --git a/src/doc/book/src/README.md b/src/doc/book/first-edition/src/README.md similarity index 100% rename from src/doc/book/src/README.md rename to src/doc/book/first-edition/src/README.md diff --git a/src/doc/book/src/SUMMARY.md b/src/doc/book/first-edition/src/SUMMARY.md similarity index 100% rename from src/doc/book/src/SUMMARY.md rename to src/doc/book/first-edition/src/SUMMARY.md diff --git a/src/doc/book/src/associated-types.md b/src/doc/book/first-edition/src/associated-types.md similarity index 100% rename from src/doc/book/src/associated-types.md rename to src/doc/book/first-edition/src/associated-types.md diff --git a/src/doc/book/src/attributes.md b/src/doc/book/first-edition/src/attributes.md similarity index 96% rename from src/doc/book/src/attributes.md rename to src/doc/book/first-edition/src/attributes.md index 103ec39aa3..49ac9b2c4f 100644 --- a/src/doc/book/src/attributes.md +++ b/src/doc/book/first-edition/src/attributes.md @@ -67,4 +67,4 @@ Rust attributes are used for a number of different things. There is a full list of attributes [in the reference][reference]. Currently, you are not allowed to create your own attributes, the Rust compiler defines them. -[reference]: ../reference/attributes.html +[reference]: ../../reference/attributes.html diff --git a/src/doc/book/src/bibliography.md b/src/doc/book/first-edition/src/bibliography.md similarity index 97% rename from src/doc/book/src/bibliography.md rename to src/doc/book/first-edition/src/bibliography.md index 07b2aa94a7..483c1e6221 100644 --- a/src/doc/book/src/bibliography.md +++ b/src/doc/book/first-edition/src/bibliography.md @@ -81,3 +81,4 @@ Language](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf). Early GPU work Munksgaard's master's thesis. Research for Servo. * [Ownership is Theft: Experiences Building an Embedded OS in Rust - Amit Levy, et. al.](http://amitlevy.com/papers/tock-plos2015.pdf) * [You can't spell trust without Rust](https://raw.githubusercontent.com/Gankro/thesis/master/thesis.pdf). Alexis Beingessner's master's thesis. +* [Rust as a Language for High Performance GC Implementation](http://users.cecs.anu.edu.au/~steveb/downloads/pdf/rust-ismm-2016.pdf) diff --git a/src/doc/book/src/borrow-and-asref.md b/src/doc/book/first-edition/src/borrow-and-asref.md similarity index 92% rename from src/doc/book/src/borrow-and-asref.md rename to src/doc/book/first-edition/src/borrow-and-asref.md index a6e396571c..3b1ef1a2ae 100644 --- a/src/doc/book/src/borrow-and-asref.md +++ b/src/doc/book/first-edition/src/borrow-and-asref.md @@ -3,8 +3,8 @@ The [`Borrow`][borrow] and [`AsRef`][asref] traits are very similar, but different. Here’s a quick refresher on what these two traits mean. -[borrow]: ../std/borrow/trait.Borrow.html -[asref]: ../std/convert/trait.AsRef.html +[borrow]: ../../std/borrow/trait.Borrow.html +[asref]: ../../std/convert/trait.AsRef.html # Borrow @@ -19,8 +19,8 @@ fn get(&self, k: &Q) -> Option<&V> Q: Hash + Eq ``` -[hashmap]: ../std/collections/struct.HashMap.html -[get]: ../std/collections/struct.HashMap.html#method.get +[hashmap]: ../../std/collections/struct.HashMap.html +[get]: ../../std/collections/struct.HashMap.html#method.get This signature is pretty complicated. The `K` parameter is what we’re interested in here. It refers to a parameter of the `HashMap` itself: diff --git a/src/doc/book/src/casting-between-types.md b/src/doc/book/first-edition/src/casting-between-types.md similarity index 100% rename from src/doc/book/src/casting-between-types.md rename to src/doc/book/first-edition/src/casting-between-types.md diff --git a/src/doc/book/src/chapter_1.md b/src/doc/book/first-edition/src/chapter_1.md similarity index 100% rename from src/doc/book/src/chapter_1.md rename to src/doc/book/first-edition/src/chapter_1.md diff --git a/src/doc/book/src/choosing-your-guarantees.md b/src/doc/book/first-edition/src/choosing-your-guarantees.md similarity index 97% rename from src/doc/book/src/choosing-your-guarantees.md rename to src/doc/book/first-edition/src/choosing-your-guarantees.md index 89dd09e670..b1ba4df24c 100644 --- a/src/doc/book/src/choosing-your-guarantees.md +++ b/src/doc/book/first-edition/src/choosing-your-guarantees.md @@ -38,7 +38,7 @@ This is a zero-cost abstraction for dynamic allocation. If you want to allocate heap and safely pass around a pointer to that memory, this is ideal. Note that you will only be allowed to share references to this by the regular borrowing rules, checked at compile time. -[box]: ../std/boxed/struct.Box.html +[box]: ../../std/boxed/struct.Box.html ## `&T` and `&mut T` @@ -104,7 +104,7 @@ two `usize` values) as compared to a regular `Box` (for "strong" and "weak" r or goes out of scope respectively. Note that a clone will not do a deep copy, rather it will simply increment the inner reference count and return a copy of the `Rc`. -[rc]: ../std/rc/struct.Rc.html +[rc]: ../../std/rc/struct.Rc.html # Cell types @@ -234,9 +234,9 @@ indicator (one word in size) along with the data. At runtime each borrow causes a modification/check of the refcount. -[cell-mod]: ../std/cell/index.html -[cell]: ../std/cell/struct.Cell.html -[refcell]: ../std/cell/struct.RefCell.html +[cell-mod]: ../../std/cell/index.html +[cell]: ../../std/cell/struct.Cell.html +[refcell]: ../../std/cell/struct.RefCell.html # Synchronous types @@ -252,7 +252,7 @@ time. There are many useful wrappers for concurrent programming in the [sync][sync] module, but only the major ones will be covered below. -[sync]: ../std/sync/index.html +[sync]: ../../std/sync/index.html ## `Arc` @@ -280,7 +280,7 @@ This has the added cost of using atomics for changing the refcount (which will h cloned or goes out of scope). When sharing data from an `Arc` in a single thread, it is preferable to share `&` pointers whenever possible. -[arc]: ../std/sync/struct.Arc.html +[arc]: ../../std/sync/struct.Arc.html ## `Mutex` and `RwLock` @@ -316,8 +316,8 @@ These use internal atomic-like types to maintain the locks, which are pretty cos all memory reads across processors till they're done). Waiting on these locks can also be slow when there's a lot of concurrent access happening. -[rwlock]: ../std/sync/struct.RwLock.html -[mutex]: ../std/sync/struct.Mutex.html +[rwlock]: ../../std/sync/struct.RwLock.html +[mutex]: ../../std/sync/struct.Mutex.html [sessions]: https://github.com/Munksgaard/rust-sessions # Composition diff --git a/src/doc/book/src/closures.md b/src/doc/book/first-edition/src/closures.md similarity index 96% rename from src/doc/book/src/closures.md rename to src/doc/book/first-edition/src/closures.md index 5426ed0ff4..0fe08bfb68 100644 --- a/src/doc/book/src/closures.md +++ b/src/doc/book/first-edition/src/closures.md @@ -222,26 +222,11 @@ operator. From this, everything else clicks into place. In Rust, we use the trait system to overload operators. Calling functions is no different. We have three separate traits to overload with: -```rust -# #![feature(unboxed_closures)] -# mod foo { -pub trait Fn : FnMut { - extern "rust-call" fn call(&self, args: Args) -> Self::Output; -} - -pub trait FnMut : FnOnce { - extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; -} - -pub trait FnOnce { - type Output; - - extern "rust-call" fn call_once(self, args: Args) -> Self::Output; -} -# } -``` +* `Fn` +* `FnMut` +* `FnOnce` -You’ll notice a few differences between these traits, but a big one is `self`: +There are a few differences between these traits, but a big one is `self`: `Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This covers all three kinds of `self` via the usual method call syntax. But we’ve split them up into three traits, rather than having a single one. This gives us diff --git a/src/doc/book/src/comments.md b/src/doc/book/first-edition/src/comments.md similarity index 100% rename from src/doc/book/src/comments.md rename to src/doc/book/first-edition/src/comments.md diff --git a/src/doc/book/src/concurrency.md b/src/doc/book/first-edition/src/concurrency.md similarity index 97% rename from src/doc/book/src/concurrency.md rename to src/doc/book/first-edition/src/concurrency.md index afed379fe4..0fd71ee6d1 100644 --- a/src/doc/book/src/concurrency.md +++ b/src/doc/book/first-edition/src/concurrency.md @@ -26,7 +26,7 @@ to help us make sense of code that can possibly be concurrent. ### `Send` The first trait we're going to talk about is -[`Send`](../std/marker/trait.Send.html). When a type `T` implements `Send`, it +[`Send`](../../std/marker/trait.Send.html). When a type `T` implements `Send`, it indicates that something of this type is able to have ownership transferred safely between threads. @@ -43,7 +43,7 @@ us enforce that it can't leave the current thread. ### `Sync` -The second of these traits is called [`Sync`](../std/marker/trait.Sync.html). +The second of these traits is called [`Sync`](../../std/marker/trait.Sync.html). When a type `T` implements `Sync`, it indicates that something of this type has no possibility of introducing memory unsafety when used from multiple threads concurrently through shared references. This implies that @@ -238,7 +238,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 -matter and can have a data race. +manner and can have a data race. To solve this, we'll use `Arc`, Rust's standard atomic reference count type. @@ -333,8 +333,8 @@ locked, it will wait until the other thread releases the lock. The lock "release" here is implicit; when the result of the lock (in this case, `data`) goes out of scope, the lock is automatically released. -Note that [`lock`](../std/sync/struct.Mutex.html#method.lock) method of -[`Mutex`](../std/sync/struct.Mutex.html) has this signature: +Note that [`lock`](../../std/sync/struct.Mutex.html#method.lock) method of +[`Mutex`](../../std/sync/struct.Mutex.html) has this signature: ```rust,ignore fn lock(&self) -> LockResult> diff --git a/src/doc/book/src/conditional-compilation.md b/src/doc/book/first-edition/src/conditional-compilation.md similarity index 100% rename from src/doc/book/src/conditional-compilation.md rename to src/doc/book/first-edition/src/conditional-compilation.md diff --git a/src/doc/book/src/const-and-static.md b/src/doc/book/first-edition/src/const-and-static.md similarity index 100% rename from src/doc/book/src/const-and-static.md rename to src/doc/book/first-edition/src/const-and-static.md diff --git a/src/doc/book/src/crates-and-modules.md b/src/doc/book/first-edition/src/crates-and-modules.md similarity index 96% rename from src/doc/book/src/crates-and-modules.md rename to src/doc/book/first-edition/src/crates-and-modules.md index 84f5fac044..10e66d42c6 100644 --- a/src/doc/book/src/crates-and-modules.md +++ b/src/doc/book/first-edition/src/crates-and-modules.md @@ -176,23 +176,28 @@ mod english; mod japanese; ``` -These two declarations tell Rust to look for either `src/english.rs` and -`src/japanese.rs`, or `src/english/mod.rs` and `src/japanese/mod.rs`, depending -on our preference. In this case, because our modules have sub-modules, we’ve -chosen the second. Both `src/english/mod.rs` and `src/japanese/mod.rs` look -like this: +These two declarations tell Rust to look for + +- either `src/english.rs` or `src/english/mod.rs`, and +- either `src/japanese.rs` or `src/japanese/mod.rs`, + +depending on our preference. In this case, because our modules have sub-modules, +we’ve chosen the `mod.rs` approach. Both `src/english/mod.rs` and +`src/japanese/mod.rs` look like this: ```rust,ignore mod greetings; mod farewells; ``` -Again, these declarations tell Rust to look for either -`src/english/greetings.rs`, `src/english/farewells.rs`, -`src/japanese/greetings.rs` and `src/japanese/farewells.rs` or -`src/english/greetings/mod.rs`, `src/english/farewells/mod.rs`, -`src/japanese/greetings/mod.rs` and -`src/japanese/farewells/mod.rs`. Because these sub-modules don’t have +Again, these declarations tell Rust to look for + +- `src/english/greetings.rs` or `src/english/greetings/mod.rs`, +- `src/english/farewells.rs` or `src/english/farewells/mod.rs`, +- `src/japanese/greetings.rs` or `src/japanese/greetings/mod.rs`, +- and `src/japanese/farewells.rs` or `src/japanese/farewells/mod.rs`. + +Because these sub-modules don’t have their own sub-modules, we’ve chosen to make them `src/english/greetings.rs`, `src/english/farewells.rs`, `src/japanese/greetings.rs` and `src/japanese/farewells.rs`. Whew! diff --git a/src/doc/book/src/deref-coercions.md b/src/doc/book/first-edition/src/deref-coercions.md similarity index 98% rename from src/doc/book/src/deref-coercions.md rename to src/doc/book/first-edition/src/deref-coercions.md index 8552a7c8b3..e62c50ac8d 100644 --- a/src/doc/book/src/deref-coercions.md +++ b/src/doc/book/first-edition/src/deref-coercions.md @@ -24,7 +24,7 @@ fn main() { } ``` -[deref]: ../std/ops/trait.Deref.html +[deref]: ../../std/ops/trait.Deref.html This is useful for writing custom pointer types. However, there’s a language feature related to `Deref`: ‘deref coercions’. Here’s the rule: If you have a diff --git a/src/doc/book/src/documentation.md b/src/doc/book/first-edition/src/documentation.md similarity index 95% rename from src/doc/book/src/documentation.md rename to src/doc/book/first-edition/src/documentation.md index 69d49e2f96..6a2c85035a 100644 --- a/src/doc/book/src/documentation.md +++ b/src/doc/book/first-edition/src/documentation.md @@ -76,7 +76,7 @@ This [unfortunate error](https://github.com/rust-lang/rust/issues/22547) is correct; documentation comments apply to the thing after them, and there's nothing after that last comment. -[rc-new]: ../std/rc/struct.Rc.html#method.new +[rc-new]: ../../std/rc/struct.Rc.html#method.new ### Writing documentation comments @@ -170,8 +170,6 @@ more than one section: # fn foo() {} ``` -Let's discuss the details of these code blocks. - #### Code block annotations To write some Rust code in a comment, use the triple graves: @@ -183,23 +181,8 @@ To write some Rust code in a comment, use the triple graves: # fn foo() {} ``` -If you want something that's not Rust code, you can add an annotation: - -```rust -/// ```c -/// printf("Hello, world\n"); -/// ``` -# fn foo() {} -``` - -This will highlight according to whatever language you're showing off. -If you're only showing plain text, choose `text`. - -It's important to choose the correct annotation here, because `rustdoc` uses it -in an interesting way: It can be used to actually test your examples in a -library crate, so that they don't get out of date. If you have some C code but -`rustdoc` thinks it's Rust because you left off the annotation, `rustdoc` will -complain when trying to generate the documentation. +This will add code highlighting. If you are only showing plain text, put `text` +instead of `rust` after the triple graves (see below). ## Documentation as tests diff --git a/src/doc/book/src/drop.md b/src/doc/book/first-edition/src/drop.md similarity index 95% rename from src/doc/book/src/drop.md rename to src/doc/book/first-edition/src/drop.md index 53c507eba3..1d8c9a3afb 100644 --- a/src/doc/book/src/drop.md +++ b/src/doc/book/first-edition/src/drop.md @@ -4,7 +4,7 @@ Now that we’ve discussed traits, let’s talk about a particular trait provide by the Rust standard library, [`Drop`][drop]. The `Drop` trait provides a way to run some code when a value goes out of scope. For example: -[drop]: ../std/ops/trait.Drop.html +[drop]: ../../std/ops/trait.Drop.html ```rust struct HasDrop; @@ -64,4 +64,4 @@ reference-counted type. When `Drop` is called, it will decrement the reference count, and if the total number of references is zero, will clean up the underlying value. -[arc]: ../std/sync/struct.Arc.html +[arc]: ../../std/sync/struct.Arc.html diff --git a/src/doc/book/src/effective-rust.md b/src/doc/book/first-edition/src/effective-rust.md similarity index 100% rename from src/doc/book/src/effective-rust.md rename to src/doc/book/first-edition/src/effective-rust.md diff --git a/src/doc/book/src/enums.md b/src/doc/book/first-edition/src/enums.md similarity index 100% rename from src/doc/book/src/enums.md rename to src/doc/book/first-edition/src/enums.md diff --git a/src/doc/book/src/error-handling.md b/src/doc/book/first-edition/src/error-handling.md similarity index 95% rename from src/doc/book/src/error-handling.md rename to src/doc/book/first-edition/src/error-handling.md index c823c32a13..02bd67587a 100644 --- a/src/doc/book/src/error-handling.md +++ b/src/doc/book/first-edition/src/error-handling.md @@ -59,7 +59,7 @@ handling is reducing the amount of explicit case analysis the programmer has to do while keeping code composable. Keeping code composable is important, because without that requirement, we -could [`panic`](../std/macro.panic.html) whenever we +could [`panic`](../../std/macro.panic.html) whenever we come across something unexpected. (`panic` causes the current task to unwind, and in most cases, the entire program aborts.) Here's an example: @@ -236,7 +236,7 @@ fn extension_explicit(file_name: &str) -> Option<&str> { ``` (Pro-tip: don't use this code. Use the -[`extension`](../std/path/struct.Path.html#method.extension) +[`extension`](../../std/path/struct.Path.html#method.extension) method in the standard library instead.) The code stays simple, but the important thing to notice is that the type of @@ -530,10 +530,10 @@ above is generic over all the different number types defined in the standard library. We could (and probably should) also make our function generic, but let's favor explicitness for the moment. We only care about `i32`, so we need to [find its implementation of -`FromStr`](../std/primitive.i32.html) (do a `CTRL-F` in your browser +`FromStr`](../../std/primitive.i32.html) (do a `CTRL-F` in your browser for “FromStr”) and look at its [associated type][10] `Err`. We did this so we can find the concrete error type. In this case, it's -[`std::num::ParseIntError`](../std/num/struct.ParseIntError.html). +[`std::num::ParseIntError`](../../std/num/struct.ParseIntError.html). Finally, we can rewrite our function: ```rust @@ -577,12 +577,12 @@ fn main() { ``` The usual suspects are all there for `Result`, including -[`unwrap_or`](../std/result/enum.Result.html#method.unwrap_or) and -[`and_then`](../std/result/enum.Result.html#method.and_then). +[`unwrap_or`](../../std/result/enum.Result.html#method.unwrap_or) and +[`and_then`](../../std/result/enum.Result.html#method.and_then). Additionally, since `Result` has a second type parameter, there are combinators that affect only the error type, such as -[`map_err`](../std/result/enum.Result.html#method.map_err) (instead of -`map`) and [`or_else`](../std/result/enum.Result.html#method.or_else) +[`map_err`](../../std/result/enum.Result.html#method.map_err) (instead of +`map`) and [`or_else`](../../std/result/enum.Result.html#method.or_else) (instead of `and_then`). ### The `Result` type alias idiom @@ -611,11 +611,11 @@ Why would we do this? Well, if we have a lot of functions that could return uses `ParseIntError` so that we don't have to write it out all the time. The most prominent place this idiom is used in the standard library is -with [`io::Result`](../std/io/type.Result.html). Typically, one writes +with [`io::Result`](../../std/io/type.Result.html). Typically, one writes `io::Result`, which makes it clear that you're using the `io` module's type alias instead of the plain definition from `std::result`. (This idiom is also used for -[`fmt::Result`](../std/fmt/type.Result.html).) +[`fmt::Result`](../../std/fmt/type.Result.html).) ## A brief interlude: unwrapping isn't evil @@ -639,7 +639,7 @@ summarize some of my *opinions* on the matter. This is probably not an exhaustive list. Moreover, when using an `Option`, it is often better to use its -[`expect`](../std/option/enum.Option.html#method.expect) +[`expect`](../../std/option/enum.Option.html#method.expect) method. `expect` does exactly the same thing as `unwrap`, except it prints a message you give to `expect`. This makes the resulting panic a bit nicer to deal with, since it will show your message instead of @@ -719,7 +719,7 @@ fn main() { ``` There are a couple new things in this example. The first is the use of the -[`Option::ok_or`](../std/option/enum.Option.html#method.ok_or) +[`Option::ok_or`](../../std/option/enum.Option.html#method.ok_or) combinator. This is one way to convert an `Option` into a `Result`. The conversion requires you to specify what error to use if `Option` is `None`. Like the other combinators we've seen, its definition is very simple: @@ -734,7 +734,7 @@ fn ok_or(option: Option, err: E) -> Result { ``` The other new combinator used here is -[`Result::map_err`](../std/result/enum.Result.html#method.map_err). +[`Result::map_err`](../../std/result/enum.Result.html#method.map_err). This is like `Result::map`, except it maps a function on to the *error* portion of a `Result` value. If the `Result` is an `Ok(...)` value, then it is returned unmodified. @@ -781,7 +781,7 @@ fn main() { (N.B. The `AsRef` is used because those are the [same bounds used on -`std::fs::File::open`](../std/fs/struct.File.html#method.open). +`std::fs::File::open`](../../std/fs/struct.File.html#method.open). This makes it ergonomic to use any kind of string as a file path.) There are three different errors that can occur here: @@ -791,16 +791,16 @@ There are three different errors that can occur here: 3. A problem parsing the data as a number. The first two problems are described via the -[`std::io::Error`](../std/io/struct.Error.html) type. We know this +[`std::io::Error`](../../std/io/struct.Error.html) type. We know this because of the return types of -[`std::fs::File::open`](../std/fs/struct.File.html#method.open) and -[`std::io::Read::read_to_string`](../std/io/trait.Read.html#method.read_to_string). +[`std::fs::File::open`](../../std/fs/struct.File.html#method.open) and +[`std::io::Read::read_to_string`](../../std/io/trait.Read.html#method.read_to_string). (Note that they both use the [`Result` type alias idiom](#the-result-type-alias-idiom) described previously. If you click on the `Result` type, you'll [see the type -alias](../std/io/type.Result.html), and consequently, the underlying +alias](../../std/io/type.Result.html), and consequently, the underlying `io::Error` type.) The third problem is described by the -[`std::num::ParseIntError`](../std/num/struct.ParseIntError.html) +[`std::num::ParseIntError`](../../std/num/struct.ParseIntError.html) type. The `io::Error` type in particular is *pervasive* throughout the standard library. You will see it again and again. @@ -944,7 +944,7 @@ macro_rules! try { } ``` -(The [real definition](../std/macro.try.html) is a bit more +(The [real definition](../../std/macro.try.html) is a bit more sophisticated. We will address that later.) Using the `try!` macro makes it very easy to simplify our last example. Since @@ -1003,7 +1003,7 @@ determine the type of error is not robust. (Admittedly, this downside is far more important inside of a library as opposed to, say, an application.) For example, the `io::Error` type embeds an -[`io::ErrorKind`](../std/io/enum.ErrorKind.html), +[`io::ErrorKind`](../../std/io/enum.ErrorKind.html), which is *structured data* that represents what went wrong during an IO operation. This is important because you might want to react differently depending on the error. (e.g., A `BrokenPipe` error might mean quitting your @@ -1076,8 +1076,8 @@ that you don't remove choices from the caller unnecessarily. # Standard library traits used for error handling The standard library defines two integral traits for error handling: -[`std::error::Error`](../std/error/trait.Error.html) and -[`std::convert::From`](../std/convert/trait.From.html). While `Error` +[`std::error::Error`](../../std/error/trait.Error.html) and +[`std::convert::From`](../../std/convert/trait.From.html). While `Error` is designed specifically for generically describing errors, the `From` trait serves a more general role for converting values between two distinct types. @@ -1085,7 +1085,7 @@ distinct types. ## The `Error` trait The `Error` trait is [defined in the standard -library](../std/error/trait.Error.html): +library](../../std/error/trait.Error.html): ```rust use std::fmt::{Debug, Display}; @@ -1113,7 +1113,7 @@ The first two are a result of `Error` requiring impls for both `Debug` and `Display`. The latter two are from the two methods defined on `Error`. The power of `Error` comes from the fact that all error types impl `Error`, which means errors can be existentially quantified as a -[trait object](../book/trait-objects.html). +[trait object](trait-objects.html). This manifests as either `Box` or `&Error`. Indeed, the `cause` method returns an `&Error`, which is itself a trait object. We'll revisit the `Error` trait's utility as a trait object later. @@ -1189,7 +1189,7 @@ different error types and satisfy the contracts defined for `description` and The `std::convert::From` trait is [defined in the standard -library](../std/convert/trait.From.html): +library](../../std/convert/trait.From.html): @@ -1204,7 +1204,7 @@ way to talk about conversion *from* a particular type `T` to some other type (in this case, “some other type” is the subject of the impl, or `Self`). The crux of `From` is the [set of implementations provided by the standard -library](../std/convert/trait.From.html). +library](../../std/convert/trait.From.html). Here are a few simple examples demonstrating how `From` works: @@ -1271,7 +1271,7 @@ macro_rules! try { ``` This is not its real definition. Its real definition is -[in the standard library](../std/macro.try.html): +[in the standard library](../../std/macro.try.html): @@ -1340,8 +1340,8 @@ There's one little nit left: the `Box` type is *opaque*. If we return a `Box` to the caller, the caller can't (easily) inspect underlying error type. The situation is certainly better than `String` because the caller can call methods like -[`description`](../std/error/trait.Error.html#tymethod.description) -and [`cause`](../std/error/trait.Error.html#method.cause), but the +[`description`](../../std/error/trait.Error.html#tymethod.description) +and [`cause`](../../std/error/trait.Error.html#method.cause), but the limitation remains: `Box` is opaque. (N.B. This isn't entirely true because Rust does have runtime reflection, which is useful in some scenarios that are [beyond the scope of this @@ -1484,14 +1484,14 @@ And that's it! If your library needs to report custom errors, then you should probably define your own error type. It's up to you whether or not to expose its representation (like -[`ErrorKind`](../std/io/enum.ErrorKind.html)) or keep it hidden (like -[`ParseIntError`](../std/num/struct.ParseIntError.html)). Regardless +[`ErrorKind`](../../std/io/enum.ErrorKind.html)) or keep it hidden (like +[`ParseIntError`](../../std/num/struct.ParseIntError.html)). Regardless of how you do it, it's usually good practice to at least provide some information about the error beyond its `String` representation. But certainly, this will vary depending on use cases. At a minimum, you should probably implement the -[`Error`](../std/error/trait.Error.html) +[`Error`](../../std/error/trait.Error.html) trait. This will give users of your library some minimum flexibility for [composing errors](#the-real-try-macro). Implementing the `Error` trait also means that users are guaranteed the ability to obtain a string representation @@ -1507,8 +1507,8 @@ provides `From` impls for both `io::Error` and `byteorder::Error`. Finally, depending on your tastes, you may also want to define a [`Result` type alias](#the-result-type-alias-idiom), particularly if your library defines a single error type. This is used in the standard library -for [`io::Result`](../std/io/type.Result.html) -and [`fmt::Result`](../std/fmt/type.Result.html). +for [`io::Result`](../../std/io/type.Result.html) +and [`fmt::Result`](../../std/fmt/type.Result.html). # Case study: A program to read population data @@ -1702,9 +1702,9 @@ fn main() { Let's outline the errors. We can start with the obvious: the three places that `unwrap` is called: -1. [`File::open`](../std/fs/struct.File.html#method.open) +1. [`File::open`](../../std/fs/struct.File.html#method.open) can return an - [`io::Error`](../std/io/struct.Error.html). + [`io::Error`](../../std/io/struct.Error.html). 2. [`csv::Reader::decode`](http://burntsushi.net/rustdoc/csv/struct.Reader.html#method.decode) decodes one record at a time, and [decoding a @@ -1859,7 +1859,7 @@ Instead of `x.unwrap()`, we now have `try!(x)`. Since our function returns a error occurs. At the end of `search` we also convert a plain string to an error type -by using the [corresponding `From` impls](../std/convert/trait.From.html): +by using the [corresponding `From` impls](../../std/convert/trait.From.html): ```rust,ignore // We are making use of this impl in the code above, since we call `From::from` @@ -2162,10 +2162,10 @@ heuristics! * If you're writing short example code that would be overburdened by error handling, it's probably fine to use `unwrap` (whether that's - [`Result::unwrap`](../std/result/enum.Result.html#method.unwrap), - [`Option::unwrap`](../std/option/enum.Option.html#method.unwrap) + [`Result::unwrap`](../../std/result/enum.Result.html#method.unwrap), + [`Option::unwrap`](../../std/option/enum.Option.html#method.unwrap) or preferably - [`Option::expect`](../std/option/enum.Option.html#method.expect)). + [`Option::expect`](../../std/option/enum.Option.html#method.expect)). Consumers of your code should know to use proper error handling. (If they don't, send them here!) * If you're writing a quick 'n' dirty program, don't feel ashamed if you use @@ -2175,37 +2175,37 @@ heuristics! anyway, then use either a `String` or a `Box` for your error type. * Otherwise, in a program, define your own error types with appropriate - [`From`](../std/convert/trait.From.html) + [`From`](../../std/convert/trait.From.html) and - [`Error`](../std/error/trait.Error.html) - impls to make the [`try!`](../std/macro.try.html) + [`Error`](../../std/error/trait.Error.html) + impls to make the [`try!`](../../std/macro.try.html) macro more ergonomic. * If you're writing a library and your code can produce errors, define your own error type and implement the - [`std::error::Error`](../std/error/trait.Error.html) + [`std::error::Error`](../../std/error/trait.Error.html) trait. Where appropriate, implement - [`From`](../std/convert/trait.From.html) to make both + [`From`](../../std/convert/trait.From.html) to make both your library code and the caller's code easier to write. (Because of Rust's coherence rules, callers will not be able to impl `From` on your error type, so your library should do it.) * Learn the combinators defined on - [`Option`](../std/option/enum.Option.html) + [`Option`](../../std/option/enum.Option.html) and - [`Result`](../std/result/enum.Result.html). + [`Result`](../../std/result/enum.Result.html). Using them exclusively can be a bit tiring at times, but I've personally found a healthy mix of `try!` and combinators to be quite appealing. `and_then`, `map` and `unwrap_or` are my favorites. -[1]: ../book/patterns.html -[2]: ../std/option/enum.Option.html#method.map -[3]: ../std/option/enum.Option.html#method.unwrap_or -[4]: ../std/option/enum.Option.html#method.unwrap_or_else -[5]: ../std/option/enum.Option.html -[6]: ../std/result/index.html -[7]: ../std/result/enum.Result.html#method.unwrap -[8]: ../std/fmt/trait.Debug.html -[9]: ../std/primitive.str.html#method.parse -[10]: ../book/associated-types.html +[1]: patterns.html +[2]: ../../std/option/enum.Option.html#method.map +[3]: ../../std/option/enum.Option.html#method.unwrap_or +[4]: ../../std/option/enum.Option.html#method.unwrap_or_else +[5]: ../../std/option/enum.Option.html +[6]: ../../std/result/index.html +[7]: ../../std/result/enum.Result.html#method.unwrap +[8]: ../../std/fmt/trait.Debug.html +[9]: ../../std/primitive.str.html#method.parse +[10]: associated-types.html [11]: https://github.com/petewarden/dstkdata [12]: http://burntsushi.net/stuff/worldcitiespop.csv.gz [13]: http://burntsushi.net/stuff/uscitiespop.csv.gz diff --git a/src/doc/book/src/ffi.md b/src/doc/book/first-edition/src/ffi.md similarity index 97% rename from src/doc/book/src/ffi.md rename to src/doc/book/first-edition/src/ffi.md index e9e2dab73e..067d061a86 100644 --- a/src/doc/book/src/ffi.md +++ b/src/doc/book/first-edition/src/ffi.md @@ -28,8 +28,7 @@ and add `extern crate libc;` to your crate root. The following is a minimal example of calling a foreign function which will compile if snappy is installed: -```rust,no_run -# #![feature(libc)] +```rust,ignore extern crate libc; use libc::size_t; @@ -62,8 +61,7 @@ of keeping the binding correct at runtime. The `extern` block can be extended to cover the entire snappy API: -```rust,no_run -# #![feature(libc)] +```rust,ignore extern crate libc; use libc::{c_int, size_t}; @@ -98,8 +96,7 @@ vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous length is the number of elements currently contained, and the capacity is the total size in elements of the allocated memory. The length is less than or equal to the capacity. -```rust -# #![feature(libc)] +```rust,ignore # extern crate libc; # use libc::{c_int, size_t}; # unsafe fn snappy_validate_compressed_buffer(_: *const u8, _: size_t) -> c_int { 0 } @@ -123,8 +120,7 @@ required capacity to hold the compressed output. The vector can then be passed t `snappy_compress` function as an output parameter. An output parameter is also passed to retrieve the true length after compression for setting the length. -```rust -# #![feature(libc)] +```rust,ignore # extern crate libc; # use libc::{size_t, c_int}; # unsafe fn snappy_compress(a: *const u8, b: size_t, c: *mut u8, @@ -150,8 +146,7 @@ pub fn compress(src: &[u8]) -> Vec { Decompression is similar, because snappy stores the uncompressed size as part of the compression format and `snappy_uncompressed_length` will retrieve the exact buffer size required. -```rust -# #![feature(libc)] +```rust,ignore # extern crate libc; # use libc::{size_t, c_int}; # unsafe fn snappy_uncompress(compressed: *const u8, @@ -185,8 +180,7 @@ pub fn uncompress(src: &[u8]) -> Option> { Then, we can add some tests to show how to use them. -```rust -# #![feature(libc)] +```rust,ignore # extern crate libc; # use libc::{c_int, size_t}; # unsafe fn snappy_compress(input: *const u8, @@ -246,7 +240,7 @@ Foreign libraries often hand off ownership of resources to the calling code. When this occurs, we must use Rust's destructors to provide safety and guarantee the release of these resources (especially in the case of panic). -For more about destructors, see the [Drop trait](../std/ops/trait.Drop.html). +For more about destructors, see the [Drop trait](../../std/ops/trait.Drop.html). # Callbacks from C code to Rust functions @@ -460,8 +454,7 @@ Foreign APIs often export a global variable which could do something like track global state. In order to access these variables, you declare them in `extern` blocks with the `static` keyword: -```rust,no_run -# #![feature(libc)] +```rust,ignore extern crate libc; #[link(name = "readline")] @@ -479,8 +472,7 @@ Alternatively, you may need to alter global state provided by a foreign interface. To do this, statics can be declared with `mut` so we can mutate them. -```rust,no_run -# #![feature(libc)] +```rust,ignore extern crate libc; use std::ffi::CString; @@ -512,8 +504,7 @@ Most foreign code exposes a C ABI, and Rust uses the platform's C calling conven calling foreign functions. Some foreign functions, most notably the Windows API, use other calling conventions. Rust provides a way to tell the compiler which convention to use: -```rust -# #![feature(libc)] +```rust,ignore extern crate libc; #[cfg(all(target_os = "win32", target_arch = "x86"))] @@ -624,8 +615,7 @@ callback, which gets called in certain situations. The callback is passed a func and an integer and it is supposed to run the function with the integer as a parameter. So we have function pointers flying across the FFI boundary in both directions. -```rust -# #![feature(libc)] +```rust,ignore extern crate libc; use libc::c_int; @@ -687,7 +677,7 @@ attribute turns off Rust's name mangling, so that it is easier to link to. It’s important to be mindful of `panic!`s when working with FFI. A `panic!` across an FFI boundary is undefined behavior. If you’re writing code that may -panic, you should run it in a closure with [`catch_unwind()`]: +panic, you should run it in a closure with [`catch_unwind`]: ```rust use std::panic::catch_unwind; @@ -706,11 +696,11 @@ pub extern fn oh_no() -> i32 { fn main() {} ``` -Please note that [`catch_unwind()`] will only catch unwinding panics, not -those who abort the process. See the documentation of [`catch_unwind()`] +Please note that [`catch_unwind`] will only catch unwinding panics, not +those who abort the process. See the documentation of [`catch_unwind`] for more information. -[`catch_unwind()`]: ../std/panic/fn.catch_unwind.html +[`catch_unwind`]: ../../std/panic/fn.catch_unwind.html # Representing opaque structs @@ -725,8 +715,7 @@ void bar(void *arg); We can represent this in Rust with the `c_void` type: -```rust -# #![feature(libc)] +```rust,ignore extern crate libc; extern "C" { diff --git a/src/doc/book/src/functions.md b/src/doc/book/first-edition/src/functions.md similarity index 100% rename from src/doc/book/src/functions.md rename to src/doc/book/first-edition/src/functions.md diff --git a/src/doc/book/src/generics.md b/src/doc/book/first-edition/src/generics.md similarity index 97% rename from src/doc/book/src/generics.md rename to src/doc/book/first-edition/src/generics.md index d02cd776d0..891380c2d0 100644 --- a/src/doc/book/src/generics.md +++ b/src/doc/book/first-edition/src/generics.md @@ -186,5 +186,5 @@ functions or methods. See [Iterators § Consumers](iterators.html#consumers) for an example. [traits]: traits.html -[Vec]: ../std/vec/struct.Vec.html -[turbofish]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect +[Vec]: ../../std/vec/struct.Vec.html +[turbofish]: ../../std/iter/trait.Iterator.html#method.collect diff --git a/src/doc/book/src/getting-started.md b/src/doc/book/first-edition/src/getting-started.md similarity index 100% rename from src/doc/book/src/getting-started.md rename to src/doc/book/first-edition/src/getting-started.md diff --git a/src/doc/book/src/glossary.md b/src/doc/book/first-edition/src/glossary.md similarity index 97% rename from src/doc/book/src/glossary.md rename to src/doc/book/first-edition/src/glossary.md index b17b89633f..389530355a 100644 --- a/src/doc/book/src/glossary.md +++ b/src/doc/book/first-edition/src/glossary.md @@ -56,7 +56,7 @@ They can be used to manage control flow in a modular fashion. A type without a statically known size or alignment. ([more info][link]) -[link]: ../nomicon/exotic-sizes.html#dynamically-sized-types-dsts +[link]: ../../nomicon/exotic-sizes.html#dynamically-sized-types-dsts ### Expression diff --git a/src/doc/book/src/guessing-game.md b/src/doc/book/first-edition/src/guessing-game.md similarity index 98% rename from src/doc/book/src/guessing-game.md rename to src/doc/book/first-edition/src/guessing-game.md index 4d81438b11..8464cf0ff2 100644 --- a/src/doc/book/src/guessing-game.md +++ b/src/doc/book/first-edition/src/guessing-game.md @@ -106,8 +106,8 @@ prelude, you’ll have to `use` it directly. There is also a second ‘prelude [`io` prelude][ioprelude], which serves a similar function: you import it, and it imports a number of useful, `io`-related things. -[prelude]: ../std/prelude/index.html -[ioprelude]: ../std/io/prelude/index.html +[prelude]: ../../std/prelude/index.html +[ioprelude]: ../../std/io/prelude/index.html ```rust,ignore fn main() { @@ -177,7 +177,7 @@ bound to: `String::new()`. `String` is a string type, provided by the standard library. A [`String`][string] is a growable, UTF-8 encoded bit of text. -[string]: ../std/string/struct.String.html +[string]: ../../std/string/struct.String.html The `::new()` syntax uses `::` because this is an ‘associated function’ of a particular type. That is to say, it’s associated with `String` itself, @@ -209,7 +209,7 @@ have written this line as `std::io::stdin()`. This particular function returns a handle to the standard input for your terminal. More specifically, a [std::io::Stdin][iostdin]. -[iostdin]: ../std/io/struct.Stdin.html +[iostdin]: ../../std/io/struct.Stdin.html The next part will use this handle to get input from the user: @@ -217,12 +217,12 @@ The next part will use this handle to get input from the user: .read_line(&mut guess) ``` -Here, we call the [`read_line()`][read_line] method on our handle. +Here, we call the [`read_line`] method on our handle. [Methods][method] are like associated functions, but are only available on a particular instance of a type, rather than the type itself. We’re also passing one argument to `read_line()`: `&mut guess`. -[read_line]: ../std/io/struct.Stdin.html#method.read_line +[`read_line`]: ../../std/io/struct.Stdin.html#method.read_line [method]: method-syntax.html Remember how we bound `guess` above? We said it was mutable. However, @@ -266,8 +266,8 @@ String` we pass it. But it also returns a value: in this case, an standard library: a generic [`Result`][result], and then specific versions for sub-libraries, like `io::Result`. -[ioresult]: ../std/io/type.Result.html -[result]: ../std/result/enum.Result.html +[ioresult]: ../../std/io/type.Result.html +[result]: ../../std/result/enum.Result.html The purpose of these `Result` types is to encode error handling information. Values of the `Result` type, like any type, have methods defined on them. In @@ -276,7 +276,7 @@ it’s called on, and if it isn’t a successful one, [`panic!`][panic]s with a message you passed it. A `panic!` like this will cause our program to crash, displaying the message. -[expect]: ../std/result/enum.Result.html#method.expect +[expect]: ../../std/result/enum.Result.html#method.expect [panic]: error-handling.html If we do not call `expect()`, our program will compile, but @@ -620,7 +620,7 @@ match guess.cmp(&secret_number) { } ``` -[ordering]: ../std/cmp/enum.Ordering.html +[ordering]: ../../std/cmp/enum.Ordering.html If it’s `Less`, we print `Too small!`, if it’s `Greater`, `Too big!`, and if `Equal`, `You win!`. `match` is really useful, and is used often in Rust. @@ -726,7 +726,7 @@ exact type of number we want. Hence, `let guess: u32`. The colon (`:`) after thirty-two bit integer. Rust has [a number of built-in number types][number], but we’ve chosen `u32`. It’s a good default choice for a small positive number. -[parse]: ../std/primitive.str.html#method.parse +[parse]: ../../std/primitive.str.html#method.parse [number]: primitive-types.html#numeric-types Just like `read_line()`, our call to `parse()` could cause an error. What if diff --git a/src/doc/book/src/if-let.md b/src/doc/book/first-edition/src/if-let.md similarity index 100% rename from src/doc/book/src/if-let.md rename to src/doc/book/first-edition/src/if-let.md diff --git a/src/doc/book/src/if.md b/src/doc/book/first-edition/src/if.md similarity index 100% rename from src/doc/book/src/if.md rename to src/doc/book/first-edition/src/if.md diff --git a/src/doc/book/src/iterators.md b/src/doc/book/first-edition/src/iterators.md similarity index 97% rename from src/doc/book/src/iterators.md rename to src/doc/book/first-edition/src/iterators.md index 8ee6c0828a..548816a8d4 100644 --- a/src/doc/book/src/iterators.md +++ b/src/doc/book/first-edition/src/iterators.md @@ -14,10 +14,9 @@ Now that you know more Rust, we can talk in detail about how this works. Ranges (the `0..10`) are 'iterators'. An iterator is something that we can call the `.next()` method on repeatedly, and it gives us a sequence of things. -(By the way, a range with two dots like `0..10` is inclusive on the left (so it +A range with two dots like `0..10` is inclusive on the left (so it starts at 0) and exclusive on the right (so it ends at 9). A mathematician -would write "[0, 10)". To get a range that goes all the way up to 10 you can -write `0...10`.) +would write "[0, 10)". Like this: @@ -341,4 +340,4 @@ can help you with. There are a number of really useful iterators, and you can write your own as well. Iterators provide a safe, efficient way to manipulate all kinds of lists. They're a little unusual at first, but if you play with them, you'll get hooked. For a full list of the different iterators and -consumers, check out the [iterator module documentation](../std/iter/index.html). +consumers, check out the [iterator module documentation](../../std/iter/index.html). diff --git a/src/doc/book/src/lifetimes.md b/src/doc/book/first-edition/src/lifetimes.md similarity index 100% rename from src/doc/book/src/lifetimes.md rename to src/doc/book/first-edition/src/lifetimes.md diff --git a/src/doc/book/src/loops.md b/src/doc/book/first-edition/src/loops.md similarity index 88% rename from src/doc/book/src/loops.md rename to src/doc/book/first-edition/src/loops.md index b7658d57a9..20e6eeef30 100644 --- a/src/doc/book/src/loops.md +++ b/src/doc/book/first-edition/src/loops.md @@ -81,14 +81,14 @@ for var in expression { ``` The expression is an item that can be converted into an [iterator] using -[`IntoIterator`]. The iterator gives back a series of elements. Each element is -one iteration of the loop. That value is then bound to the name `var`, which is +[`IntoIterator`]. The iterator gives back a series of elements, one element per +iteration of the loop. That value is then bound to the name `var`, which is valid for the loop body. Once the body is over, the next value is fetched from the iterator, and we loop another time. When there are no more values, the `for` loop is over. [iterator]: iterators.html -[`IntoIterator`]: ../std/iter/trait.IntoIterator.html +[`IntoIterator`]: ../../std/iter/trait.IntoIterator.html In our example, `0..10` is an expression that takes a start and an end position, and gives an iterator over those values. The upper bound is exclusive, though, @@ -194,11 +194,15 @@ for x in 0..10 { You may also encounter situations where you have nested loops and need to specify which one your `break` or `continue` statement is for. Like most -other languages, by default a `break` or `continue` will apply to innermost -loop. In a situation where you would like to `break` or `continue` for one +other languages, Rust's `break` or `continue` apply to the innermost loop. +In a situation where you would like to `break` or `continue` for one of the outer loops, you can use labels to specify which loop the `break` or - `continue` statement applies to. This will only print when both `x` and `y` are - odd: +`continue` statement applies to. + +In the example below, we `continue` to the next iteration of `outer` loop +when `x` is even, while we `continue` to the next iteration of `inner` +loop when y is even. So it will execute the `println!` when both `x` and +`y` are odd. ```rust 'outer: for x in 0..10 { diff --git a/src/doc/book/src/macros.md b/src/doc/book/first-edition/src/macros.md similarity index 99% rename from src/doc/book/src/macros.md rename to src/doc/book/first-edition/src/macros.md index fa8e8975a5..c2b9960948 100644 --- a/src/doc/book/src/macros.md +++ b/src/doc/book/first-edition/src/macros.md @@ -58,6 +58,7 @@ We can implement this shorthand, using a macro: [^actual] [^actual]: The actual definition of `vec!` in libcollections differs from the one presented here, for reasons of efficiency and reusability. + ```rust macro_rules! vec { @@ -101,7 +102,7 @@ trees, at compile time. The semicolon is optional on the last (here, only) case. The "pattern" on the left-hand side of `=>` is known as a ‘matcher’. These have [their own little grammar] within the language. -[their own little grammar]: ../reference/macros.html +[their own little grammar]: ../../reference/macros.html The matcher `$x:expr` will match any Rust expression, binding that syntax tree to the ‘metavariable’ `$x`. The identifier `expr` is a ‘fragment specifier’; @@ -363,7 +364,7 @@ fn main() { } ``` -[items]: ../reference/items.html +[items]: ../../reference/items.html # Recursive macros @@ -490,7 +491,7 @@ be forced to choose between parsing `$i` and parsing `$e`. Changing the invocation syntax to put a distinctive token in front can solve the problem. In this case, you can write `$(I $i:ident)* E $e:expr`. -[item]: ../reference/items.html +[item]: ../../reference/items.html # Scoping and macro import/export @@ -565,7 +566,7 @@ When this library is loaded with `#[macro_use] extern crate`, only `m2` will be imported. The Rust Reference has a [listing of macro-related -attributes](../reference/attributes.html#macro-related-attributes). +attributes](../../reference/attributes.html#macro-related-attributes). # The variable `$crate` diff --git a/src/doc/book/src/match.md b/src/doc/book/first-edition/src/match.md similarity index 100% rename from src/doc/book/src/match.md rename to src/doc/book/first-edition/src/match.md diff --git a/src/doc/book/src/method-syntax.md b/src/doc/book/first-edition/src/method-syntax.md similarity index 100% rename from src/doc/book/src/method-syntax.md rename to src/doc/book/first-edition/src/method-syntax.md diff --git a/src/doc/book/src/mutability.md b/src/doc/book/first-edition/src/mutability.md similarity index 97% rename from src/doc/book/src/mutability.md rename to src/doc/book/first-edition/src/mutability.md index fa7a259392..4d53a5aaed 100644 --- a/src/doc/book/src/mutability.md +++ b/src/doc/book/first-edition/src/mutability.md @@ -72,7 +72,7 @@ let x = Arc::new(5); let y = x.clone(); ``` -[arc]: ../std/sync/struct.Arc.html +[arc]: ../../std/sync/struct.Arc.html When we call `clone()`, the `Arc` needs to update the reference count. Yet we’ve not used any `mut`s here, `x` is an immutable binding, and we didn’t take @@ -107,7 +107,7 @@ let x = RefCell::new(42); let y = x.borrow_mut(); ``` -[stdcell]: ../std/cell/index.html +[stdcell]: ../../std/cell/index.html RefCell hands out `&mut` references to what’s inside of it with the `borrow_mut()` method. Isn’t that dangerous? What if we do: @@ -176,6 +176,6 @@ point.y.set(7); println!("y: {:?}", point.y); ``` -[cell]: ../std/cell/struct.Cell.html +[cell]: ../../std/cell/struct.Cell.html This will print `y: Cell { value: 7 }`. We’ve successfully updated `y`. diff --git a/src/doc/book/src/operators-and-overloading.md b/src/doc/book/first-edition/src/operators-and-overloading.md similarity index 97% rename from src/doc/book/src/operators-and-overloading.md rename to src/doc/book/first-edition/src/operators-and-overloading.md index a69cd6adb3..ed202f3d7d 100644 --- a/src/doc/book/src/operators-and-overloading.md +++ b/src/doc/book/first-edition/src/operators-and-overloading.md @@ -41,7 +41,7 @@ There are a number of operators that can be overloaded this way, and all of their associated traits live in the [`std::ops`][stdops] module. Check out its documentation for the full list. -[stdops]: ../std/ops/index.html +[stdops]: ../../std/ops/index.html Implementing these traits follows a pattern. Let’s look at [`Add`][add] in more detail: @@ -56,7 +56,7 @@ pub trait Add { # } ``` -[add]: ../std/ops/trait.Add.html +[add]: ../../std/ops/trait.Add.html There’s three types in total involved here: the type you `impl Add` for, `RHS`, which defaults to `Self`, and `Output`. For an expression `let z = x + y`, `x` diff --git a/src/doc/book/src/ownership.md b/src/doc/book/first-edition/src/ownership.md similarity index 100% rename from src/doc/book/src/ownership.md rename to src/doc/book/first-edition/src/ownership.md diff --git a/src/doc/book/src/patterns.md b/src/doc/book/first-edition/src/patterns.md similarity index 100% rename from src/doc/book/src/patterns.md rename to src/doc/book/first-edition/src/patterns.md diff --git a/src/doc/book/src/primitive-types.md b/src/doc/book/first-edition/src/primitive-types.md similarity index 92% rename from src/doc/book/src/primitive-types.md rename to src/doc/book/first-edition/src/primitive-types.md index 8fd3d17c15..93220a2ba8 100644 --- a/src/doc/book/src/primitive-types.md +++ b/src/doc/book/first-edition/src/primitive-types.md @@ -22,7 +22,7 @@ A common use of booleans is in [`if` conditionals][if]. You can find more documentation for `bool`s [in the standard library documentation][bool]. -[bool]: ../std/primitive.bool.html +[bool]: ../../std/primitive.bool.html # `char` @@ -40,7 +40,7 @@ but four. You can find more documentation for `char`s [in the standard library documentation][char]. -[char]: ../std/primitive.char.html +[char]: ../../std/primitive.char.html # Numeric types @@ -62,18 +62,18 @@ let y = 1.0; // `y` has type `f64`. Here’s a list of the different numeric types, with links to their documentation in the standard library: -* [i8](../std/primitive.i8.html) -* [i16](../std/primitive.i16.html) -* [i32](../std/primitive.i32.html) -* [i64](../std/primitive.i64.html) -* [u8](../std/primitive.u8.html) -* [u16](../std/primitive.u16.html) -* [u32](../std/primitive.u32.html) -* [u64](../std/primitive.u64.html) -* [isize](../std/primitive.isize.html) -* [usize](../std/primitive.usize.html) -* [f32](../std/primitive.f32.html) -* [f64](../std/primitive.f64.html) +* [i8](../../std/primitive.i8.html) +* [i16](../../std/primitive.i16.html) +* [i32](../../std/primitive.i32.html) +* [i64](../../std/primitive.i64.html) +* [u8](../../std/primitive.u8.html) +* [u16](../../std/primitive.u16.html) +* [u32](../../std/primitive.u32.html) +* [u64](../../std/primitive.u64.html) +* [isize](../../std/primitive.isize.html) +* [usize](../../std/primitive.usize.html) +* [f32](../../std/primitive.f32.html) +* [f64](../../std/primitive.f64.html) Let’s go over them by category: @@ -155,7 +155,7 @@ languages. You can find more documentation for `array`s [in the standard library documentation][array]. -[array]: ../std/primitive.array.html +[array]: ../../std/primitive.array.html # Slices @@ -189,7 +189,7 @@ Slices have type `&[T]`. We’ll talk about that `T` when we cover You can find more documentation for slices [in the standard library documentation][slice]. -[slice]: ../std/primitive.slice.html +[slice]: ../../std/primitive.slice.html # `str` @@ -205,7 +205,7 @@ reference, like `&str`. We'll elaborate further when we cover You can find more documentation for `str` [in the standard library documentation][str]. -[str]: ../std/primitive.str.html +[str]: ../../std/primitive.str.html # Tuples @@ -289,7 +289,7 @@ Like array indexing, it starts at zero, but unlike array indexing, it uses a You can find more documentation for tuples [in the standard library documentation][tuple]. -[tuple]: ../std/primitive.tuple.html +[tuple]: ../../std/primitive.tuple.html # Functions diff --git a/src/doc/book/src/procedural-macros.md b/src/doc/book/first-edition/src/procedural-macros.md similarity index 99% rename from src/doc/book/src/procedural-macros.md rename to src/doc/book/first-edition/src/procedural-macros.md index e02b5a6cdd..c2902790a4 100644 --- a/src/doc/book/src/procedural-macros.md +++ b/src/doc/book/first-edition/src/procedural-macros.md @@ -115,7 +115,7 @@ pub fn hello_world(input: TokenStream) -> TokenStream { let s = input.to_string(); // Parse the string representation - let ast = syn::parse_macro_input(&s).unwrap(); + let ast = syn::parse_derive_input(&s).unwrap(); // Build the impl let gen = impl_hello_world(&ast); diff --git a/src/doc/book/src/raw-pointers.md b/src/doc/book/first-edition/src/raw-pointers.md similarity index 98% rename from src/doc/book/src/raw-pointers.md rename to src/doc/book/first-edition/src/raw-pointers.md index 1f75665f4b..77024275b1 100644 --- a/src/doc/book/src/raw-pointers.md +++ b/src/doc/book/first-edition/src/raw-pointers.md @@ -72,7 +72,7 @@ println!("raw points at {}", points_at); For more operations on raw pointers, see [their API documentation][rawapi]. [unsafe]: unsafe.html -[rawapi]: ../std/primitive.pointer.html +[rawapi]: ../../std/primitive.pointer.html # FFI diff --git a/src/doc/book/src/references-and-borrowing.md b/src/doc/book/first-edition/src/references-and-borrowing.md similarity index 100% rename from src/doc/book/src/references-and-borrowing.md rename to src/doc/book/first-edition/src/references-and-borrowing.md diff --git a/src/doc/book/src/release-channels.md b/src/doc/book/first-edition/src/release-channels.md similarity index 100% rename from src/doc/book/src/release-channels.md rename to src/doc/book/first-edition/src/release-channels.md diff --git a/src/doc/book/src/strings.md b/src/doc/book/first-edition/src/strings.md similarity index 98% rename from src/doc/book/src/strings.md rename to src/doc/book/first-edition/src/strings.md index ffc9d2b697..537e5f94a8 100644 --- a/src/doc/book/src/strings.md +++ b/src/doc/book/first-edition/src/strings.md @@ -192,4 +192,4 @@ feature called ‘[`Deref` coercions][dc]’. [ut]: unsized-types.html [dc]: deref-coercions.html -[connect]: ../std/net/struct.TcpStream.html#method.connect +[connect]: ../../std/net/struct.TcpStream.html#method.connect diff --git a/src/doc/book/src/structs.md b/src/doc/book/first-edition/src/structs.md similarity index 100% rename from src/doc/book/src/structs.md rename to src/doc/book/first-edition/src/structs.md diff --git a/src/doc/book/src/syntax-and-semantics.md b/src/doc/book/first-edition/src/syntax-and-semantics.md similarity index 100% rename from src/doc/book/src/syntax-and-semantics.md rename to src/doc/book/first-edition/src/syntax-and-semantics.md diff --git a/src/doc/book/src/syntax-index.md b/src/doc/book/first-edition/src/syntax-index.md similarity index 97% rename from src/doc/book/src/syntax-index.md rename to src/doc/book/first-edition/src/syntax-index.md index a06520f4ac..c7b19a9cdb 100644 --- a/src/doc/book/src/syntax-index.md +++ b/src/doc/book/first-edition/src/syntax-index.md @@ -235,10 +235,10 @@ [Primitive Types (Tuple Indexing)]: primitive-types.html#tuple-indexing [Primitive Types (Tuples)]: primitive-types.html#tuples [Raw Pointers]: raw-pointers.html -[Reference (Byte String Literals)]: ../reference/tokens.html/#byte-string-literals -[Reference (Integer literals)]: ../reference/tokens.html#integer-literals -[Reference (Raw Byte String Literals)]: ../reference/tokens.html#raw-byte-string-literals -[Reference (Raw String Literals)]: ../reference/tokens.html#raw-string-literals +[Reference (Byte String Literals)]: ../../reference/tokens.html/#byte-string-literals +[Reference (Integer literals)]: ../../reference/tokens.html#integer-literals +[Reference (Raw Byte String Literals)]: ../../reference/tokens.html#raw-byte-string-literals +[Reference (Raw String Literals)]: ../../reference/tokens.html#raw-string-literals [References and Borrowing]: references-and-borrowing.html [Strings]: strings.html [Structs (Update syntax)]: structs.html#update-syntax diff --git a/src/doc/book/src/testing.md b/src/doc/book/first-edition/src/testing.md similarity index 99% rename from src/doc/book/src/testing.md rename to src/doc/book/first-edition/src/testing.md index 291c4481d5..b4f580fcdf 100644 --- a/src/doc/book/src/testing.md +++ b/src/doc/book/first-edition/src/testing.md @@ -147,7 +147,7 @@ And that's reflected in the summary line: test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured ``` -We also get a non-zero status code. We can use `$?` on OS X and Linux: +We also get a non-zero status code. We can use `$?` on macOS and Linux: ```bash $ echo $? diff --git a/src/doc/book/src/the-stack-and-the-heap.md b/src/doc/book/first-edition/src/the-stack-and-the-heap.md similarity index 99% rename from src/doc/book/src/the-stack-and-the-heap.md rename to src/doc/book/first-edition/src/the-stack-and-the-heap.md index 6866505df1..2e7441aaf5 100644 --- a/src/doc/book/src/the-stack-and-the-heap.md +++ b/src/doc/book/first-edition/src/the-stack-and-the-heap.md @@ -215,7 +215,7 @@ fn main() { } ``` -[box]: ../std/boxed/index.html +[box]: ../../std/boxed/index.html Here’s what happens in memory when `main()` is called: diff --git a/src/doc/book/src/trait-objects.md b/src/doc/book/first-edition/src/trait-objects.md similarity index 99% rename from src/doc/book/src/trait-objects.md rename to src/doc/book/first-edition/src/trait-objects.md index a77d5fe93b..4a4b2cb8e6 100644 --- a/src/doc/book/src/trait-objects.md +++ b/src/doc/book/first-edition/src/trait-objects.md @@ -195,7 +195,7 @@ pub struct TraitObject { # } ``` -[stdraw]: ../std/raw/struct.TraitObject.html +[stdraw]: ../../std/raw/struct.TraitObject.html That is, a trait object like `&Foo` consists of a ‘data’ pointer and a ‘vtable’ pointer. diff --git a/src/doc/book/src/traits.md b/src/doc/book/first-edition/src/traits.md similarity index 95% rename from src/doc/book/src/traits.md rename to src/doc/book/first-edition/src/traits.md index 19a133f84b..91a4bbbf56 100644 --- a/src/doc/book/src/traits.md +++ b/src/doc/book/first-edition/src/traits.md @@ -230,7 +230,7 @@ impl Rectangle { ... } Now, a rectangle can be defined in terms of any type that can be compared for equality. -[PartialEq]: ../core/cmp/trait.PartialEq.html +[PartialEq]: ../../core/cmp/trait.PartialEq.html Here we defined a new struct `Rectangle` that accepts numbers of any precision—really, objects of pretty much any type—as long as they can be @@ -266,7 +266,7 @@ example: the standard library provides a [`Write`][write] trait which adds extra functionality to `File`s, for doing file I/O. By default, a `File` won’t have its methods: -[write]: ../std/io/trait.Write.html +[write]: ../../std/io/trait.Write.html ```rust,ignore let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt"); @@ -414,12 +414,12 @@ impl ConvertTo for i32 { } // Can be called with T == i32. -fn normal>(x: &T) -> i64 { +fn convert_t_to_i64>(x: T) -> i64 { x.convert() } // Can be called with T == i64. -fn inverse(x: i32) -> T +fn convert_i32_to_t(x: i32) -> T // This is using ConvertTo as if it were "ConvertTo". where i32: ConvertTo { x.convert() @@ -540,12 +540,12 @@ fn main() { However, deriving is limited to a certain set of traits: -- [`Clone`](../core/clone/trait.Clone.html) -- [`Copy`](../core/marker/trait.Copy.html) -- [`Debug`](../core/fmt/trait.Debug.html) -- [`Default`](../core/default/trait.Default.html) -- [`Eq`](../core/cmp/trait.Eq.html) -- [`Hash`](../core/hash/trait.Hash.html) -- [`Ord`](../core/cmp/trait.Ord.html) -- [`PartialEq`](../core/cmp/trait.PartialEq.html) -- [`PartialOrd`](../core/cmp/trait.PartialOrd.html) +- [`Clone`](../../core/clone/trait.Clone.html) +- [`Copy`](../../core/marker/trait.Copy.html) +- [`Debug`](../../core/fmt/trait.Debug.html) +- [`Default`](../../core/default/trait.Default.html) +- [`Eq`](../../core/cmp/trait.Eq.html) +- [`Hash`](../../core/hash/trait.Hash.html) +- [`Ord`](../../core/cmp/trait.Ord.html) +- [`PartialEq`](../../core/cmp/trait.PartialEq.html) +- [`PartialOrd`](../../core/cmp/trait.PartialOrd.html) diff --git a/src/doc/book/src/type-aliases.md b/src/doc/book/first-edition/src/type-aliases.md similarity index 97% rename from src/doc/book/src/type-aliases.md rename to src/doc/book/first-edition/src/type-aliases.md index 1bd0f78e36..f70e7a3176 100644 --- a/src/doc/book/src/type-aliases.md +++ b/src/doc/book/first-edition/src/type-aliases.md @@ -75,4 +75,4 @@ This creates a specialized version of the `Result` type, which always has a in the standard library to create custom errors for each subsection. For example, [io::Result][ioresult]. -[ioresult]: ../std/io/type.Result.html +[ioresult]: ../../std/io/type.Result.html diff --git a/src/doc/book/src/ufcs.md b/src/doc/book/first-edition/src/ufcs.md similarity index 100% rename from src/doc/book/src/ufcs.md rename to src/doc/book/first-edition/src/ufcs.md diff --git a/src/doc/book/src/unsafe.md b/src/doc/book/first-edition/src/unsafe.md similarity index 98% rename from src/doc/book/src/unsafe.md rename to src/doc/book/first-edition/src/unsafe.md index 9bf59fe2ab..0331c9530b 100644 --- a/src/doc/book/src/unsafe.md +++ b/src/doc/book/first-edition/src/unsafe.md @@ -139,4 +139,4 @@ I’ll repeat again: even though you _can_ do arbitrary things in unsafe blocks and functions doesn’t mean you should. The compiler will act as though you’re upholding its invariants, so be careful! -[intrinsics]: ../unstable-book/intrinsics.html +[intrinsics]: ../../unstable-book/language-features/intrinsics.html diff --git a/src/doc/book/src/unsized-types.md b/src/doc/book/first-edition/src/unsized-types.md similarity index 100% rename from src/doc/book/src/unsized-types.md rename to src/doc/book/first-edition/src/unsized-types.md diff --git a/src/doc/book/src/using-rust-without-the-standard-library.md b/src/doc/book/first-edition/src/using-rust-without-the-standard-library.md similarity index 80% rename from src/doc/book/src/using-rust-without-the-standard-library.md rename to src/doc/book/first-edition/src/using-rust-without-the-standard-library.md index 709d10f4e4..c1dcfea149 100644 --- a/src/doc/book/src/using-rust-without-the-standard-library.md +++ b/src/doc/book/first-edition/src/using-rust-without-the-standard-library.md @@ -9,7 +9,7 @@ don’t want to use the standard library via an attribute: `#![no_std]`. > Note: This feature is technically stable, but there are some caveats. For > one, you can build a `#![no_std]` _library_ on stable, but not a _binary_. > For details on binaries without the standard library, see [the nightly -> chapter on 'lang items'](../unstable-book/lang-items.html#using-libc) +> chapter on 'lang items'][unstable book lang items] To use `#![no_std]`, add it to your crate root: @@ -22,11 +22,11 @@ fn plus_one(x: i32) -> i32 { ``` Much of the functionality that’s exposed in the standard library is also -available via the [`core` crate](../core/index.html). When we’re using the +available via the [`core` crate](../../core/index.html). When we’re using the standard library, Rust automatically brings `std` into scope, allowing you to use its features without an explicit import. By the same token, when using `#![no_std]`, Rust will bring `core` into scope for you, as well as [its -prelude](../core/prelude/v1/index.html). This means that a lot of code will Just +prelude](../../core/prelude/v1/index.html). This means that a lot of code will Just Work: ```rust,ignore @@ -40,3 +40,5 @@ fn may_fail(failure: bool) -> Result<(), &'static str> { } } ``` + +[unstable book lang items]: ../../unstable-book/language-features/lang-items.html#using-libc diff --git a/src/doc/book/src/variable-bindings.md b/src/doc/book/first-edition/src/variable-bindings.md similarity index 99% rename from src/doc/book/src/variable-bindings.md rename to src/doc/book/first-edition/src/variable-bindings.md index d6aa8b1acb..65e172e9b2 100644 --- a/src/doc/book/src/variable-bindings.md +++ b/src/doc/book/first-edition/src/variable-bindings.md @@ -176,7 +176,7 @@ more detailed manner, there are a [wide number of options available][format]. For now, we'll stick to the default: integers aren't very complicated to print. -[format]: ../std/fmt/index.html +[format]: ../../std/fmt/index.html # Scope and shadowing diff --git a/src/doc/book/src/vectors.md b/src/doc/book/first-edition/src/vectors.md similarity index 95% rename from src/doc/book/src/vectors.md rename to src/doc/book/first-edition/src/vectors.md index aff078718d..138a15273c 100644 --- a/src/doc/book/src/vectors.md +++ b/src/doc/book/first-edition/src/vectors.md @@ -148,9 +148,9 @@ for i in &v { Vectors have many more useful methods, which you can read about in [their API documentation][vec]. -[vec]: ../std/vec/index.html -[box]: ../std/boxed/index.html +[vec]: ../../std/vec/index.html +[box]: ../../std/boxed/index.html [generic]: generics.html [panic]: concurrency.html#panics -[get]: ../std/vec/struct.Vec.html#method.get -[get_mut]: ../std/vec/struct.Vec.html#method.get_mut +[get]: ../../std/vec/struct.Vec.html#method.get +[get_mut]: ../../std/vec/struct.Vec.html#method.get_mut diff --git a/src/doc/book/index.md b/src/doc/book/index.md new file mode 100644 index 0000000000..6540e789f7 --- /dev/null +++ b/src/doc/book/index.md @@ -0,0 +1,11 @@ +% The Rust Programming Language + +There are two editions of "The Rust Programming Language": + +* [First edition](first-edition/index.html) +* [Second edition](second-edition/index.html) + +The second edition is a complete re-write. It is still under construction; +though it is far enough along to learn most of Rust; we suggest reading the +second edition and then checking out the first edition later to pick up some of +the more esoteric parts of the language. diff --git a/src/doc/book/redirects/README.md b/src/doc/book/redirects/README.md new file mode 100644 index 0000000000..477c426046 --- /dev/null +++ b/src/doc/book/redirects/README.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/index.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/SUMMARY.md b/src/doc/book/redirects/SUMMARY.md new file mode 100644 index 0000000000..477c426046 --- /dev/null +++ b/src/doc/book/redirects/SUMMARY.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/index.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/associated-types.md b/src/doc/book/redirects/associated-types.md new file mode 100644 index 0000000000..0aac089fa8 --- /dev/null +++ b/src/doc/book/redirects/associated-types.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/associated-types.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/attributes.md b/src/doc/book/redirects/attributes.md new file mode 100644 index 0000000000..f9f2ae588f --- /dev/null +++ b/src/doc/book/redirects/attributes.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/attributes.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/bibliography.md b/src/doc/book/redirects/bibliography.md new file mode 100644 index 0000000000..152dd38939 --- /dev/null +++ b/src/doc/book/redirects/bibliography.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/bibliography.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/borrow-and-asref.md b/src/doc/book/redirects/borrow-and-asref.md new file mode 100644 index 0000000000..804e46be7a --- /dev/null +++ b/src/doc/book/redirects/borrow-and-asref.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/borrow-and-asref.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/casting-between-types.md b/src/doc/book/redirects/casting-between-types.md new file mode 100644 index 0000000000..45e3b4747b --- /dev/null +++ b/src/doc/book/redirects/casting-between-types.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/casting-between-types.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/choosing-your-guarantees.md b/src/doc/book/redirects/choosing-your-guarantees.md new file mode 100644 index 0000000000..e457baf883 --- /dev/null +++ b/src/doc/book/redirects/choosing-your-guarantees.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/choosing-your-guarantees.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/closures.md b/src/doc/book/redirects/closures.md new file mode 100644 index 0000000000..b176a1a69c --- /dev/null +++ b/src/doc/book/redirects/closures.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/closures.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/comments.md b/src/doc/book/redirects/comments.md new file mode 100644 index 0000000000..f44eedb55b --- /dev/null +++ b/src/doc/book/redirects/comments.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/comments.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/compiler-plugins.md b/src/doc/book/redirects/compiler-plugins.md new file mode 100644 index 0000000000..f92738f4ee --- /dev/null +++ b/src/doc/book/redirects/compiler-plugins.md @@ -0,0 +1,6 @@ +% The Rust Programming Language Has Moved + +This chapter of the book has moved to [a chapter in the Unstable +Book][unstable book plugins]. Please check it out there. + +[unstable book plugins]: ../unstable-book/language-features/plugin.html diff --git a/src/doc/book/redirects/concurrency.md b/src/doc/book/redirects/concurrency.md new file mode 100644 index 0000000000..b17fa6fd89 --- /dev/null +++ b/src/doc/book/redirects/concurrency.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/concurrency.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/conditional-compilation.md b/src/doc/book/redirects/conditional-compilation.md new file mode 100644 index 0000000000..954eba4d17 --- /dev/null +++ b/src/doc/book/redirects/conditional-compilation.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/conditional-compilation.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/const-and-static.md b/src/doc/book/redirects/const-and-static.md new file mode 100644 index 0000000000..edf3c43513 --- /dev/null +++ b/src/doc/book/redirects/const-and-static.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/const-and-static.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/crates-and-modules.md b/src/doc/book/redirects/crates-and-modules.md new file mode 100644 index 0000000000..c612821d12 --- /dev/null +++ b/src/doc/book/redirects/crates-and-modules.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/crates-and-modules.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/deref-coercions.md b/src/doc/book/redirects/deref-coercions.md new file mode 100644 index 0000000000..e53bfe5f56 --- /dev/null +++ b/src/doc/book/redirects/deref-coercions.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/deref-coercions.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/documentation.md b/src/doc/book/redirects/documentation.md new file mode 100644 index 0000000000..60e91f9cca --- /dev/null +++ b/src/doc/book/redirects/documentation.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/documentation.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/drop.md b/src/doc/book/redirects/drop.md new file mode 100644 index 0000000000..0de72b2d54 --- /dev/null +++ b/src/doc/book/redirects/drop.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/drop.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/effective-rust.md b/src/doc/book/redirects/effective-rust.md new file mode 100644 index 0000000000..b077ccd5f1 --- /dev/null +++ b/src/doc/book/redirects/effective-rust.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/effective-rust.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/enums.md b/src/doc/book/redirects/enums.md new file mode 100644 index 0000000000..22f611604e --- /dev/null +++ b/src/doc/book/redirects/enums.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/enums.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/error-handling.md b/src/doc/book/redirects/error-handling.md new file mode 100644 index 0000000000..024ab2f15e --- /dev/null +++ b/src/doc/book/redirects/error-handling.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/error-handling.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/ffi.md b/src/doc/book/redirects/ffi.md new file mode 100644 index 0000000000..3b67524839 --- /dev/null +++ b/src/doc/book/redirects/ffi.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/ffi.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/functions.md b/src/doc/book/redirects/functions.md new file mode 100644 index 0000000000..17c64f13aa --- /dev/null +++ b/src/doc/book/redirects/functions.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/functions.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/generics.md b/src/doc/book/redirects/generics.md new file mode 100644 index 0000000000..6a8c03c894 --- /dev/null +++ b/src/doc/book/redirects/generics.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/generics.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/getting-started.md b/src/doc/book/redirects/getting-started.md new file mode 100644 index 0000000000..cacb74b795 --- /dev/null +++ b/src/doc/book/redirects/getting-started.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/getting-started.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/glossary.md b/src/doc/book/redirects/glossary.md new file mode 100644 index 0000000000..a1e000d6cc --- /dev/null +++ b/src/doc/book/redirects/glossary.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/glossary.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/guessing-game.md b/src/doc/book/redirects/guessing-game.md new file mode 100644 index 0000000000..ef056b41d6 --- /dev/null +++ b/src/doc/book/redirects/guessing-game.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/guessing-game.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/if-let.md b/src/doc/book/redirects/if-let.md new file mode 100644 index 0000000000..3fb6338f75 --- /dev/null +++ b/src/doc/book/redirects/if-let.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/if-let.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/if.md b/src/doc/book/redirects/if.md new file mode 100644 index 0000000000..5d1336cb63 --- /dev/null +++ b/src/doc/book/redirects/if.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/if.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/iterators.md b/src/doc/book/redirects/iterators.md new file mode 100644 index 0000000000..2ade93ecf0 --- /dev/null +++ b/src/doc/book/redirects/iterators.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/iterators.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/lifetimes.md b/src/doc/book/redirects/lifetimes.md new file mode 100644 index 0000000000..e581f57faa --- /dev/null +++ b/src/doc/book/redirects/lifetimes.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/lifetimes.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/loops.md b/src/doc/book/redirects/loops.md new file mode 100644 index 0000000000..6408bd6056 --- /dev/null +++ b/src/doc/book/redirects/loops.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/loops.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/macros.md b/src/doc/book/redirects/macros.md new file mode 100644 index 0000000000..811fb2d629 --- /dev/null +++ b/src/doc/book/redirects/macros.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/macros.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/match.md b/src/doc/book/redirects/match.md new file mode 100644 index 0000000000..3193a804cb --- /dev/null +++ b/src/doc/book/redirects/match.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/match.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/method-syntax.md b/src/doc/book/redirects/method-syntax.md new file mode 100644 index 0000000000..3ff65ad515 --- /dev/null +++ b/src/doc/book/redirects/method-syntax.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/method-syntax.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/mutability.md b/src/doc/book/redirects/mutability.md new file mode 100644 index 0000000000..0fe93e855c --- /dev/null +++ b/src/doc/book/redirects/mutability.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/mutability.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/operators-and-overloading.md b/src/doc/book/redirects/operators-and-overloading.md new file mode 100644 index 0000000000..1938bf1073 --- /dev/null +++ b/src/doc/book/redirects/operators-and-overloading.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/operators-and-overloading.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/ownership.md b/src/doc/book/redirects/ownership.md new file mode 100644 index 0000000000..0246d01363 --- /dev/null +++ b/src/doc/book/redirects/ownership.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/ownership.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/patterns.md b/src/doc/book/redirects/patterns.md new file mode 100644 index 0000000000..d08bff2c5e --- /dev/null +++ b/src/doc/book/redirects/patterns.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/patterns.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/primitive-types.md b/src/doc/book/redirects/primitive-types.md new file mode 100644 index 0000000000..f6e20d0b17 --- /dev/null +++ b/src/doc/book/redirects/primitive-types.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/primitive-types.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/procedural-macros.md b/src/doc/book/redirects/procedural-macros.md new file mode 100644 index 0000000000..521fe36798 --- /dev/null +++ b/src/doc/book/redirects/procedural-macros.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/procedural-macros.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/raw-pointers.md b/src/doc/book/redirects/raw-pointers.md new file mode 100644 index 0000000000..c084c7500d --- /dev/null +++ b/src/doc/book/redirects/raw-pointers.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/raw-pointers.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/references-and-borrowing.md b/src/doc/book/redirects/references-and-borrowing.md new file mode 100644 index 0000000000..346d3e9967 --- /dev/null +++ b/src/doc/book/redirects/references-and-borrowing.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/references-and-borrowing.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/release-channels.md b/src/doc/book/redirects/release-channels.md new file mode 100644 index 0000000000..63c5c45967 --- /dev/null +++ b/src/doc/book/redirects/release-channels.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/release-channels.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/strings.md b/src/doc/book/redirects/strings.md new file mode 100644 index 0000000000..29152d5ff7 --- /dev/null +++ b/src/doc/book/redirects/strings.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/strings.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/structs.md b/src/doc/book/redirects/structs.md new file mode 100644 index 0000000000..a9f409de8b --- /dev/null +++ b/src/doc/book/redirects/structs.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/structs.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/syntax-and-semantics.md b/src/doc/book/redirects/syntax-and-semantics.md new file mode 100644 index 0000000000..cf69533f5a --- /dev/null +++ b/src/doc/book/redirects/syntax-and-semantics.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/syntax-and-semantics.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/syntax-index.md b/src/doc/book/redirects/syntax-index.md new file mode 100644 index 0000000000..4243e8ef3b --- /dev/null +++ b/src/doc/book/redirects/syntax-index.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/syntax-index.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/testing.md b/src/doc/book/redirects/testing.md new file mode 100644 index 0000000000..764beaa4ac --- /dev/null +++ b/src/doc/book/redirects/testing.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/testing.html +[second edition]: second-edition/index.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 new file mode 100644 index 0000000000..e42a6eb90e --- /dev/null +++ b/src/doc/book/redirects/the-stack-and-the-heap.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/the-stack-and-the-heap.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/trait-objects.md b/src/doc/book/redirects/trait-objects.md new file mode 100644 index 0000000000..412c6159e0 --- /dev/null +++ b/src/doc/book/redirects/trait-objects.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/trait-objects.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/traits.md b/src/doc/book/redirects/traits.md new file mode 100644 index 0000000000..e1dc70fd6c --- /dev/null +++ b/src/doc/book/redirects/traits.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/traits.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/type-aliases.md b/src/doc/book/redirects/type-aliases.md new file mode 100644 index 0000000000..ac9dbeeb70 --- /dev/null +++ b/src/doc/book/redirects/type-aliases.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/type-aliases.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/ufcs.md b/src/doc/book/redirects/ufcs.md new file mode 100644 index 0000000000..1e123ce5ee --- /dev/null +++ b/src/doc/book/redirects/ufcs.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/ufcs.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/unsafe.md b/src/doc/book/redirects/unsafe.md new file mode 100644 index 0000000000..ba72e17a0f --- /dev/null +++ b/src/doc/book/redirects/unsafe.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/unsafe.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/unsized-types.md b/src/doc/book/redirects/unsized-types.md new file mode 100644 index 0000000000..c0b165ef27 --- /dev/null +++ b/src/doc/book/redirects/unsized-types.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/unsized-types.html +[second edition]: second-edition/index.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 new file mode 100644 index 0000000000..5e7e4587ef --- /dev/null +++ b/src/doc/book/redirects/using-rust-without-the-standard-library.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/using-rust-without-the-standard-library.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/variable-bindings.md b/src/doc/book/redirects/variable-bindings.md new file mode 100644 index 0000000000..b7adf7c904 --- /dev/null +++ b/src/doc/book/redirects/variable-bindings.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/variable-bindings.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/redirects/vectors.md b/src/doc/book/redirects/vectors.md new file mode 100644 index 0000000000..23b894f173 --- /dev/null +++ b/src/doc/book/redirects/vectors.md @@ -0,0 +1,13 @@ +% The Rust Programming Language Has Moved + +When The Rust Programming Language only had one edition, it was all hosted at +`book/`. Now that it has two, they are properly namespaced under +`first-edition/` and `second-edition/`. + +You've found this page because you have a link to the older URL structure; you +probably want to visit [first-edition/] if you need the exact older page; if +you're trying to learn Rust, checking out the [second edition] might be a +better choice. + +[first-edition/]: first-edition/vectors.html +[second edition]: second-edition/index.html diff --git a/src/doc/book/second-edition/Cargo.lock b/src/doc/book/second-edition/Cargo.lock new file mode 100644 index 0000000000..5cd51aa43f --- /dev/null +++ b/src/doc/book/second-edition/Cargo.lock @@ -0,0 +1,142 @@ +[root] +name = "rust-book" +version = "0.0.1" +dependencies = [ + "docopt 0.6.82 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "aho-corasick" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "docopt" +version = "0.6.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "0.1.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc-serialize" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "strsim" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "thread-id" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "utf8-ranges" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "walkdir" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9" +"checksum docopt 0.6.82 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20016093b4e545dccf6ad4a01099de0b695f9bc99b08210e68f6425db2d37d" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f" +"checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2" +"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" +"checksum regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)" = "56b7ee9f764ecf412c6e2fff779bca4b22980517ae335a21aeaf4e32625a5df2" +"checksum regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "31040aad7470ad9d8c46302dcffba337bb4289ca5da2e3cd6e37b64109a85199" +"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b" +"checksum strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4d73a2c36a4d095ed1a6df5cbeac159863173447f7a82b3f4757426844ab825" +"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" +"checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d" +"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" +"checksum walkdir 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7ad450634b9022aeb0e8e7f1c79c1ded92d0fc5bee831033d148479771bd218d" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/src/doc/book/second-edition/Cargo.toml b/src/doc/book/second-edition/Cargo.toml new file mode 100644 index 0000000000..7ab2575fa5 --- /dev/null +++ b/src/doc/book/second-edition/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "rust-book" +version = "0.0.1" +authors = ["Steve Klabnik "] +description = "The Rust Book" + +[[bin]] +name = "concat_chapters" +path = "tools/src/bin/concat_chapters.rs" + +[[bin]] +name = "lfp" +path = "tools/src/bin/lfp.rs" + +[[bin]] +name = "link2print" +path = "tools/src/bin/link2print.rs" + +[[bin]] +name = "remove_links" +path = "tools/src/bin/remove_links.rs" + +[[bin]] +name = "remove_markup" +path = "tools/src/bin/remove_markup.rs" + +[dependencies] +walkdir = "0.1.5" +docopt = "0.6.82" +rustc-serialize = "0.3.19" +regex = "0.1.73" +lazy_static = "0.2.1" diff --git a/src/doc/book/second-edition/LICENSE-APACHE b/src/doc/book/second-edition/LICENSE-APACHE new file mode 100644 index 0000000000..96e9f0458b --- /dev/null +++ b/src/doc/book/second-edition/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2010-2017 The Rust Project Developers + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/doc/book/second-edition/LICENSE-MIT b/src/doc/book/second-edition/LICENSE-MIT new file mode 100644 index 0000000000..5a56e6e8ed --- /dev/null +++ b/src/doc/book/second-edition/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2010-2017 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/doc/book/second-edition/book.toml b/src/doc/book/second-edition/book.toml new file mode 100644 index 0000000000..fef7c06146 --- /dev/null +++ b/src/doc/book/second-edition/book.toml @@ -0,0 +1,2 @@ +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 new file mode 100644 index 0000000000..e61896ac35 --- /dev/null +++ b/src/doc/book/second-edition/dictionary.txt @@ -0,0 +1,358 @@ +personal_ws-1.1 en 0 utf-8 +abcabcabc +abcd +abcdefghijklmnopqrstuvwxyz +adaptor +adaptors +Addr +aggregator +AGraph +aliasability +alignof +Amir +APIs +aren +args +AveragedCollection +backtrace +backtraces +BACKTRACE +Backtraces +Baz’s +benchmarking +bitand +BitAnd +bitor +BitOr +bitwise +Bitwise +bitxor +BitXor +Bjarne +Boehm +bool +boolean +booleans +Bors +BorrowMutError +BuildHasher +Cagain +callsite +CamelCase +cargodoc +ChangeColor +ChangeColorMessage +chXX +chYY +ConcreteType +config +Config +const +constant's +copyeditor +couldn +cratesio +cryptographically +CStr +CString +ctrl +Ctrl +CustomSmartPointer +deallocated +deallocating +deallocation +debuginfo +deps +deref +Deref +dereference +Dereference +dereferenced +dereferences +dereferencing +DerefMut +destructor +destructure +destructured +destructures +destructuring +Destructuring +didn +Dobrý +doccargo +doccratesio +doesn +DraftPost +DSTs +ebooks +Edsger +else's +emoji +encodings +enum +Enum +enums +enum's +Enums +ErrorKind +Executables +extern +FFFF +figcaption +filename +fieldname +Filename +filesystem +Filesystem +FnMut +FnOnce +formatter +FromIterator +GGraph +GitHub +gitignore +grapheme +Grapheme +greprs +growable +hardcoded +hardcoding +hasher +hashers +HashMap +HashSet +Haskell +hasn +helloworld +Hmmm +Hoare +Hola +homogenous +html +Iceburgh +IEEE +impl +ImportantExcerpt +indices +init +inline +instantiation +internet +IntoIterator +InvalidDigit +ioerror +iokind +ioresult +iostdin +IpAddr +IpAddrKind +irst +isize +iter +iterator's +JavaScript +JoinHandle +kinded +lang +latin +libc +libcollections +libcore +libpanic +librarys +libreoffice +libstd +lifecycle +login +lookup +loopback +lval +mathematic +metadata +Metadata +metaprogramming +mibbit +Mibbit +mixup +mkdir +modifiability +monomorphization +Monomorphization +monomorphized +MoveMessage +mpsc +multithreaded +mutex +Mutex +mutexes +Mutexes +MutexGuard +namespace +namespaced +namespaces +namespacing +newfound +NewsArticle +newtype +newtypes +nitty +nocapture +nomicon +Nomicon +NotFound +null's +OCaml +offsetof +online +OpenGL +OptionalFloatingPointNumber +OptionalNumber +OsStr +OsString +other's +OutlinePrint +overread +parameterize +ParseIntError +PartialEq +PartialOrd +PendingReview +PendingReviewPost +PlaceholderType +portia +powi +preprocessing +Preprocessing +preprocessor +PrimaryColor +println +priv +proc +pthreads +QuitMessage +RAII +randcrate +READMEs +rect +recurse +recv +redeclaring +Refactoring +refactor +refactoring +refcell +RefCell +RefMut +refutability +repr +retweet +ripgrep +runtime +runtimes +Rustacean +Rustaceans +rUsT +rustc +rustdoc +rustup +searchstring +SecondaryColor +SelectBox +semver +SemVer +shouldn +Simula +sizeof +someproject +someusername +SPDX +spdx +SpreadsheetCell +sqrt +stackoverflow +StaticRef +stderr +stdin +Stdin +stdlib +stdout +steveklabnik's +Stroustrup +struct +Struct +structs +struct's +Structs +subcommand +subcommands +subdirectories +subdirectory +submodule +submodules +Submodules +suboptimal +substring +subtree +subtyping +Summarizable +supertrait +supertraits +test's +TextField +That'd +there'd +threadsafe +timestamp +Tiếng +timeline +TODO +toml +TOML +ToString +tradeoff +tradeoffs +TrafficLight +trpl +tuesday +tuple +tuples +typeof +UFCS +unary +Unary +uncomment +Uncomment +Uninstalling +uninstall +unix +unoptimized +UnsafeCell +unsafety +unsized +unsynchronized +username +USERPROFILE +usize +UsState +utils +vals +variable's +variant's +vers +versa +Versioning +vtable +wasn +WeatherForecast +WebSocket +whitespace +wildcard +wildcards +workflow +workspace +workspaces +Workspaces +wouldn +writeln +WriteMessage +yyyy diff --git a/src/doc/book/second-edition/doc-to-md.sh b/src/doc/book/second-edition/doc-to-md.sh new file mode 100755 index 0000000000..259d6f02f0 --- /dev/null +++ b/src/doc/book/second-edition/doc-to-md.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -eu + +# Get all the docx files in the tmp dir, +ls tmp/*.docx | \ +# Extract just the filename so we can reuse it easily. +xargs -n 1 basename -s .docx | \ +while IFS= read -r filename; do + # Make a directory to put the XML in + mkdir -p "tmp/$filename" + # Unzip the docx to get at the xml + unzip -o "tmp/$filename.docx" -d "tmp/$filename" + # Convert to markdown with XSL + xsltproc tools/docx-to-md.xsl "tmp/$filename/word/document.xml" | \ + # Hard wrap at 80 chars at word bourdaries + fold -w 80 -s | \ + # Remove trailing whitespace & save in the nostarch dir for comparison + sed -e "s/ *$//" > "nostarch/$filename.md" +done diff --git a/src/doc/book/second-edition/dot/trpl04-01.dot b/src/doc/book/second-edition/dot/trpl04-01.dot new file mode 100644 index 0000000000..24f6964208 --- /dev/null +++ b/src/doc/book/second-edition/dot/trpl04-01.dot @@ -0,0 +1,25 @@ +digraph { + rankdir=LR; + dpi=300.0; + node [shape="plaintext"]; + + table0[label=< + + + + + +
s1
namevalue
ptr
len5
capacity5
>]; + table1[label=< + + + + + + +
indexvalue
0h
1e
2l
3l
4o
>]; + + edge[tailclip="false"]; + table0:pointer:c -> table1:pointee; +} + diff --git a/src/doc/book/second-edition/dot/trpl04-02.dot b/src/doc/book/second-edition/dot/trpl04-02.dot new file mode 100644 index 0000000000..d785760812 --- /dev/null +++ b/src/doc/book/second-edition/dot/trpl04-02.dot @@ -0,0 +1,34 @@ +digraph { + rankdir=LR; + dpi=300.0; + node [shape="plaintext"]; + + table0[label=< + + + + + +
s1
namevalue
ptr
len5
capacity5
>]; + table3[label=< + + + + + +
s2
namevalue
ptr
len5
capacity5
>]; + + table1[label=< + + + + + + +
indexvalue
0h
1e
2l
3l
4o
>]; + + edge[tailclip="false"]; + table0:pointer:c -> table1:pointee; + table3:pointer:c -> table1:pointee; +} + diff --git a/src/doc/book/second-edition/dot/trpl04-03.dot b/src/doc/book/second-edition/dot/trpl04-03.dot new file mode 100644 index 0000000000..2ddc335abb --- /dev/null +++ b/src/doc/book/second-edition/dot/trpl04-03.dot @@ -0,0 +1,43 @@ +digraph { + rankdir=LR; + dpi=300.0; + node [shape="plaintext"]; + + table0[label=< + + + + + +
s2
namevalue
ptr
len5
capacity5
>]; + table1[label=< + + + + + + +
indexvalue
0h
1e
2l
3l
4o
>]; + + table3[label=< + + + + + +
s1
namevalue
ptr
len5
capacity5
>]; + table4[label=< + + + + + + +
indexvalue
0h
1e
2l
3l
4o
>]; + + + edge[tailclip="false"]; + table0:pointer:c -> table1:pointee; + table3:pointer:c -> table4:pointee; +} + diff --git a/src/doc/book/second-edition/dot/trpl04-04.dot b/src/doc/book/second-edition/dot/trpl04-04.dot new file mode 100644 index 0000000000..87b1303e13 --- /dev/null +++ b/src/doc/book/second-edition/dot/trpl04-04.dot @@ -0,0 +1,34 @@ +digraph { + rankdir=LR; + dpi=300.0; + node [shape="plaintext"]; + + table0[label=< + + + + + +
s1
namevalue
ptr
len5
capacity5
>]; + table3[label=< + + + + + +
s2
namevalue
ptr
len5
capacity5
>]; + + table1[label=< + + + + + + +
indexvalue
0h
1e
2l
3l
4o
>]; + + edge[tailclip="false"]; + table0:pointer:c -> table1:pointee; + table3:pointer:c -> table1:pointee; +} + diff --git a/src/doc/book/second-edition/dot/trpl04-05.dot b/src/doc/book/second-edition/dot/trpl04-05.dot new file mode 100644 index 0000000000..55aa221fd6 --- /dev/null +++ b/src/doc/book/second-edition/dot/trpl04-05.dot @@ -0,0 +1,31 @@ +digraph { + rankdir=LR; + dpi=300.0; + node [shape="plaintext"]; + + table0[label=< + + + +
s
namevalue
ptr
>]; + table1[label=< + + + + + +
s1
namevalue
ptr
len5
capacity5
>]; + table2[label=< + + + + + + +
indexvalue
0h
1e
2l
3l
4o
>]; + + edge[tailclip="false"]; + table1:pointer:c -> table2:pointee; + table0:borrower:c -> table1:borrowee; +} + diff --git a/src/doc/book/second-edition/dot/trpl04-06.dot b/src/doc/book/second-edition/dot/trpl04-06.dot new file mode 100644 index 0000000000..a81d208fb8 --- /dev/null +++ b/src/doc/book/second-edition/dot/trpl04-06.dot @@ -0,0 +1,40 @@ +digraph { + rankdir=LR; + dpi=300.0; + node [shape="plaintext"]; + + table0[label=< + + + + +
world
namevalue
ptr
len5
>]; + + table3[label=< + + + + + +
s
namevalue
ptr
len11
capacity11
>]; + table4[label=< + + + + + + + + + + + + +
indexvalue
0h
1e
2l
3l
4o
5
6w
7o
8r
9l
10d
>]; + + + edge[tailclip="false"]; + table0:pointer2:c -> table4:pointee2; + table3:pointer:c -> table4:pointee; +} + diff --git a/src/doc/book/second-edition/dot/trpl15-01.dot b/src/doc/book/second-edition/dot/trpl15-01.dot new file mode 100644 index 0000000000..217d6d09e4 --- /dev/null +++ b/src/doc/book/second-edition/dot/trpl15-01.dot @@ -0,0 +1,23 @@ +digraph { + rankdir=LR; + dpi=300.0; + node [shape="plaintext"]; + + table0[label=< + + +
Cons
i32 + + +
Cons
i32 + + +
Cons
i32 + + +
Cons
i32 + + +
Cons
i32∞
>]; +} + diff --git a/src/doc/book/second-edition/dot/trpl15-02.dot b/src/doc/book/second-edition/dot/trpl15-02.dot new file mode 100644 index 0000000000..bdd8b517a1 --- /dev/null +++ b/src/doc/book/second-edition/dot/trpl15-02.dot @@ -0,0 +1,17 @@ +digraph { + rankdir=LR; + dpi=300.0; + node [shape="plaintext"]; + + table0[label=< + + + +
Cons
i32 + + + +
Box
usize
+
>]; +} + diff --git a/src/doc/book/second-edition/dot/trpl15-03.dot b/src/doc/book/second-edition/dot/trpl15-03.dot new file mode 100644 index 0000000000..5626de2485 --- /dev/null +++ b/src/doc/book/second-edition/dot/trpl15-03.dot @@ -0,0 +1,50 @@ +digraph { + rankdir=LR; + dpi=300.0; + node [shape="plaintext"]; + + table4[label=< + +
b
>]; + + table5[label=< + +
3
>]; + + + table0[label=< + +
a
>]; + + table1[label=< + +
5
>]; + + table2[label=< + +
10
>]; + + table3[label=< + +
Nil
>]; + + + table6[label=< + +
c
>]; + + table7[label=< + +
4
>]; + + + edge[tailclip="false"]; + table0:ptr0:c -> table1:pte0; + table1:ptr1:c -> table2:pte1; + table2:ptr2:c -> table3:pte2; + table4:ptr4:c -> table5:pte4; + table5:ptr5:c -> table1:pte0; + table6:ptr6:c -> table7:pte6; + table7:ptr7:c -> table1:pte0; +} + diff --git a/src/doc/book/second-edition/nostarch.sh b/src/doc/book/second-edition/nostarch.sh new file mode 100755 index 0000000000..a24d6bb9dd --- /dev/null +++ b/src/doc/book/second-edition/nostarch.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -eu + +cargo build --release + +mkdir -p tmp +rm -rf tmp/*.md + +# Get all the markdown files in the src dir, +ls src/*.md | \ +# except for SUMMARY.md. +grep -v SUMMARY.md | \ +# Extract just the filename so we can reuse it easily. +xargs -n 1 basename | \ +# Remove all links followed by , then +# Change all remaining links from markdown to italicized inline text. +while IFS= read -r filename; do + < "src/$filename" cargo run --bin remove_links \ + | cargo run --bin link2print \ + | cargo run --bin remove_markup > "tmp/$filename" +done +# Concat the files into the nostarch dir. +cargo run --bin concat_chapters tmp nostarch diff --git a/src/doc/book/second-edition/nostarch/appendix.md b/src/doc/book/second-edition/nostarch/appendix.md new file mode 100644 index 0000000000..6f061d779b --- /dev/null +++ b/src/doc/book/second-edition/nostarch/appendix.md @@ -0,0 +1,63 @@ +# Appendix + +The following sections contain reference material you may find useful in your +Rust journey. + +## Keywords + +The following keywords are reserved by the Rust language and may not be used as +names of functions, variables, macros, modules, crates, constants, static +values, attributes, struct fields, or arguments. + +* `abstract` +* `alignof` +* `as` +* `become` +* `box` +* `break` +* `const` +* `continue` +* `crate` +* `do` +* `else` +* `enum` +* `extern` +* `false` +* `final` +* `fn` +* `for` +* `if` +* `impl` +* `in` +* `let` +* `loop` +* `macro` +* `match` +* `mod` +* `move` +* `mut` +* `offsetof` +* `override` +* `priv` +* `proc` +* `pub` +* `pure` +* `ref` +* `return` +* `Self` +* `self` +* `sizeof` +* `static` +* `struct` +* `super` +* `trait` +* `true` +* `type` +* `typeof` +* `unsafe` +* `unsized` +* `use` +* `virtual` +* `where` +* `while` +* `yield` diff --git a/src/doc/book/second-edition/nostarch/chapter01.md b/src/doc/book/second-edition/nostarch/chapter01.md new file mode 100644 index 0000000000..f4dc4150e9 --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter01.md @@ -0,0 +1,516 @@ +# 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. + +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. + +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. + +## 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*. + +## 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. + +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. + +### Installing on Linux or Mac + +If you're on Linux or a Mac, all you need to do is open a terminal and type +this: + +```bash +$ 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: + +```bash +Rust is installed now. Great! +``` + +### Installing on Windows + +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 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. + +### Uninstalling + +Uninstalling Rust is as easy as installing it. 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: + +```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 don't and you're on Windows, check that Rust is in your `%PATH%` system +variable. + +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, 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 +at *https://users.rust-lang.org/* and Stack Overflow at +*http://stackoverflow.com/questions/tagged/rust*. + +### 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. + +## Hello, World! + +Now that you have Rust installed, let’s write your first Rust program. It's +traditional when learning a new language to write a little program to print the +text “Hello, world!” to the screen, and in this section, we'll follow that +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. + +### Creating a Project File + +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: + +Linux and Mac: + +```bash +$ mkdir ~/projects +$ cd ~/projects +$ mkdir hello_world +$ cd hello_world +``` + +Windows: + +```bash +$ mkdir %USERPROFILE%\projects +$ cd %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`. + +Now open the `main.rs` file you just created, and type the following code: + +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: + +```bash +$ 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. + +### 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 `)`. + +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. + +Inside the `main()` function: + +```rust + println!("Hello, world!"); +``` + +This line does all of the work in this little program: it prints text to the +screen. There are a number of details that are important here. The first is +that it’s indented 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. + +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! + +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 +`;`. + +### 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. + +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: + +```bash +$ ls +main main.rs +``` + +On Windows, you'd enter: + +```bash +$ dir /B # the /B option says to only show the file names +main.exe +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: + +```bash +$ ./main # or .\main.exe on Windows +``` + +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 +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 +introduce you to a tool called Cargo, which will help you write real-world Rust +programs. + +## Hello, Cargo! + +Cargo is Rust’s build system and package manager, and Rustaceans use Cargo to +manage their Rust projects because it makes a lot of tasks easier. For example, +Cargo takes care of building your code, downloading the libraries your code +depends on, and building those libraries. We call libraries your code needs +*dependencies*. + +The simplest Rust programs, like the one we've written so far, don’t have any +dependencies, so right now, you'd only be using the part of Cargo that can take +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 +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 +have Cargo installed by typing the following into your terminal: + +```bash +$ cargo --version +``` + +If you see a version number, great! If you see an error like `command not +found`, then you should look at the documentation for your method of +installation to determine how to install Cargo separately. + +### Creating a Project with Cargo + +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: + +```bash +$ cd ~/projects +``` + +Windows: + +```bash +$ cd %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. + +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. + +Open up `Cargo.toml` in your text editor of choice. It should look something +like this: + +Filename: Cargo.toml + +```toml +[package] +name = "hello_cargo" +version = "0.1.0" +authors = ["Your Name "] + +[dependencies] +``` + +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. + +The first line, `[package]`, is a section heading that indicates that the +following statements are configuring a package. As we add more information to +this file, we’ll add other sections. + +The next three lines set the three bits of configuration that Cargo needs to +see in order to know that it should compile your program: its name, what +version it is, and who wrote it. Cargo gets your name and email information +from your environment. If it’s not correct, go ahead and fix that and save the +file. + +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. + +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: + +1. Our code goes in the `src` directory +2. The top level contains a `Cargo.toml` configuration file + +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`. + +### 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) +``` + +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: + +```bash +$ ./target/debug/hello_cargo # or .\target\debug\hello_cargo.exe on Windows +Hello, world! +``` + +Bam! If all goes well, `Hello, world!` should print to the terminal once more. + +Running `cargo build` for the first time also causes Cargo to create a new file +at the top level called `Cargo.lock`, which 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. + +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: + +```bash +$ cargo run + Running `target/debug/hello_cargo` +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 +this: + +```bash +$ cargo run + Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo) + Running `target/debug/hello_cargo` +Hello, world! +``` + +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. + +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 +providing specific instructions for Linux and Mac versus Windows. + +### Building for Release + +When your project is finally ready for release, you can use `cargo build +--release` to compile your project with optimizations. This will create an +executable in `target/release` instead of `target/debug`. These optimizations +make your Rust code run faster, but turning them on 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`. + +### Cargo as Convention + +With simple projects, Cargo doesn't provide a whole lot of value over just +using `rustc`, but it will prove its worth as you continue. With complex +projects composed of multiple crates, it’s much easier to let Cargo coordinate +the build. With 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: + +```bash +$ 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. diff --git a/src/doc/book/second-edition/nostarch/chapter02.md b/src/doc/book/second-edition/nostarch/chapter02.md new file mode 100644 index 0000000000..fb500b2e91 --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter02.md @@ -0,0 +1,1048 @@ + +[TOC] + +# Guessing Game + +Let’s jump into Rust by working through a hands-on project together! This +chapter introduces you to a few common Rust concepts by showing you how to use +them in a real program. You’ll learn about `let`, `match`, methods, associated +functions, using external crates, and more! The following chapters will explore +these ideas in more detail. In this chapter, you’ll practice the fundamentals. + +We’ll implement a classic beginner programming problem: a guessing game. Here’s +how it works: the program will generate a random integer between 1 and 100. It +will then prompt the player to enter a guess. After entering a guess, it will +indicate whether the guess is too low or too high. If the guess is correct, the +game will print congratulations and exit. + +## Setting Up a New Project + +To set up a new project, go to the *projects* directory that you created in +Chapter 1, and make a new project using Cargo, like so: + +```bash +$ cargo new guessing_game --bin +$ cd guessing_game +``` + +The first command, `cargo new`, takes the name of the project (`guessing_game`) +as the first argument. The `--bin` flag tells Cargo to make a binary project, +similar to the one in Chapter 1. The second command changes to the new +project’s directory. + +Look at the generated *Cargo.toml* file: + +Filename: Cargo.toml + +```toml +[package] +name = "guessing_game" +version = "0.1.0" +authors = ["Your Name "] + +[dependencies] +``` + +If the author information that Cargo obtained from your environment is not +correct, fix that in the file and save it again. + +As you saw in Chapter 1, `cargo new` generates a “Hello, world!” program for +you. Check out the *src/main.rs* file: + +Filename: src/main.rs + +```rust +fn main() { + println!("Hello, world!"); +} +``` + +Now let’s compile this “Hello, world!” program and run it in the same step +using the `cargo run` command: + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) + Running `target/debug/guessing_game` +Hello, world! +``` + +The `run` command comes in handy when you need to rapidly iterate on a project, +and this game is such a project: we want to quickly test each iteration +before moving on to the next one. + +Reopen the *src/main.rs* file. You’ll be writing all the code in this file. + +## Processing a Guess + +The first part of the program will ask for user input, process that input, and +check that the input is in the expected form. To start, we’ll allow the player +to input a guess. Enter the code in Listing 2-1 into *src/main.rs*. + +Filename: src/main.rs + +```rust,ignore +use std::io; + +fn main() { + println!("Guess the number!"); + + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("Failed to read line"); + + println!("You guessed: {}", guess); +} +``` + + +Listing 2-1: Code to get a guess from the user and print it out + + +This code contains a lot of information, so let’s go over it bit by bit. To +obtain user input and then print the result as output, we need to import the +`io` (input/output) library from the standard library (which is known as `std`): + +```rust,ignore +use std::io; +``` + +By default, Rust imports only a few types into every program in the +*prelude*. If a type you want to use isn’t in the +prelude, you have to import that type into your program explicitly with a `use` +statement. Using the `std::io` library provides you with a number of useful +`io`-related features, including the functionality to accept user input. + +As you saw in Chapter 1, the `main` function is the entry point into the +program: + +```rust,ignore +fn main() { +``` + +The `fn` syntax declares a new function, the `()` indicate there are no +arguments, and `{` starts the body of the function. + +As you also learned in Chapter 1, `println!` is a macro that prints a string to +the screen: + +```rust,ignore +println!("Guess the number!"); + +println!("Please input your guess."); +``` + +This code is just printing a prompt stating what the game is and requesting +input from the user. + +### Storing Values with Variables + +Next, we’ll create a place to store the user input, like this: + +```rust,ignore +let mut guess = String::new(); +``` + +Now the program is getting interesting! There’s a lot going on in this little +line. Notice that this is a `let` statement, which is used to create +*variables*. Here’s another example: + +```rust,ignore +let foo = bar; +``` + +This line will create a new variable named `foo` and bind it to the value +`bar`. In Rust, variables are immutable by default. The following example shows +how to use `mut` before the variable name to make a variable mutable: + +```rust +let foo = 5; // immutable +let mut bar = 5; // mutable +``` + +> Note: The `//` syntax starts a comment that continues until the end of the +> line. Rust ignores everything in comments. + +Now you know that `let mut guess` will introduce a mutable variable named +`guess`. On the other side of the equal sign (`=`) is the value that `guess` is +bound to, which is the result of calling `String::new`, a function that returns +a new instance of a `String`. `String` is a string +type provided by the standard library that is a growable, UTF-8 encoded bit of +text. + +The `::` syntax in the `::new` line indicates that `new` is an *associated +function* of the `String` type. An associated function is implemented on a type, +in this case `String`, rather than on a particular instance of a `String`. Some +languages call this a *static method*. + +This `new` function creates a new, empty `String`. You’ll find a `new` function +on many types, because it’s a common name for a function that makes a new value +of some kind. + +To summarize, the `let mut guess = String::new();` line has created a mutable +variable that is currently bound to a new, empty instance of a `String`. Whew! + +Recall that we included the input/output functionality from the standard +library with `use std::io;` on the first line of the program. Now we’ll call an +associated function, `stdin`, on `io`: + +```rust,ignore +io::stdin().read_line(&mut guess) + .expect("Failed to read line"); +``` + +If we didn’t have the `use std::io` line at the beginning of the program, we +could have written this function call as `std::io::stdin`. The `stdin` function +returns an instance of `std::io::Stdin`, which is a +type that represents a handle to the standard input for your terminal. + +The next part of the code, `.read_line(&mut guess)`, calls the +`read_line` method on the standard input handle to +get input from the user. We’re also passing one argument to `read_line`: `&mut +guess`. + +The job of `read_line` is to take whatever the user types into standard input +and place that into a string, so it takes that string as an argument. The +string argument needs to be mutable so the method can change the string’s +content by adding the user input. + +The `&` indicates that this argument is a *reference*, which gives you a way to +let multiple parts of your code access one piece of data without needing to +copy that data into memory multiple times. References are a complex feature, +and one of Rust’s major advantages is how safe and easy it is to use +references. You don’t need to know a lot of those details to finish this +program: Chapter 4 will explain references more thoroughly. For now, all you +need to know is that like variables, references are immutable by default. +Hence, we need to write `&mut guess` rather than `&guess` to make it mutable. + +We’re not quite done with this line of code. Although it’s a single line of +text, it’s only the first part of the single logical line of code. The second +part is this method: + +```rust,ignore +.expect("Failed to read line"); +``` + +When you call a method with the `.foo()` syntax, it’s often wise to introduce a +newline and other whitespace to help break up long lines. We could have +written this code as: + +```rust,ignore +io::stdin().read_line(&mut guess).expect("Failed to read line"); +``` + +However, one long line is difficult to read, so it’s best to divide it, two +lines for two method calls. Now let’s discuss what this line does. + +### Handling Potential Failure with the `Result` Type + +As mentioned earlier, `read_line` puts what the user types into the string we’re +passing it, but it also returns a value—in this case, an +`io::Result`. Rust has a number of types named +`Result` in its standard library: a generic `Result` as +well as specific versions for submodules, such as `io::Result`. + +The `Result` types are *enumerations*, often referred +to as *enums*. An enumeration is a type that can have a fixed set of values, +and those values are called the enum’s *variants*. Chapter 6 will cover enums +in more detail. + +For `Result`, the variants are `Ok` or `Err`. `Ok` indicates the operation was +successful, and inside the `Ok` variant is the successfully generated value. +`Err` means the operation failed, and `Err` contains information about how or +why the operation failed. + +The purpose of these `Result` types is to encode error handling information. +Values of the `Result` type, like any type, have methods defined on them. An +instance of `io::Result` has an `expect` method that +you can call. If this instance of `io::Result` is an `Err` value, `expect` will +cause the program to crash and display the message that you passed as an +argument to `expect`. If the `read_line` method returns an `Err`, it would +likely be the result of an error coming from the underlying operating system. +If this instance of `io::Result` is an `Ok` value, `expect` will take the +return value that `Ok` is holding and return just that value to you so you +could use it. In this case, that value is the number of characters the user +entered into standard input. + +If we don’t call `expect`, the program will compile, but we’ll get a warning: + +```bash +$ cargo build + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) +src/main.rs:10:5: 10:39 warning: unused result which must be used, +#[warn(unused_must_use)] on by default +src/main.rs:10 io::stdin().read_line(&mut guess); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +Rust warns that we haven’t used the `Result` value returned from `read_line`, +indicating that the program hasn’t handled a possible error. The right way to +suppress the warning is to actually write error handling, but since we just +want to crash this program when a problem occurs, we can use `expect`. You’ll +learn about recovering from errors in Chapter 9. + +### Printing Values with `println!` Placeholders + +Aside from the closing curly brace, there’s only one more line to discuss in +the code added so far, which is the following: + +```rust,ignore +println!("You guessed: {}", guess); +``` + +This line prints out the string we saved the user’s input in. The set of `{}` +is a placeholder that holds a value in place. You can print more than one value +using `{}`: the first set of `{}` holds the first value listed after the format +string, the second set holds the second value, and so on. Printing out multiple +values in one call to `println!` would look like this: + +```rust +let x = 5; +let y = 10; + +println!("x = {} and y = {}", x, y); +``` + +This code would print out `x = 5 and y = 10`. + +### Testing the First Part + +Let’s test the first part of the guessing game. You can run it using `cargo run`: + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) + Running `target/debug/guessing_game` +Guess the number! +Please input your guess. +6 +You guessed: 6 +``` + +At this point, the first part of the game is done: we’re getting input from the +keyboard and then printing it. + +## Generating a Secret Number + +Next, we need to generate a secret number that the user will try to guess. The +secret number should be different every time so the game is fun to play more +than once. Let’s use a random number between 1 and 100 so the game isn’t too +difficult. Rust doesn’t yet include random number functionality in its standard +library. However, the Rust team does provide a `rand` crate at *https://crates.io/crates/rand*. + + +### Using a Crate to Get More Functionality + +Remember that a *crate* is a package of Rust code. The project we’ve been +building is a *binary crate*, which is an executable. The `rand` crate is a +*library crate*, which contains code intended to be used in other programs. + +Cargo’s use of external crates is where it really shines. Before we can write +code that uses `rand`, we need to modify the *Cargo.toml* file to include the +`rand` crate as a dependency. Open that file now and add the following line to +the bottom beneath the `[dependencies]` section header that Cargo created for +you: + +Filename: Cargo.toml + +```toml +[dependencies] + +rand = "0.3.14" +``` + +In the *Cargo.toml* file, everything that follows a header is part of a section +that continues until another section starts. The `[dependencies]` section is +where you tell Cargo which external crates your project depends on and which +versions of those crates you require. In this case, we’ll specify the `rand` +crate with the semantic version specifier `0.3.14`. Cargo understands Semantic +Versioning (sometimes called *SemVer*), which is a +standard for writing version numbers. The number `0.3.14` is actually shorthand +for `^0.3.14`, which means “any version that has a public API compatible with +version 0.3.14.” + +Now, without changing any of the code, let’s build the project, as shown in +Listing 2-2: + +```bash +$ cargo build + Updating registry `https://github.com/rust-lang/crates.io-index` + Downloading rand v0.3.14 + Downloading libc v0.2.14 + Compiling libc v0.2.14 + Compiling rand v0.3.14 + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) +``` + + +Listing 2-2: The output from running `cargo build` after adding the rand crate +as a dependency + + +You may see different version numbers (but they will all be compatible with +the code, thanks to SemVer!), and the lines may be in a different order. + +Now that we have an external dependency, Cargo fetches the latest versions of +everything from the *registry*, which is a copy of data from +Crates.io at *https://crates.io*. Crates.io is where people in the Rust ecosystem post +their open source Rust projects for others to use. + + +After updating the registry, Cargo checks the `[dependencies]` section and +downloads any you don’t have yet. In this case, although we only listed `rand` +as a dependency, Cargo also grabbed a copy of `libc`, because `rand` depends on +`libc` to work. After downloading them, Rust compiles them and then compiles +the project with the dependencies available. + +If you immediately run `cargo build` again without making any changes, you won’t +get any output. Cargo knows it has already downloaded and compiled the +dependencies, and you haven't changed anything about them in your *Cargo.toml* +file. Cargo also knows that you haven't changed anything about your code, so it +doesn't recompile that either. With nothing to do, it simply exits. If you open +up the *src/main.rs* file, make a trivial change, then save it and build again, +you’ll only see one line of output: + +```bash +$ cargo build + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) +``` + +This line shows Cargo only updates the build with your tiny change to the +*src/main.rs* file. Your dependencies haven't changed, so Cargo knows it can +reuse what it has already downloaded and compiled for those. It just rebuilds +your part of the code. + +#### The *Cargo.lock* File Ensures Reproducible Builds + +Cargo has a mechanism that ensures you can rebuild the same artifact every time +you or anyone else builds your code: Cargo will use only the versions of the +dependencies you specified until you indicate otherwise. For example, what +happens if next week version `v0.3.15` of the `rand` crate comes out and +contains an important bug fix but also contains a regression that will break +your code? + +The answer to this problem is the *Cargo.lock* file, which was created the +first time you ran `cargo build` and is now in your *guessing_game* directory. +When you build a project for the first time, Cargo figures out all the +versions of the dependencies that fit the criteria and then writes them to +the *Cargo.lock* file. When you build your project in the future, Cargo will +see that the *Cargo.lock* file exists and use the versions specified there +rather than doing all the work of figuring out versions again. This lets you +have a reproducible build automatically. In other words, your project will +remain at `0.3.14` until you explicitly upgrade, thanks to the *Cargo.lock* +file. + +#### Updating a Crate to Get a New Version + +When you *do* want to update a crate, Cargo provides another command, `update`, +which will: + +1. Ignore the *Cargo.lock* file and figure out all the latest versions that fit +your specifications in *Cargo.toml*. +1. If that works, Cargo will write those versions to the *Cargo.lock* file. + +But by default, Cargo will only look for versions larger than `0.3.0` and +smaller than `0.4.0`. If the `rand` crate has released two new versions, +`0.3.15` and `0.4.0`, you would see the following if you ran `cargo update`: + +```bash +$ cargo update + Updating registry `https://github.com/rust-lang/crates.io-index` + Updating rand v0.3.14 -> v0.3.15 +``` + +At this point, you would also notice a change in your *Cargo.lock* file noting +that the version of the `rand` crate you are now using is `0.3.15`. + +If you wanted to use `rand` version `0.4.0` or any version in the `0.4.x` +series, you’d have to update the *Cargo.toml* file to look like this instead: + +```toml +[dependencies] + +rand = "0.4.0" +``` + +The next time you run `cargo build`, Cargo will update the registry of crates +available and reevaluate your `rand` requirements according to the new version +you specified. + +There’s a lot more to say about Cargo and its +ecosystem that Chapter XX will discuss, but for +now, that’s all you need to know. Cargo makes it very easy to reuse libraries, +so Rustaceans are able to write smaller projects that are assembled from a +number of packages. + +### Generating a Random Number + +Let’s start *using* `rand`. The next step is to update *src/main.rs*, as shown +in Listing 2-3: + +Filename: src/main.rs + +```rust,ignore +extern crate rand; + +use std::io; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("Failed to read line"); + + println!("You guessed: {}", guess); +} +``` + + +Listing 2-3: Code changes needed in order to generate a random number + + +We’re adding a `extern crate rand;` line to the top that lets Rust know we’ll be +using that external dependency. This also does the equivalent of calling `use +rand`, so now we can call anything in the `rand` crate by prefixing it with +`rand::`. + +Next, we’re adding another `use` line: `use rand::Rng`. `Rng` is a trait that +defines methods that random number generators implement, and this trait must be +in scope for us to use those methods. Chapter 10 will cover traits in detail. + +Also, we’re adding two more lines in the middle. The `rand::thread_rng` function +will give us the particular random number generator that we’re going to use: +one that is local to the current thread of execution and seeded by the +operating system. Next, we call the `gen_range` method on the random number +generator. This method is defined by the `Rng` trait that we brought into +scope with the `use rand::Rng` statement. The `gen_range` method takes two +numbers as arguments and generates a random number between them. It’s inclusive +on the lower bound but exclusive on the upper bound, so we need to specify `1` +and `101` to request a number between 1 and 100. + +Knowing which traits to import and which functions and methods to use from a +crate isn’t something that you’ll just *know*. Instructions for using a crate +are in each crate’s documentation. Another neat feature of Cargo is that you +can run the `cargo doc --open` command that will build documentation provided +by all of your dependencies locally and open it in your browser. If you’re +interested in other functionality in the `rand` crate, for example, run `cargo +doc --open` and click `rand` in the sidebar on the left. + +The second line that we added to the code prints the secret number. This is +useful while we’re developing the program to be able to test it, but we’ll +delete it from the final version. It’s not much of a game if the program prints +the answer as soon as it starts! + +Try running the program a few times: + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) + Running `target/debug/guessing_game` +Guess the number! +The secret number is: 7 +Please input your guess. +4 +You guessed: 4 +$ cargo run + Running `target/debug/guessing_game` +Guess the number! +The secret number is: 83 +Please input your guess. +5 +You guessed: 5 +``` + +You should get different random numbers, and they should all be numbers between +1 and 100. Great job! + +## Comparing the Guess to the Secret Number + +Now that we have user input and a random number, we can compare them. That +step is shown in Listing 2-4: + +Filename: src/main.rs + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("Failed to read line"); + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => println!("You win!"), + } +} +``` + + +Listing 2-4: Handling the possible return values of comparing two numbers + + +The first new bit here is another `use`, bringing a type called +`std::cmp::Ordering` into scope from the standard library. `Ordering` is +another enum, like `Result`, but the variants for `Ordering` are `Less`, +`Greater`, and `Equal`. These are the three outcomes that are possible when you +compare two values. + +Then we add five new lines at the bottom that use the `Ordering` type: + +```rust,ignore +match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => println!("You win!"), +} +``` + +The `cmp` method compares two values and can be called on anything that can be +compared. It takes a reference to whatever you want to compare with: here it’s +comparing the `guess` to the `secret_number`. `cmp` returns a variant of the +`Ordering` enum we imported with the `use` statement. We use a +`match` expression to decide what to do next based on +which variant of `Ordering` was returned from the call to `cmp` with the values +in `guess` and `secret_number`. + +A `match` expression is made up of *arms*. An arm consists of a *pattern* and +the code that should be run if the value given to the beginning of the `match` +expression fits that arm’s pattern. Rust takes the value given to `match` and +looks through each arm’s pattern in turn. The `match` construct and patterns +are powerful features in Rust that let you express a variety of situations your +code might encounter and helps ensure that you handle them all. These features +will be covered in detail in Chapter 6 and Chapter XX, respectively. + +Let’s walk through an example of what would happen with the `match` expression +used here. Say that the user has guessed 50, and the randomly generated secret +number this time is 38. When the code compares 50 to 38, the `cmp` method will +return `Ordering::Greater`, because 50 is greater than 38. `Ordering::Greater` +is the value that the `match` expression gets. It looks at the first arm’s +pattern, `Ordering::Less`, but the value `Ordering::Greater` does not match +`Ordering::Less`. So it ignores the code in that arm and moves to the next arm. +The next arm’s pattern, `Ordering::Greater`, *does* match +`Ordering::Greater`! The associated code in that arm will execute and print +`Too big!` to the screen. The `match` expression ends because it has no need to +look at the last arm in this particular scenario. + +However, the code in Listing 2-4 won’t compile yet. Let’s try it: + +```bash +$ cargo build + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) +error[E0308]: mismatched types + --> src/main.rs:23:21 + | +23 | match guess.cmp(&secret_number) { + | ^^^^^^^^^^^^^^ expected struct `std::string::String`, found integral variable + | + = note: expected type `&std::string::String` + = note: found type `&{integer}` + +error: aborting due to previous error +Could not compile `guessing_game`. +``` + +The core of the error states that there are *mismatched types*. Rust has a +strong, static type system. However, it also has type inference. When we wrote +`let guess = String::new()`, Rust was able to infer that `guess` should be a +`String` and didn’t make us write the type. The `secret_number`, on the other +hand, is a number type. A few number types can have a value between 1 and 100: +`i32`, a 32-bit number; `u32`, an unsigned 32-bit number; `i64`, a 64-bit +number; as well as others. Rust defaults to an `i32`, which is the type of +`secret_number` unless we add type information elsewhere that would cause Rust +to infer a different numerical type. The reason for the error is that Rust will +not compare a string and a number type. + +Ultimately, we want to convert the `String` the program reads as input into a +real number type so we can compare it to the guess numerically. We can do +that by adding the following two lines to the `main` function body: + +Filename: src/main.rs + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("Failed to read line"); + + let guess: u32 = guess.trim().parse() + .expect("Please type a number!"); + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => println!("You win!"), + } +} +``` + +The two new lines are: + +```rust,ignore +let guess: u32 = guess.trim().parse() + .expect("Please type a number!"); +``` + +We create a variable named `guess`. But wait, doesn’t the program +already have a variable named `guess`? It does, but Rust allows us to +*shadow* the previous value of `guess` with a new one. This feature is often +used in similar situations in which you want to convert a value from one type +to another type. Shadowing lets us reuse the `guess` variable name rather than +forcing us to create two unique variables, like `guess_str` and `guess` for +example. (Chapter 3 covers shadowing in more detail.) + +We bind `guess` to the expression `guess.trim().parse()`. The `guess` in the +expression refers to the original `guess` that was a `String` with the input in +it. The `trim` method on a `String` instance will eliminate any whitespace at +the beginning and end. `u32` can only contain numerical characters, but the +user must press the Return key to satisfy `read_line`. When the user presses +Return, a newline character is added to the string. For example, if the user +types 5 and presses return, `guess` looks like this: `5\n`. The `\n` represents +“newline,” the return key. The `trim` method eliminates `\n`, resulting in just +`5`. + +The `parse` method on strings parses a string into some +kind of number. Because this method can parse a variety of number types, we +need to tell Rust the exact number type we want by using `let guess: u32`. The +colon (`:`) after `guess` tells Rust we’ll annotate the variable’s type. Rust +has a few built-in number types; the `u32` seen here is an unsigned, 32-bit +integer. It’s a good default choice for a small positive number. You’ll learn +about other number types in Chapter 3. Additionally, the `u32` annotation in +this example program and the comparison with `secret_number` means that Rust +will infer that `secret_number` should be a `u32` as well. So now the +comparison will be between two values of the same type! + +The call to `parse` could easily cause an error. If, for example, the string +contained `A👍%`, there would be no way to convert that to a number. Because it +might fail, the `parse` method returns a `Result` type, much like the +`read_line` method does as discussed earlier in “Handling Potential Failure +with the Result Type” on page XX. We’ll treat this `Result` the same way by +using the `expect` method again. If `parse` returns an `Err` `Result` variant +because it couldn’t create a number from the string, the `expect` call will +crash the game and print the message we give it. If `parse` can successfully +convert the string to a number, it will return the `Ok` variant of `Result`, +and `expect` will return the number that we want from the `Ok` value. + +Let’s run the program now! + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) + Running `target/guessing_game` +Guess the number! +The secret number is: 58 +Please input your guess. + 76 +You guessed: 76 +Too big! +``` + +Nice! Even though spaces were added before the guess, the program still figured +out that the user guessed 76. Run the program a few times to verify the +different behavior with different kinds of input: guess the number correctly, +guess a number that is too high, and guess a number that is too low. + +We have most of the game working now, but the user can make only one guess. +Let’s change that by adding a loop! + +## Allowing Multiple Guesses with Looping + +The `loop` keyword gives us an infinite loop. Add that now to give users more +chances at guessing the number: + +Filename: src/main.rs + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + loop { + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("Failed to read line"); + + let guess: u32 = guess.trim().parse() + .expect("Please type a number!"); + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => println!("You win!"), + } + } +} +``` + +As you can see, we’ve moved everything into a loop from the guess input prompt +onward. Be sure to indent those lines another four spaces each, and run the +program again. Notice that there is a new problem because the program is doing +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 insatiable monster that we mentioned in +the `parse` discussion in “Comparing the Guesses” on page XX: 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: + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) + Running `target/guessing_game` +Guess the number! +The secret number is: 59 +Please input your guess. +45 +You guessed: 45 +Too small! +Please input your guess. +60 +You guessed: 60 +Too big! +Please input your guess. +59 +You guessed: 59 +You win! +Please input your guess. +quit +thread 'main' panicked at 'Please type a number!: ParseIntError { kind: InvalidDigit }', src/libcore/result.rs:785 +note: Run with `RUST_BACKTRACE=1` for a backtrace. +error: Process didn't exit successfully: `target/debug/guess` (exit code: 101) +``` + +Typing `quit` actually quits the game, but so will any other non-number input. +However, this is suboptimal to say the least. We want the game to automatically +stop when the correct number is guessed. + +### Quitting After a Correct Guess + +Let’s program the game to quit when the user wins by adding a `break`: + +Filename: src/main.rs + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + println!("The secret number is: {}", secret_number); + + loop { + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("Failed to read line"); + + let guess: u32 = guess.trim().parse() + .expect("Please type a number!"); + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => { + println!("You win!"); + break; + } + } + } +} +``` + +By adding the `break` line after `You win!`, the program will exit the loop +when the user guesses the secret number correctly. Exiting the loop also means +exiting the program, because the loop is the last part of `main`. + +### Handling Invalid Input + +To further refine the game’s behavior, rather than crashing the program when +the user inputs a non-number, let’s make the game ignore a non-number so the +user can continue guessing. We can do that by altering the line where `guess` is +converted from a `String` to a `u32`: + +```rust,ignore +let guess: u32 = match guess.trim().parse() { + Ok(num) => num, + Err(_) => continue, +}; +``` + +Switching from an `expect` call to a `match` expression is how you generally +move from crash on error to actually handling the error. Remember that `parse` +returns a `Result` type, and `Result` is an enum that has the variants `Ok` or +`Err`. We’re using a `match` expression here, like we did with the `Ordering` +result of the `cmp` method. + +If `parse` is able to successfully turn the string into a number, it will return +an `Ok` value that contains the resulting number. That `Ok` value will match the +first arm’s pattern, and the `match` expression will just return the `num` value +that `parse` produced and put inside the `Ok` value. That number will end up +right where we want it in the new `guess` variable we’re creating. + +If `parse` is *not* able to turn the string into a number, it will return an +`Err` value that contains more information about the error. The `Err` value +does not match the `Ok(num)` pattern in the first `match` arm, but it does match +the `Err(_)` pattern in the second arm. The `_` is a catchall value; in this +example, we’re saying we want to match all `Err` values, no matter what +information they have inside them. So the program will execute the second arm’s +code, `continue`, which means to go to the next iteration of the `loop` and ask +for another guess. So effectively, the program ignores all errors that `parse` +might encounter! + +Now everything in the program should work as expected. Let’s try it by running +`cargo run`: + +```bash +$ cargo run + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) + Running `target/guessing_game` +Guess the number! +The secret number is: 61 +Please input your guess. +10 +You guessed: 10 +Too small! +Please input your guess. +99 +You guessed: 99 +Too big! +Please input your guess. +foo +Please input your guess. +61 +You guessed: 61 +You win! +``` + +Awesome! With one tiny final tweak, we will finish the guessing game: recall +that the program is still printing out the secret number. That worked well for +testing, but it ruins the game. Let’s delete the `println!` that outputs the +secret number. Listing 2-5 shows the final code: + +Filename: src/main.rs + +```rust,ignore +extern crate rand; + +use std::io; +use std::cmp::Ordering; +use rand::Rng; + +fn main() { + println!("Guess the number!"); + + let secret_number = rand::thread_rng().gen_range(1, 101); + + loop { + println!("Please input your guess."); + + let mut guess = String::new(); + + io::stdin().read_line(&mut guess) + .expect("Failed to read line"); + + let guess: u32 = match guess.trim().parse() { + Ok(num) => num, + Err(_) => continue, + }; + + println!("You guessed: {}", guess); + + match guess.cmp(&secret_number) { + Ordering::Less => println!("Too small!"), + Ordering::Greater => println!("Too big!"), + Ordering::Equal => { + println!("You win!"); + break; + } + } + } +} +``` + + +Listing 2-5: Complete code of the guessing game + + +## Summary + +At this point, you’ve successfully built the guessing game! Congratulations! + +This project was a hands-on way to introduce you to many new Rust concepts: +`let`, `match`, methods, associated functions, using external crates, and more. +In the next few chapters, you’ll learn about these concepts in more detail. +Chapter 3 covers concepts that most programming languages have, such as +variables, data types, and functions, and shows how to use them in Rust. +Chapter 4 explores ownership, which is a Rust feature that is most different +from other languages. Chapter 5 discusses structs and method syntax, and +Chapter 6 endeavors to explain enums. diff --git a/src/doc/book/second-edition/nostarch/chapter03.md b/src/doc/book/second-edition/nostarch/chapter03.md new file mode 100644 index 0000000000..a70d090f22 --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter03.md @@ -0,0 +1,1469 @@ + +[TOC] + +# Common Programming Concepts + +This chapter covers concepts that appear in almost every programming language +and how they work in Rust. Many programming languages have much in common at +their core. None of the concepts presented in this chapter are unique to Rust, +but we’ll discuss them in the context of Rust and explain their conventions. + +Specifically, you’ll learn about variables, basic types, functions, comments, +and control flow. These foundations will be in every Rust program, and learning +them early will give you a strong core to start from. + +PROD: START BOX + +### Keywords + +The Rust language has a set of *keywords* that have been reserved for use by +the language only, much like other languages do. Keep in mind that you cannot +use these words as names of variables or functions. Most of the keywords have +special meanings, and you’ll be using them to do various tasks in your Rust +programs; a few have no current functionality associated with them but have +been reserved for functionality that might be added to Rust in the future. You +can find a list of the keywords in Appendix A. + +PROD: END BOX + +## Variables and Mutability + +As mentioned in Chapter 2, by default variables are *immutable*. This is one of +many nudges in Rust that encourages you to write your code in a way that takes +advantage of the safety and easy concurrency that Rust offers. However, you +still have the option to make your variables mutable. Let’s explore how and why +Rust encourages you to favor immutability, and why you might want to opt out. + +When a variable is immutable, that means once a value is bound to a name, you +can’t change that value. To illustrate, let’s generate a new project called +*variables* in your *projects* directory by using `cargo new --bin variables`. + +Then, in your new *variables* directory, open *src/main.rs* and replace its +code with the following: + +Filename: src/main.rs + +```rust,ignore +fn main() { + let x = 5; + println!("The value of x is: {}", x); + x = 6; + println!("The value of x is: {}", x); +} +``` + +Save and run the program using `cargo run`. You should receive an error +message, as shown in this output: + +``` +error[E0384]: re-assignment of immutable variable `x` + --> src/main.rs:4:5 + | +2 | let x = 5; + | - first assignment to `x` +3 | println!("The value of x is: {}", x); +4 | x = 6; + | ^^^^^ re-assignment of immutable variable +``` + +This example shows how the compiler helps you find errors in your programs. +Even though compiler errors can be frustrating, they only mean your program +isn’t safely doing what you want it to do yet; they do *not* mean that you’re +not a good programmer! Experienced Rustaceans still get compiler errors. The +error indicates that the cause of the error is `re-assignment of immutable +variable`, because we tried to assign a second value to the immutable `x` +variable. + +It’s important that we get compile-time errors when we attempt to change a +value that we previously designated as immutable because this very situation +can lead to bugs. If one part of our code operates on the assumption that a +value will never change and another part of our code changes that value, it’s +possible that the first part of the code won’t do what it was designed to do. +This cause of bugs can be difficult to track down after the fact, especially +when the second piece of code changes the value only *sometimes*. + +In Rust the compiler guarantees that when we state that a value won’t change, +it really won’t change. That means that when you’re reading and writing code, +you don’t have to keep track of how and where a value might change, which can +make code easier to reason about. + +But mutability can be very useful. Variables are immutable only by default; we +can make them mutable by adding `mut` in front of the variable name. In +addition to allowing this value to change, it conveys intent to future readers +of the code by indicating that other parts of the code will be changing this +variable value. + +For example, change *src/main.rs* to the following: + +Filename: src/main.rs + +```rust +fn main() { + let mut x = 5; + println!("The value of x is: {}", x); + x = 6; + println!("The value of x is: {}", x); +} +``` + +When we run this program, we get the following: + +```bash +$ cargo run + Compiling variables v0.1.0 (file:///projects/variables) + Running `target/debug/variables` +The value of x is: 5 +The value of x is: 6 +``` + +Using `mut`, we’re allowed to change the value that `x` binds to from `5` to +`6`. In some cases, you’ll want to make a variable mutable because it makes the +code more convenient to write than an implementation that only uses immutable +variables. + +There are multiple trade-offs to consider, in addition to the prevention of +bugs. For example, in cases where you’re using large data structures, mutating +an instance in place may be faster than copying and returning newly allocated +instances. With smaller data structures, creating new instances and writing in +a more functional programming style may be easier to reason about, so the lower +performance might be a worthwhile penalty for gaining that clarity. + +### Differences Between Variables and Constants + +Being unable to change the value of a variable might have reminded you of +another programming concept that most other languages have: *constants*. Like +immutable variables, constants are also values that are bound to a name and +are not allowed to change, but there are a few differences between constants +and variables. + +First, we aren’t allowed to use `mut` with constants: constants aren't only +immutable by default, they're always immutable. + +We declare constants using the `const` keyword instead of the `let` keyword, +and the type of the value *must* be annotated. We're about to cover types and +type annotations in the next section, “Data Types,” so don't worry about the +details right now, just know that we must always annotate the type. + +Constants can be declared in any scope, including the global scope, which makes +them useful for values that many parts of code need to know about. + +The last difference is that constants 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. + +Here's an example of a constant declaration where the constant's name is +`MAX_POINTS` and its value is set to 100,000. (Rust constant naming convention +is to use all upper case with underscores between words): + +``` +const MAX_POINTS: u32 = 100_000; +``` + +Constants are valid for the entire time a program runs, within the scope they +were declared in, making them a useful choice for values in your application +domain that multiple part of the program might need to know about, such as the +maximum number of points any player of a game is allowed to earn or the speed +of light. + +Naming hardcoded values used throughout your program as constants is useful in +conveying the meaning of that value to future maintainers of the code. It also +helps to have only one place in your code you would need to change if the +hardcoded value needed to be updated in the future. + +### Shadowing + +As we saw in the guessing game tutorial in Chapter 2, we can declare new +variables with the same name as a previous variables, and the new variable +*shadows* the previous variable. Rustaceans say that the first variable is +*shadowed* by the second, which means that the second variable’s value is what +we’ll see when we use the variable. We can shadow a variable by using the same +variable’s name and repeating the use of the `let` keyword as follows: + +Filename: src/main.rs + +```rust +fn main() { + let x = 5; + + let x = x + 1; + + let x = x * 2; + + println!("The value of x is: {}", x); +} +``` + +This program first binds `x` to a value of `5`. Then it shadows `x` by +repeating `let x =`, taking the original value and adding `1` so the value of +`x` is then `6`. The third `let` statement also shadows `x`, taking the +previous value and multiplying it by `2` to give `x` a final value of `12`. +When you run this program, it will output the following: + +```bash +$ cargo run + Compiling variables v0.1.0 (file:///projects/variables) + Running `target/debug/variables` +The value of x is: 12 +``` + +This is different than marking a variable as `mut`, because unless we use the +`let` keyword again, we’ll get a compile-time error if we accidentally try to +reassign to this variable. We can perform a few transformations on a value but +have the variable be immutable after those transformations have been completed. + +The other difference between `mut` and shadowing is that because we’re +effectively creating a new variable when we use the `let` keyword again, we can +change the type of the value, but reuse the same name. For example, say our +program asks a user to show how many spaces they want between some text by +inputting space characters, but we really want to store that input as a number: + +```rust +let spaces = " "; +let spaces = spaces.len(); +``` + +This construct is allowed because the first `spaces` variable is a string type, +and the second `spaces` variable, which is a brand-new variable that happens to +have the same name as the first one, is a number type. Shadowing thus spares us +from having to come up with different names, like `spaces_str` and +`spaces_num`; instead, we can reuse the simpler `spaces` name. However, if we +try to use `mut` for this, as shown here: + +```rust,ignore +let mut spaces = " "; +spaces = spaces.len(); +``` + +we’ll get a compile-time error because we’re not allowed to mutate a variable’s +type: + +```bash +error[E0308]: mismatched types + --> src/main.rs:3:14 + | +3 | spaces = spaces.len(); + | ^^^^^^^^^^^^ expected &str, found usize + | + = note: expected type `&str` + found type `usize` +``` + +Now that we’ve explored how variables work, let’s look at more data types they +can have. + +## Data Types + +Every value in Rust is of a certain *type*, which tells Rust what kind of data +is being specified so it knows how to work with that data. In this section, +we’ll look at a number of types that are built into the language. We split the +types into two subsets: scalar and compound. + +Throughout this section, keep in mind that 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, such as when we +converted a `String` to a numeric type using `parse` in Chapter 2, we must add +a type annotation, like this: + +``` +let guess: u32 = "42".parse().expect("Not a number!"); +``` + +If we don’t add the type annotation here, Rust will display the following +error, which means the compiler needs more information from us to know which +possible type we want to use: + +```bash +error[E0282]: unable to infer enough type information about `_` + --> src/main.rs:2:9 + | +2 | let guess = "42".parse().expect("Not a number!"); + | ^^^^^ cannot infer type for `_` + | + = note: type annotations or generic parameter binding required +``` + +You’ll see different type annotations as we discuss the various data types. + +### Scalar Types + +A *scalar* type represents a single value. Rust has four primary scalar types: +integers, floating-point numbers, booleans, and characters. You’ll likely +recognize these from other programming languages, but let’s jump into how they +work in Rust. + +#### Integer Types + +An *integer* is a number without a fractional component. We used one integer +type earlier in this chapter, the `i32` type. This type declaration indicates +that the value it’s associated with should be a signed integer (hence the `i`, +as opposed to a `u` for unsigned) that takes up 32 bits of space. Table 3-1 +shows the built-in integer types in Rust. Each variant in the Signed and +Unsigned columns (for example, *i32*) can be used to declare the type of an +integer value. + + +Table 3-1: Integer Types in Rust + + +| Length | Signed | Unsigned | +|--------|--------|----------| +| 8-bit | i8 | u8 | +| 16-bit | i16 | u16 | +| 32-bit | i32 | u32 | +| 64-bit | i64 | u64 | +| arch | isize | usize | + +Each variant can be either signed or unsigned and has an explicit size. +Signed and unsigned refers to whether it’s possible for the number to be +negative or positive; in other words, whether the number needs to have a sign +with it (signed) or whether it will only ever be positive and can therefore be +represented without a sign (unsigned). It’s like writing numbers on paper: when +the sign matters, a number is shown with a plus sign or a minus sign; however, +when it’s safe to assume the number is positive, it’s shown with no sign. +Signed numbers are stored using two’s complement representation (if you’re +unsure what this is, you can search for it online; an explanation is outside +the scope of this book). + +Each signed variant can store numbers from -2n - 1 to 2n - 1 - 1 inclusive, +where `n` is the number of bits that variant uses. So an `i8` can store numbers +from -27 to 27 - 1, which equals -128 to 127. Unsigned variants can store +numbers from 0 to 2n - 1, so a `u8` can store numbers from 0 to 28 - 1, which +equals 0 to 255. + +Additionally, the `isize` and `usize` types depend on the kind of computer your +program is running on: 64-bits if you’re on a 64-bit architecture and 32-bits +if you’re on a 32-bit architecture. + +You can write integer literals in any of the forms shown in Table 3-2. Note +that all number literals except the byte literal allow a type suffix, such as +`57u8`, and `_` as a visual separator, such as `1_000`. + + +Table 3-2: Integer Literals in Rust + + +| Number literals | Example | +|------------------|---------------| +| Decimal | `98_222` | +| Hex | `0xff` | +| Octal | `0o77` | +| Binary | `0b1111_0000` | +| Byte (`u8` only) | `b'A'` | + +So how do you know which type of integer to use? If you’re unsure, Rust’s +defaults are generally good choices, and integer types default to `i32`: it’s +generally the fastest, even on 64-bit systems. The primary situation in which +you’d use `isize` or `usize` is when indexing some sort of collection. + +#### Floating-Point Types + +Rust also has two primitive types for *floating-point numbers*, which are +numbers with decimal points. Rust’s floating-point types are `f32` and `f64`, +which are 32 bits and 64 bits in size, respectively. The default type is `f64` +because it’s roughly the same speed as `f32` but is capable of more precision. +It’s possible to use an `f64` type on 32-bit systems, but it will be slower +than using an `f32` type on those systems. Most of the time, trading potential +worse performance for better precision is a reasonable initial choice, and you +should benchmark your code if you suspect floating-point size is a problem in +your situation. + +Here’s an example that shows floating-point numbers in action: + +Filename: src/main.rs + +```rust +fn main() { + let x = 2.0; // f64 + + let y: f32 = 3.0; // f32 +} +``` + +Floating-point numbers are represented according to the IEEE-754 standard. The +`f32` type is a single-precision float, and `f64` has double precision. + +#### Numeric Operations + +Rust supports the usual basic mathematic operations you’d expect for all of the +number types: addition, subtraction, multiplication, division, and remainder. +The following code shows how you’d use each one in a `let` statement: + +Filename: src/main.rs + +```rust +fn main() { + // addition + let sum = 5 + 10; + + // subtraction + let difference = 95.5 - 4.3; + + // multiplication + let product = 4 * 30; + + // division + let quotient = 56.7 / 32.2; + + // remainder + let remainder = 43 % 5; +} +``` + +Each expression in these statements uses a mathematical operator and evaluates +to a single value, which is then bound to a variable. Appendix B contains a +list of all operators that Rust provides. + +#### The Boolean Type + +As in most other programming languages, a boolean type in Rust has two possible +values: `true` and `false`. The boolean type in Rust is specified using `bool`. +For example: + +Filename: src/main.rs + +```rust +fn main() { + let t = true; + + let f: bool = false; // with explicit type annotation +} +``` + +The main way to consume boolean values is through conditionals, such as an `if` +statement. We’ll cover how `if` statements work in Rust in the “Control Flow” +section. + +#### The Character Type + +So far we’ve only worked with numbers, but Rust supports letters too. Rust’s +`char` type is the language’s most primitive alphabetic type, and the following +code shows one way to use it: + +Filename: src/main.rs + +```rust +fn main() { + let c = 'z'; + let z = 'ℤ'; + let heart_eyed_cat = '😻'; +} +``` + +Rust’s `char` type represents a Unicode Scalar Value, which means it can +represent a lot more than just ASCII. Accented letters, Chinese/Japanese/Korean +ideographs, emoji, and zero width spaces are all valid `char` types in Rust. +Unicode Scalar Values range from `U+0000` to `U+D7FF` and `U+E000` to +`U+10FFFF` inclusive. However, a “character” isn’t really a concept in Unicode, +so your human intuition for what a “character” is may not match up with what a +`char` is in Rust. We’ll discuss this topic in detail in the “Strings” section +in Chapter 8. + +### Compound Types + +*Compound types* can group multiple values of other types into one type. Rust +has two primitive compound types: tuples and arrays. + +#### Grouping Values into Tuples + +A tuple is a general way of grouping together some number of other values with +a variety of types into one compound type. + +We create a tuple by writing a comma-separated list of values inside +parentheses. Each position in the tuple has a type, and the types of the +different values in the tuple don’t have to be the same. We’ve added optional +type annotations in this example: + +Filename: src/main.rs + +```rust +fn main() { + let tup: (i32, f64, u8) = (500, 6.4, 1); +} +``` + +The variable `tup` binds to the entire tuple, since a tuple is considered a +single compound element. To get the individual values out of a tuple, we can +use pattern matching to destructure a tuple value, like this: + +Filename: src/main.rs + +```rust +fn main() { + let tup = (500, 6.4, 1); + + let (x, y, z) = tup; + + println!("The value of y is: {}", y); +} +``` + +This program first creates a tuple and binds it to the variable `tup`. It then +uses a pattern with `let` to take `tup` and turn it into three separate +variables, `x`, `y`, and `z`. This is called *destructuring*, because it breaks +the single tuple into three parts. Finally, the program prints the value of +`y`, which is `6.4`. + +In addition to destructuring through pattern matching, we can also access a +tuple element directly by using a period (`.`) followed by the index of the +value we want to access. For example: + +Filename: src/main.rs + +```rust +fn main() { + let x: (i32, f64, u8) = (500, 6.4, 1); + + let five_hundred = x.0; + + let six_point_four = x.1; + + let one = x.2; +} +``` + +This program creates a tuple, `x`, and then makes new variables for each +element by using their index. As with most programming languages, the first +index in a tuple is 0. + +#### Arrays + +Another way to have a collection of multiple values is with an *array*. Unlike +a tuple, every element of an array must have the same type. Arrays in Rust are +different than arrays in some other languages because arrays in Rust have a +fixed length: once declared, they cannot grow or shrink in size. + +In Rust, the values going into an array are written as a comma-separated list +inside square brackets: + +Filename: src/main.rs + +```rust +fn main() { + let a = [1, 2, 3, 4, 5]; +} +``` + +Arrays are useful when you want your data allocated on the stack rather than +the heap (we will discuss the stack and the heap more in Chapter 4), or when +you want to ensure you always have a fixed number of elements. They aren’t as +flexible as the vector type, though. The vector type is a similar collection +type provided by the standard library that *is* allowed to grow or shrink in +size. If you’re unsure whether to use an array or a vector, you should probably +use a vector: Chapter 8 discusses vectors in more detail. + +An example of when you might want to use an array rather than a vector is in a +program that needs to know the names of the months of the year. It’s very +unlikely that such a program will need to add or remove months, so you can use +an array because you know it will always contain 12 items: + +```rust +let months = ["January", "February", "March", "April", "May", "June", "July", + "August", "September", "October", "November", "December"]; +``` + +##### Accessing Array Elements + +An array is a single chunk of memory allocated on the stack. We can access +elements of an array using indexing, like this: + +Filename: src/main.rs + +```rust +fn main() { + let a = [1, 2, 3, 4, 5]; + + let first = a[0]; + let second = a[1]; +} +``` + +In this example, the variable named `first` will get the value `1`, because +that is the value at index `[0]` in the array. The variable named `second` will +get the value `2` from index `[1]` in the array. + +##### Invalid Array Element Access + +What happens if we try to access an element of an array that is past the end of +the array? Say we change the example to the following: + +Filename: src/main.rs + +```rust,ignore +fn main() { + let a = [1, 2, 3, 4, 5]; + let index = 10; + + let element = a[index]; + + println!("The value of element is: {}", element); +} +``` + +Running this code using `cargo run` produces the following result: + +```bash +$ cargo run + Compiling arrays v0.1.0 (file:///projects/arrays) + Running `target/debug/arrays` +thread '
' panicked at 'index out of bounds: the len is 5 but the index is + 10', src/main.rs:6 +note: Run with `RUST_BACKTRACE=1` for a backtrace. +``` + +The compilation didn’t produce any errors, but the program results in a +*runtime* error and didn’t exit successfully. When you attempt to access an +element using indexing, Rust will check that the index you’ve specified is less +than the array length. If the index is greater than the length, Rust will +*panic*, which is the term Rust uses when a program exits with an error. + +This is the first example of Rust’s safety principles in action. In many +low-level languages, this kind of check is not done, and when you provide an +incorrect index, invalid memory can be accessed. Rust protects you against this +kind of error by immediately exiting instead of allowing the memory access and +continuing. Chapter 9 discusses more of Rust’s error handling. + +## How Functions Work + +Functions are pervasive in Rust code. You’ve already seen one of the most +important functions in the language: the `main` function, which is the entry +point of many programs. You’ve also seen the `fn` keyword, which allows you to +declare new functions. + +Rust code uses *snake case* as the conventional style for function and variable +names. In snake case, all letters are lowercase and underscores separate words. +Here’s a program that contains an example function definition: + +Filename: src/main.rs + +```rust +fn main() { + println!("Hello, world!"); + + another_function(); +} + +fn another_function() { + println!("Another function."); +} +``` + +Function definitions in Rust start with `fn` and have a set of parentheses +after the function name. The curly braces 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. Because `another_function` is defined in the program, it can be +called from inside the `main` function. Note that we defined `another_function` +*after* the `main` function in the source code; we could have defined it before +as well. Rust doesn’t care where you define your functions, only that they’re +defined somewhere. + +Let’s start a new binary project named *functions* to explore functions +further. Place the `another_function` example in *src/main.rs* and run it. You +should see the following output: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) + Running `target/debug/functions` +Hello, world! +Another function. +``` + +The lines execute in the order in which they appear in the `main` function. +First, the “Hello, world!” message prints, and then `another_function` is +called and its message is printed. + +### Function Parameters + +Functions can also be defined to have *parameters*, which are special variables +that are part of a function's signature. When a function has parameters, we can +provide it with concrete values for those parameters. Technically, the concrete +values are called *arguments*, but in casual conversation people tend to use +the words “parameter” and “argument” interchangeably for either the variables +in a function's definition or the concrete values passed in when you call a +function. + +The following rewritten version of `another_function` shows what parameters +look like in Rust: + +Filename: src/main.rs + +```rust +fn main() { + another_function(5); +} + +fn another_function(x: i32) { + println!("The value of x is: {}", x); +} +``` + +Try running this program; you should get the following output: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) + Running `target/debug/functions` +The value of x is: 5 +``` + +The declaration of `another_function` has one parameter named `x`. The type of +`x` is specified as `i32`. When `5` is passed to `another_function`, the +`println!` macro puts `5` where the pair of curly braces were in the format +string. + +In function signatures, you *must* declare the type of each parameter. This is +a deliberate decision in Rust’s design: requiring type annotations in function +definitions means the compiler almost never needs you to use them elsewhere in +the code to figure out what you mean. + +When you want a function to have multiple parameters, separate the parameter +declarations with commas, like this: + +Filename: src/main.rs + +```rust +fn main() { + another_function(5, 6); +} + +fn another_function(x: i32, y: i32) { + println!("The value of x is: {}", x); + println!("The value of y is: {}", y); +} +``` + +This example creates a function with two parameters, both of which are `i32` +types. The function then prints out the values in both of its parameters. Note +that function parameters don't all need to be the same type, they just happen +to be in this example. + +Let’s try running this code. Replace the program currently in your *function* +project’s *src/main.rs* file with the preceding example, and run it using +`cargo run`: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) + Running `target/debug/functions` +The value of x is: 5 +The value of y is: 6 +``` + +Because we called the function with `5` as the value for `x` and `6` is passed +as the value for `y`, the two strings are printed with these values. + +### Function Bodies + +Function bodies are made up of a series of statements optionally ending in an +expression. So far, we’ve only covered functions without an ending expression, +but we have seen expressions as parts of statements. Because Rust is an +expression-based language, this is an important distinction to understand. +Other languages don’t have the same distinctions, so let’s look at what +statements and expressions are and how their differences affect the bodies of +functions. + +### Statements and Expressions + +We’ve actually already used statements and expressions. *Statements* are +instructions that perform some action and do not return a value. *Expressions* +evaluate to a resulting value. Let’s look at some examples. + +Creating a variable and assigning a value to it with the `let` keyword is a +statement. In Listing 3-3, `let y = 6;` is a statement: + +Filename: src/main.rs + +```rust +fn main() { + let y = 6; +} +``` + + +Listing 3-3: A `main` function declaration containing one statement. + + +Function definitions are also statements; the entire preceding example is a +statement in itself. + +Statements do not return values. Therefore, you can’t assign a `let` statement +to another variable, as the following code tries to do: + +Filename: src/main.rs + +```rust,ignore +fn main() { + let x = (let y = 6); +} +``` + +When you run this program, you’ll get an error like this: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) +error: expected expression, found statement (`let`) + --> src/main.rs:2:14 + | +2 | let x = (let y = 6); + | ^^^ + | + = note: variable declaration using `let` is a statement +``` + +The `let y = 6` statement does not return a value, so there isn’t anything for +`x` to bind to. This is different than in other languages, such as C and Ruby, +where the assignment returns the value of the assignment. In those languages, +you can write `x = y = 6` and have both `x` and `y` have the value `6`; that is +not the case in Rust. + +Expressions evaluate to something and make up most of the rest of the code that +you’ll write in Rust. Consider a simple math operation, such as `5 + 6`, which +is an expression that evaluates to the value `11`. Expressions can be part of +statements: in Listing 3-3 that had the statement `let y = 6;`, `6` is an +expression that evaluates to the value `6`. Calling a function is an +expression. Calling a macro is an expression. The block that we use to create +new scopes, `{}`, is an expression, for example: + +Filename: src/main.rs + +```rust +fn main() { + let x = 5; + + let y = { + let x = 3; + x + 1 + }; + + println!("The value of y is: {}", y); +} +``` + +This expression: + +```rust,ignore +{ + let x = 3; + x + 1 +} +``` + +is a block that, in this case, evaluates to `4`. That value gets bound to `y` +as part of the `let` statement. Note the line without a semicolon at the end, +unlike most of the lines you’ve seen so far. Expressions do not include ending +semicolons. If you add a semicolon to the end of an expression, you turn it +into a statement, which will then not return a value. Keep this in mind as you +explore function return values and expressions next. + +### Functions with Return Values + +Functions can return values to the code that calls them. We don’t name return +values, but we do declare their type after an arrow (`->`). In Rust, the return +value of the function is synonymous with the value of the final expression in +the block of the body of a function. Here’s an example of a function that +returns a value: + +Filename: src/main.rs + +```rust +fn five() -> i32 { + 5 +} + +fn main() { + let x = five(); + + println!("The value of x is: {}", x); +} +``` + +There are no function calls, macros, or even `let` statements in the `five` +function—just the number `5` by itself. That’s a perfectly valid function in +Rust. Note that the function’s return type is specified, too, as `-> i32`. Try +running this code; the output should look like this: + +```bash +$ cargo run + Compiling functions v0.1.0 (file:///projects/functions) + Running `target/debug/functions` +The value of x is: 5 +``` + +The `5` in `five` is the function’s return value, which is why the return type +is `i32`. Let’s examine this in more detail. There are two important bits: +first, the line `let x = five();` shows that we’re using the return value of a +function to initialize a variable. Because the function `five` returns a `5`, +that line is the same as the following: + +```rust +let x = 5; +``` + +Second, the `five` function has no parameters and defines the type of the +return value, but the body of the function is a lonely `5` with no semicolon +because it’s an expression whose value we want to return. Let’s look at another +example: + +Filename: src/main.rs + +```rust +fn main() { + let x = plus_one(5); + + println!("The value of x is: {}", x); +} + +fn plus_one(x: i32) -> i32 { + x + 1 +} +``` + +Running this code will print `The value of x is: 6`. What happens if we place a +semicolon at the end of the line containing `x + 1`, changing it from an +expression to a statement? + +Filename: src/main.rs + +```rust,ignore +fn main() { + let x = plus_one(5); + + println!("The value of x is: {}", x); +} + +fn plus_one(x: i32) -> i32 { + x + 1; +} +``` + +Running this code produces an error, as follows: + +``` +error[E0308]: mismatched types + --> src/main.rs:7:28 + | +7 | fn plus_one(x: i32) -> i32 { + | ____________________________^ starting here... +8 | | x + 1; +9 | | } + | |_^ ...ending here: expected i32, found () + | + = note: expected type `i32` + found type `()` +help: consider removing this semicolon: + --> src/main.rs:8:10 + | +8 | x + 1; + | ^ +``` + +The main error message, “mismatched types,” reveals the core issue with this +code. The definition of the function `plus_one` says that it will return an +`i32`, but statements don’t evaluate to a value, which is expressed by `()`, +the empty tuple. Therefore, nothing is returned, which contradicts the function +definition and results in an error. In this output, Rust provides a message to +possibly help rectify this issue: it suggests removing the semicolon, which +would fix the error. + +## Comments + +All programmers strive to make their code easy to understand, but sometimes +extra explanation is warranted. In these cases, programmers leave notes, or +*comments*, in their source code that the compiler will ignore but people +reading the source code may find useful. + +Here’s a simple comment: + +```rust +// Hello, world. +``` + +In Rust, 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, like this: + +```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. +``` + +Comments can also be placed at the end of lines containing code: + +Filename: src/main.rs + +```rust +fn main() { + let lucky_number = 7; // I’m feeling lucky today. +} +``` + +But you’ll more often see them used in this format, with the comment on a +separate line above the code it's annotating: + +Filename: src/main.rs + +```rust +fn main() { + // I’m feeling lucky today. + let lucky_number = 7; +} +``` + +That’s all there is to comments. They’re not particularly complicated. + +## Control Flow + +Deciding whether or not to run some code depending on if a condition is true or +deciding to run some code repeatedly while a condition is true are basic +building blocks in most programming languages. The most common constructs that +let you control the flow of execution of Rust code are `if` expressions and +loops. + +### `if` Expressions + +An `if` expression allows us to branch our code depending on conditions. We +provide a condition and then state, “If this condition is met, run this block +of code. If the condition is not met, do not run this block of code.” + +Create a new project called *branches* in your *projects* directory to explore +the `if` expression. In the *src/main.rs* file, input the following: + +Filename: src/main.rs + +```rust +fn main() { + let number = 3; + + if number < 5 { + println!("condition was true"); + } else { + println!("condition was false"); + } +} +``` + +All `if` expressions start with the keyword `if`, which is followed by a +condition. In this case, the condition checks whether or not the variable +`number` has a value less than 5. The block of code we want to execute if the +condition is true is placed immediately after the condition inside curly +braces. Blocks of code associated with the conditions in `if` expressions are +sometimes called *arms*, just like the arms in `match` expressions that we +discussed in the “Comparing the Guess to the Secret Number” section of Chapter +2. Optionally, we can also include an `else` expression, which we chose to do +here, to give the program an alternative block of code to execute should the +condition evaluate to false. If you don’t provide an `else` expression and the +condition is false, the program will just skip the `if` block and move on to +the next bit of code. + +Try running this code; you should see the following output: + +```bash +$ cargo run + Compiling branches v0.1.0 (file:///projects/branches) + Running `target/debug/branches` +condition was true +``` + +Let’s try changing the value of `number` to a value that makes the condition +`false` to see what happens: + +```rust,ignore +let number = 7; +``` + +Run the program again, and look at the output: + +```bash +$ cargo run + Compiling branches v0.1.0 (file:///projects/branches) + Running `target/debug/branches` +condition was false +``` + +It’s also worth noting that the condition in this code *must* be a `bool`. To +see what happens if the condition isn’t a `bool`, try running the following +code: + +Filename: src/main.rs + +```rust,ignore +fn main() { + let number = 3; + + if number { + println!("number was three"); + } +} +``` + +The `if` condition evaluates to a value of `3` this time, and Rust throws an +error: + +``` +error[E0308]: mismatched types + --> src/main.rs:4:8 + | +4 | if number { + | ^^^^^^ expected bool, found integral variable + | + = note: expected type `bool` + found type `{integer}` +``` + +The error indicates that Rust expected a `bool` but got an integer. Rust will +not automatically try to convert non-boolean types to a boolean, unlike +languages such as Ruby and JavaScript. You must be explicit and always provide +`if` with a `boolean` as its condition. If we want the `if` code block to run +only when a number is not equal to `0`, for example, we can change the `if` +expression to the following: + +Filename: src/main.rs + +```rust +fn main() { + let number = 3; + + if number != 0 { + println!("number was something other than zero"); + } +} +``` + +Running this code will print `number was something other than zero`. + +#### Multiple Conditions with `else if` + +We can have multiple conditions by combining `if` and `else` in an `else if` +expression. For example: + +Filename: src/main.rs + +```rust +fn main() { + let number = 6; + + if number % 4 == 0 { + println!("number is divisible by 4"); + } else if number % 3 == 0 { + println!("number is divisible by 3"); + } else if number % 2 == 0 { + println!("number is divisible by 2"); + } else { + println!("number is not divisible by 4, 3, or 2"); + } +} +``` + +This program has four possible paths it can take. After running it, you should +see the following output: + +```bash +$ cargo run + Compiling branches v0.1.0 (file:///projects/branches) + Running `target/debug/branches` +number is divisible by 3 +``` + +When this program executes, it checks each `if` expression in turn and executes +the first body for which the condition holds true. Note that even though 6 is +divisible by 2, we don’t see the output `number is divisible by 2`, nor do we +see the `number is not divisible by 4, 3, or 2` text from the `else` block. The +reason is that Rust will only execute the block for the first true condition, +and once it finds one, it won’t even check the rest. + +Using too many `else if` expressions can clutter your code, so if you have more +than one, you might want to refactor your code. Chapter 6 describes a powerful +Rust branching construct called `match` for these cases. + +#### Using `if` in a `let` statement + +Because `if` is an expression, we can use it on the right side of a `let` +statement, for instance in Listing 3-4: + +Filename: src/main.rs + +```rust +fn main() { + let condition = true; + let number = if condition { + 5 + } else { + 6 + }; + + println!("The value of number is: {}", number); +} +``` + + +Listing 3-4: Assigning the result of an `if` expression to a variable + + +The `number` variable will be bound to a value based on the outcome of the `if` +expression. Run this code to see what happens: + +```bash +$ cargo run + Compiling branches v0.1.0 (file:///projects/branches) + Running `target/debug/branches` +The value of number is: 5 +``` + +Remember that blocks of code evaluate to the last expression in them, and +numbers by themselves are also expressions. In this case, the value of the +whole `if` expression depends on which block of code executes. This means the +values that have the potential to be results from each arm of the `if` must be +the same type; in Listing 3-4, the results of both the `if` arm and the `else` +arm were `i32` integers. But what happens if the types are mismatched, as in +the following example? + +Filename: src/main.rs + +```rust,ignore +fn main() { + let condition = true; + + let number = if condition { + 5 + } else { + "six" + }; + + println!("The value of number is: {}", number); +} +``` + +When we try to run this code, we’ll get an error. The `if` and `else` arms have +value types that are incompatible, and Rust indicates exactly where to find the +problem in the program: + +``` +error[E0308]: if and else have incompatible types + --> src/main.rs:4:18 + | +4 | let number = if condition { + | __________________^ starting here... +5 | | 5 +6 | | } else { +7 | | "six" +8 | | }; + | |_____^ ...ending here: expected integral variable, found reference + | + = note: expected type `{integer}` + found type `&'static str` +``` + +The expression in the `if` block evaluates to an integer, and the expression in +the `else` block evaluates to a string. This won’t work because variables must +have a single type. Rust needs to know at compile time what type the `number` +variable is, definitively, so it can verify at compile time that its type is +valid everywhere we use `number`. Rust wouldn’t be able to do that if the type +of `number` was only determined at runtime; the compiler would be more complex +and would make fewer guarantees about the code if it had to keep track of +multiple hypothetical types for any variable. + +### Repetition with Loops + +It’s often useful to execute a block of code more than once. For this task, +Rust provides several *loops*. A loop runs through the code inside the loop +body to the end and then starts immediately back at the beginning. To +experiment with loops, let’s make a new project called *loops*. + +Rust has three kinds of loops: `loop`, `while`, and `for`. Let’s try each one. + +#### Repeating Code with `loop` + +The `loop` keyword tells Rust to execute a block of code over and over again +forever or until you explicitly tell it to stop. + +As an example, change the *src/main.rs* file in your *loops* directory to look +like this: + +Filename: src/main.rs + +```rust,ignore +fn main() { + loop { + println!("again!"); + } +} +``` + +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 continual loop. Give it a try: + +```bash +$ cargo run + Compiling loops v0.1.0 (file:///projects/loops) + Running `target/debug/loops` +again! +again! +again! +again! +^Cagain! +``` + +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. + +Fortunately, Rust provides another, more reliable way to break out of a loop. +You can place the `break` keyword within the loop to tell the program when to +stop executing the loop. Recall that we did this in the guessing game in the +“Quitting After a Correct Guess” section of Chapter 2 to exit the +program when the user won the game by guessing the correct number. + +#### Conditional Loops with `while` + +It’s often useful for a program to evaluate a condition within a loop. While +the condition is true, the loop runs. When the condition ceases to be true, you +call `break`, stopping the loop. This loop type could be implemented using a +combination of `loop`, `if`, `else`, and `break`; you could try that now in a +program, if you’d like. + +However, this pattern is so common that Rust has a built-in language construct +for it, and it’s called a `while` loop. The following example uses `while`: the +program loops three times, counting down each time. Then, after the loop, it +prints another message and exits: + +Filename: src/main.rs + +```rust +fn main() { + let mut number = 3; + + while number != 0 { + println!("{}!", number); + + number = number - 1; + } + + println!("LIFTOFF!!!"); +} +``` + +This construct eliminates a lot of nesting that would be necessary if you used +`loop`, `if`, `else`, and `break`, and it’s clearer. While a condition holds +true, the code runs; otherwise, it exits the loop. + +#### Looping Through a Collection with `for` + +You could use the `while` construct to loop over the elements of a collection, +such as an array. For example: + +Filename: src/main.rs + +```rust +fn main() { + let a = [10, 20, 30, 40, 50]; + let mut index = 0; + + while index < 5 { + println!("the value is: {}", a[index]); + + index = index + 1; + } +} +``` + + +Listing 3-5: Looping through each element of a collection using a `while` loop + + +Here, the code counts up through the elements in the array. It starts at index +`0`, and then loops until it reaches the final index in the array (that is, +when `index < 5` is no longer true). Running this code will print out every +element in the array: + +```bash +$ cargo run + Compiling loops v0.1.0 (file:///projects/loops) + Running `target/debug/loops` +the value is: 10 +the value is: 20 +the value is: 30 +the value is: 40 +the value is: 50 +``` + +All five array values appear in the terminal, as expected. Even though `index` +will reach a value of `5` at some point, the loop stops executing before trying +to fetch a sixth value from the array. + +But this approach is error prone; we could cause the program to panic if the +index length is incorrect. It’s also slow, because the compiler adds runtime +code to perform the conditional check on every element on every iteration +through the loop. + +As a more efficient alternative, you can use a `for` loop and execute some code +for each item in a collection. A `for` loop looks like this: + +Filename: src/main.rs + +```rust +fn main() { + let a = [10, 20, 30, 40, 50]; + + for element in a.iter() { + println!("the value is: {}", element); + } +} +``` + + +Listing 3-6: Looping through each element of a collection using a `for` loop + + +When we run this code, we’ll see the same output as in Listing 3-5. More +importantly, we’ve now increased the safety of the code and eliminated the +chance of bugs that might result from going beyond the end of the array or not +going far enough and missing some items. + +For example, in the code in Listing 3-5, if you removed an item from the `a` +array but forgot to update the condition to `while index < 4`, the code would +panic. Using the `for` loop, you don’t need to remember to change any other +code if you changed the number of values in the array. + +The safety and conciseness of `for` loops make them the most commonly used loop +construct in Rust. Even in situations in which you want to run some code a +certain number of times, as in the countdown example that used a `while` loop +in Listing 3-5, most Rustaceans would use a `for` loop. The way to do that +would be to use a `Range`, which is a type provided by the standard library +that generates all numbers in sequence starting from one number and ending +before another number. + +Here’s what the countdown would look like using a `for` loop and another method +we’ve not yet talked about, `rev`, to reverse the range: + +Filename: src/main.rs + +```rust +fn main() { + for number in (1..4).rev() { + println!("{}!", number); + } + println!("LIFTOFF!!!"); +} +``` + +This code is a bit nicer, isn’t it? + +## Summary + +You made it! That was a sizable chapter: you learned about variables, scalar +and`if` expressions, and loops! If you want to practice with the concepts +discussed in this chapter, try building programs to do the following: + +* Convert temperatures between Fahrenheit and Celsius. +* Generate the nth Fibonacci number. +* Print the lyrics to the Christmas carol “The Twelve Days of Christmas,” +taking advantage of the repetition in the song. + +When you’re ready to move on, we’ll talk about a concept in Rust that *doesn’t* +commonly exist in other programming languages: ownership. diff --git a/src/doc/book/second-edition/nostarch/chapter04.md b/src/doc/book/second-edition/nostarch/chapter04.md new file mode 100644 index 0000000000..aa92aa7b7d --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter04.md @@ -0,0 +1,1244 @@ + +[TOC] + +# Understanding Ownership + +Ownership is Rust’s most unique feature, and it enables Rust to make memory +safety guarantees without needing a garbage collector. Therefore, it’s +important to understand how ownership works in Rust. In this chapter we’ll talk +about ownership as well as several related features: borrowing, slices, and how +Rust lays data out in memory. + +## What Is Ownership? + +Rust’s central feature is *ownership*. Although the feature is straightforward +to explain, it has deep implications for the rest of the language. + +All programs have to manage the way they use a computer’s memory while running. +Some languages have garbage collection that constantly looks for no longer used +memory as the program runs; in other languages, the programmer must explicitly +allocate and free the memory. Rust uses a third approach: memory is managed +through a system of ownership with a set of rules that the compiler checks at +compile time. No run-time costs are incurred for any of the ownership features. + +Because ownership is a new concept for many programmers, it does take some time +to get used to. The good news is that the more experienced you become with Rust +and the rules of the ownership system, the more you’ll be able to naturally +develop code that is safe and efficient. Keep at it! + +When you understand ownership, you’ll have a solid foundation for understanding +the features that make Rust unique. In this chapter, you’ll learn ownership by +working through some examples that focus on a very common data structure: +strings. + +PROD: START BOX + +### The Stack and the Heap + +In many programming languages, we don’t have to think about the stack and the +heap very often. But in a systems programming language like Rust, whether a +value is on the stack or the heap has more of an effect on how the language +behaves and why we have to make certain decisions. We’ll describe parts of +ownership in relation to the stack and the heap later in this chapter, so here +is a brief explanation in preparation. + +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. +This is referred to as *last in, first out*. Think of a stack of plates: when +you add more plates, you put them on top of the pile, and when you need a +plate, you take one off the top. Adding or removing plates from the middle or +bottom wouldn’t work as well! Adding data is called *pushing onto the stack*, +and removing data is called *popping off the stack*. + +The stack is fast because of the way it accesses the data: it never has to +search for a place to put new data or a place to get data from because that +place is always the top. Another property that makes the stack fast is that 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. The heap is less organized: when we put +data on the heap, we ask for some amount of space. The operating system finds +an empty spot somewhere in the heap that is big enough, marks it as being in +use, and returns to us a pointer to that location. This process is called +*allocating on the heap*, and sometimes we abbreviate the phrase as just +“allocating.” Pushing values onto the stack is not considered allocating. +Because the pointer is a known, fixed size, we can store the pointer on the +stack, but when we want the actual data, we have to follow the pointer. + +Think of being seated at a restaurant. When you enter, you state the number of +people in your group, and the staff finds an empty table that fits everyone and +leads you there. If someone in your group comes late, they can ask where you’ve +been seated to find you. + +Accessing data in the heap is slower than accessing data on the stack because +we have to follow a pointer to get there. Contemporary processors are faster if +they jump around less in memory. Continuing the analogy, consider a server at a +restaurant taking orders from many tables. It’s most efficient to get all the +orders at one table before moving on to the next table. Taking an order from +table A, then an order from table B, then one from A again, and then one from B +again would be a much slower process. By the same token, a processor can do its +job better if it works on data that’s close to other data (as it is on the +stack) rather than farther away (as it can be on the heap). Allocating a large +amount of space on the heap can also take time. + +When our code calls a function, the values passed into the function (including, +potentially, pointers to data on the heap) and the function’s local variables +get pushed onto the stack. When the function is over, those values get popped +off the stack. + +Keeping track of what parts of code are using what data on the heap, minimizing +the amount of duplicate data on the heap, and cleaning up unused data on the +heap so we don’t run out of space are all problems that ownership addresses. +Once you understand ownership, you won’t need to think about the stack and the +heap very often, but knowing that managing heap data is why ownership exists +can help explain why it works the way it does. + +PROD: END BOX + +### Ownership Rules + +First, let’s take a look at the ownership rules. Keep these rules in mind as we +work through the examples that illustrate the rules: + +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. + +### Variable Scope + +We’ve walked through an example of a Rust program already in Chapter 2. Now +that we’re past basic syntax, we won’t include all the `fn main() {` code in +examples, so if you’re following along, you’ll have to put the following +examples inside a `main` function manually. As a result, our examples will be a +bit more concise, letting us focus on the actual details rather than +boilerplate code. + +As a first example of ownership, we’ll look at the *scope* of some variables. A +scope is the range within a program for which an item is valid. Let’s say we +have a variable that looks like this: + +```rust +let s = "hello"; +``` + +The variable `s` refers to a string literal, where the value of the string is +hardcoded into the text of our program. The variable is valid from the point at +which it’s declared until the end of the current *scope*. Listing 4-1 has +comments annotating where the variable `s` is valid: + +```rust +{ // s is not valid here, it’s not yet declared + let s = "hello"; // s is valid from this point forward + + // do stuff with s +} // this scope is now over, and s is no longer valid +``` + + +Listing 4-1: A variable and the scope in which it is valid + + +In other words, there are two important points in time here: + +1. When `s` comes *into scope*, it is valid. +1. It remains so until it goes *out of scope*. + +At this point, the relationship between scopes and when variables are valid is +similar to other programming languages. Now we’ll build on top of this +understanding by introducing the `String` type. + +### The `String` Type + +To illustrate the rules of ownership, we need a data type that is more complex +than the ones we covered in Chapter 3. All the data types we’ve looked at +previously are stored on the stack and popped off the stack when their scope is +over, but we want to look at data that is stored on the heap and explore how +Rust knows when to clean up that data. + +We’ll use `String` as the example here and concentrate on the parts of `String` +that relate to ownership. These aspects also apply to other complex data types +provided by the standard library and that you create. We’ll discuss `String` in +more depth in Chapter 8. + +We’ve already seen string literals, where a string value is hardcoded into our +program. String literals are convenient, but they aren’t always suitable for +every situation in which you want to use text. One reason is that they’re +immutable. Another is that not every string value can be known when we write +our code: for example, what if we want to take user input and store it? For +these situations, Rust has a second string type, `String`. This type 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, like so: + +```rust +let s = String::from("hello"); +``` + +The double colon (`::`) is an operator that allows us to namespace this +particular `from` function under the `String` type rather than using some sort +of name like `string_from`. We’ll discuss this syntax more in the “Method +Syntax” section of Chapter 5 and when we talk about namespacing with modules in +Chapter 7. + +This kind of string *can* be mutated: + +```rust +let mut s = String::from("hello"); + +s.push_str(", world!"); // push_str() appends a literal to a String + +println!("{}", s); // This will print `hello, world!` +``` + +So, what’s the difference here? Why can `String` be mutated but literals +cannot? The difference is how these two types deal with memory. + +### Memory and Allocation + +In the case of a string literal, we know the contents at compile time so the +text is hardcoded directly into the final executable, making string literals +fast and efficient. But these properties only come from its immutability. +Unfortunately, we can’t put a blob of memory into the binary for each piece of +text whose size is unknown at compile time and whose size might change while +running the program. + +With the `String` type, in order to support a mutable, growable piece of text, +we need to allocate an amount of memory on the heap, unknown at compile time, +to hold the contents. This means: + +1. The memory must be requested from the operating system at runtime. +2. We need a way of returning this memory to the operating system when we’re +done with our `String`. + +That first part is done by us: when we call `String::from`, its implementation +requests the memory it needs. This is pretty much universal in programming +languages. + +However, the second part is different. In languages with a *garbage collector +(GC)*, the GC keeps track and cleans up memory that isn’t being used anymore, +and we, as the programmer, don’t need to think about it. Without a GC, it’s the +programmer’s responsibility to identify when memory is no longer being used and +call code to explicitly return it, just as we did to request it. Doing this +correctly has historically been a difficult programming problem. If we forget, +we’ll waste memory. If we do it too early, we’ll have an invalid variable. If +we do it twice, that’s a bug too. We need to pair exactly one `allocate` with +exactly one `free`. + +Rust takes a different path: the memory is automatically returned once the +variable that owns it goes out of scope. Here’s a version of our scope example +from Listing 4-1 using a `String` instead of a string literal: + +```rust +{ + let s = String::from("hello"); // s is valid from this point forward + + // do stuff with s +} // this scope is now over, and s is no + // longer valid +``` + +There is a natural point at which we can return the memory our `String` needs +to the operating system: when `s` goes out of scope. When a variable goes out +of scope, Rust calls a special function for us. This function is called `drop`, +and it’s where the author of `String` can put the code to return the memory. +Rust calls `drop` automatically at the closing `}`. + +> Note: In C++, this pattern of deallocating resources at the end of an item's +lifetime is sometimes called *Resource Acquisition Is Initialization (RAII)*. +The `drop` function in Rust will be familiar to you if you’ve used RAII +patterns. + +This pattern has a profound impact on the way Rust code is written. It may seem +simple right now, but the behavior of code can be unexpected in more +complicated situations when we want to have multiple variables use the data +we’ve allocated on the heap. Let’s explore some of those situations now. + +#### Ways Variables and Data Interact: Move + +Multiple variables can interact with the same data in different ways in Rust. +Let’s look at an example using an integer in Listing 4-2: + +```rust +let x = 5; +let y = x; +``` + + +Listing 4-2: Assigning the integer value of variable `x` to `y` + + +We can probably guess what this is doing based on our experience with other +languages: “Bind the value `5` to `x`; then make a copy of the value in `x` and +bind it to `y`.” We now have two variables, `x` and `y`, and both equal `5`. +This is indeed what is happening because integers are simple values with a +known, fixed size, and these two `5` values are pushed onto the stack. + +Now let’s look at the `String` version: + +```rust +let s1 = String::from("hello"); +let s2 = s1; +``` + +This looks very similar to the previous code, so we might assume that the way +it works would be the same: that is, the second line would make a copy of the +value in `s1` and bind it to `s2`. But this isn’t quite what happens. + +To explain this more thoroughly, let’s look at what `String` looks like under +the covers in Figure 4-3. A `String` is made up of three parts, shown on the +left: a pointer to the memory that holds the contents of the string, a length, +and a capacity. This group of data is stored on the stack. On the right is the +memory on the heap that holds the contents. + +String in memory + + +Figure 4-3: Representation in memory of a `String` holding the value `"hello"` +bound to `s1` + + +The length is how much memory, in bytes, the contents of the `String` is +currently using. The capacity is the total amount of memory, in bytes, that the +`String` has received from the operating system. The difference between length +and capacity matters, but not in this context, so for now, it’s fine to ignore +the capacity. + +When we assign `s1` to `s2`, the `String` data is copied, meaning we copy the +pointer, the length, and the capacity that are on the stack. We do not copy the +data on the heap that the pointer refers to. In other words, the data +representation in memory looks like Figure 4-4. + +s1 and s2 pointing to the same value + + +Figure 4-4: Representation in memory of the variable `s2` that has a copy of +the pointer, length, and capacity of `s1` + + +The representation does *not* look like Figure 4-5, which is what memory would +look like if Rust instead copied the heap data as well. If Rust did this, the +operation `s2 = s1` could potentially be very expensive in terms of runtime +performance if the data on the heap was large. + +s1 and s2 to two places + + +Figure 4-5: Another possibility of what `s2 = s1` might do if Rust copied the +heap data as well + + +Earlier, we said that when a variable goes out of scope, Rust automatically +calls the `drop` function and cleans up the heap memory for that variable. But +Figure 4-4 shows both data pointers pointing to the same location. This is a +problem: when `s2` and `s1` go out of scope, they will both try to free the +same memory. This is known as a *double free* error and is one of the memory +safety bugs we mentioned previously. Freeing memory twice can lead to memory +corruption, which can potentially lead to security vulnerabilities. + +To ensure memory safety, there’s one more detail to what happens in this +situation in Rust. Instead of trying to copy the allocated memory, Rust +considers `s1` to no longer be valid and therefore, Rust doesn’t need to free +anything when `s1` goes out of scope. Check out what happens when you try to +use `s1` after `s2` is created: + +```rust,ignore +let s1 = String::from("hello"); +let s2 = s1; + +println!("{}", s1); +``` + +You’ll get an error like this because Rust prevents you from using the +invalidated reference: + +```text +5:22 error: use of moved value: `s1` [E0382] +println!("{}", s1); + ^~ +5:24 note: in this expansion of println! (defined in ) +3:11 note: `s1` moved here because it has type `collections::string::String`, +which is moved by default + let s2 = s1; + ^~ +``` + +If you’ve heard the terms “shallow copy” and “deep copy” while working with +other languages, the concept of copying the pointer, length, and capacity +without copying the data probably sounds like a shallow copy. But because Rust +also invalidates the first variable, instead of calling this a shallow copy, +it’s known as a *move*. Here we would read this by saying that `s1` was *moved* +into `s2`. So what actually happens is shown in Figure 4-6. + +s1 moved to s2 + + +Figure 4-6: Representation in memory after `s1` has been invalidated + + +That solves our problem! With only `s2` valid, when it goes out of scope, it +alone will free the memory, and we’re done. + +In addition, there’s a design choice that’s implied by this: Rust will never +automatically create “deep” copies of your data. Therefore, any *automatic* +copying can be assumed to be inexpensive in terms of runtime performance. + +#### Ways Variables and Data Interact: Clone + +If we *do* want to deeply copy the heap data of the `String`, not just the +stack data, we can use a common method called `clone`. We’ll discuss method +syntax in Chapter 5, but because methods are a common feature in many +programming languages, you’ve probably seen them before. + +Here’s an example of the `clone` method in action: + +```rust +let s1 = String::from("hello"); +let s2 = s1.clone(); + +println!("s1 = {}, s2 = {}", s1, s2); +``` + +This works just fine and is how you can explicitly produce the behavior shown +in Figure 4-4, where the heap data *does* get copied. + +When you see a call to `clone`, you know that some arbitrary code is being +executed and that code may be expensive. It’s a visual indicator that something +different is going on. + +#### Stack-Only Data: Copy + +There’s another wrinkle we haven’t talked about yet. This code using integers, +part of which was shown earlier in Listing 4-2, works and is valid: + +```rust +let x = 5; +let y = x; + +println!("x = {}, y = {}", x, y); +``` + +But this code seems to contradict what we just learned: we don’t have a call to +`clone`, but `x` is still valid and wasn’t moved into `y`. + +The reason is that types like integers that have a known size at compile time +are stored entirely on the stack, so copies of the actual values are quick to +make. That means there’s no reason we would want to prevent `x` from being +valid after we create the variable `y`. In other words, there’s no difference +between deep and shallow copying here, so calling `clone` wouldn’t do anything +differently from the usual shallow copying and we can leave it out. + +Rust has a special annotation called the `Copy` trait that we can place on +types like integers that are stored on the stack (we’ll talk more about traits +in Chapter 10). If a type has the `Copy` trait, an older variable is still +usable after assignment. Rust won’t let us annotate a type with the `Copy` +trait if the type, or any of its parts, has implemented the `D``rop` trait. If +the type needs something special to happen when the value goes out of scope and +we add the `Copy` annotation to that type, we’ll get a compile time error. + +So what types are `Copy`? You can check the documentation for the given type to +be sure, but as a general rule, any group of simple scalar values can be +`Copy`, and nothing that requires allocation or is some form of resource is +`Copy`. Here are some of the types that are `Copy`: + +* All the integer types, like `u32`. +* The boolean type, `bool`, with values `true` and `false`. +* All the floating point types, like `f64`. +* Tuples, but only if they contain types that are also `Copy`. `(i32, i32)` is +`Copy`, but `(i32, String)` is not. + +### Ownership and Functions + +The semantics for passing a value to a function are similar to assigning a +value to a variable. Passing a variable to a function will move or copy, just +like assignment. Listing 4-7 has an example with some annotations showing where +variables go into and out of scope: + +Filename: src/main.rs + +```rust +fn main() { + let s = String::from("hello"); // s comes into scope. + + takes_ownership(s); // s's value moves into the function... + // ... and so is no longer valid here. + let x = 5; // x comes into scope. + + makes_copy(x); // x would move into the function, + // but i32 is Copy, so it’s okay to still + // use x afterward. + +} // Here, x goes out of scope, then s. But since s's value was moved, nothing + // special happens. + +fn takes_ownership(some_string: String) { // some_string comes into scope. + println!("{}", some_string); +} // Here, some_string goes out of scope and `drop` is called. The backing + // memory is freed. + +fn makes_copy(some_integer: i32) { // some_integer comes into scope. + println!("{}", some_integer); +} // Here, some_integer goes out of scope. Nothing special happens. +``` + + +Listing 4-7: Functions with ownership and scope annotated + + +If we tried to use `s` after the call to `takes_ownership`, Rust would throw a +compile time error. These static checks protect us from mistakes. Try adding +code to `main` that uses `s` and `x` to see where you can use them and where +the ownership rules prevent you from doing so. + +### Return Values and Scope + +Returning values can also transfer ownership. Here’s an example with similar +annotations to those in Listing 4-7: + +Filename: src/main.rs + +```rust +fn main() { + let s1 = gives_ownership(); // gives_ownership moves its return + // value into s1. + + let s2 = String::from("hello"); // s2 comes into scope. + + let s3 = takes_and_gives_back(s2); // s2 is moved into + // takes_and_gives_back, which also + // moves its return value into s3. +} // Here, s3 goes out of scope and is dropped. s2 goes out of scope but was + // moved, so nothing happens. s1 goes out of scope and is dropped. + +fn gives_ownership() -> String { // gives_ownership will move its + // return value into the function + // that calls it. + + let some_string = String::from("hello"); // some_string comes into scope. + + some_string // some_string is returned and + // moves out to the calling + // function. +} + +// takes_and_gives_back will take a String and return one. +fn takes_and_gives_back(a_string: String) -> String { // a_string comes into +scope. + + a_string // a_string is returned and moves out to the calling function. +} +``` + +The ownership of variables follows the same pattern every time: assigning a +value to another variable moves it, and when heap data values’ variables go out +of scope, if the data hasn’t been moved to be owned by another variable, the +value will be cleaned up by `drop`. + +Taking ownership and then returning ownership with every function is a bit +tedious. What if we want to let a function use a value but not take ownership? +It’s quite annoying that anything we pass in also needs to be passed back if we +want to use it again, in addition to any data resulting from the body of the +function that we might want to return as well. + +It’s possible to return multiple values using a tuple, like this: + +Filename: src/main.rs + +```rust +fn main() { + let s1 = String::from("hello"); + + let (s2, len) = calculate_length(s1); + + println!("The length of '{}' is {}.", s2, len); +} + +fn calculate_length(s: String) -> (String, usize) { + let length = s.len(); // len() returns the length of a String. + + (s, length) +} +``` + +But this is too much ceremony and a lot of work for a concept that should be +common. Luckily for us, Rust has a feature for this concept, and it’s called +*references*. + +## References and Borrowing + +The issue with the tuple code at the end of the preceding section is that we +have to return the `String` to the calling function so we can still use the +`String` after the call to `calculate_length`, because the `String` was moved +into `calculate_length`. + +Here is how you would define and use a `calculate_length` function that takes a +*reference* to an object as an argument instead of taking ownership of the +argument: + +Filename: src/main.rs + +```rust +fn main() { + let s1 = String::from("hello"); + + let len = calculate_length(&s1); + + println!("The length of '{}' is {}.", s1, len); +} + +fn calculate_length(s: &String) -> usize { + s.len() +} +``` + +First, notice that all the tuple code in the variable declaration and the +function return value is gone. Second, note that we pass `&s1` into +`calculate_length`, and in its definition, we take `&String` rather than +`String`. + +These ampersands are *references*, and they allow you to refer to some value +without taking ownership of it. Figure 4-8 shows a diagram. + +&String s pointing at String s1 + + +Figure 4-8: `&String s` pointing at `String s1` + + +Let’s take a closer look at the function call here: + +```rust +let s1 = String::from("hello"); + +let len = calculate_length(&s1); +``` + +The `&s1` syntax lets us create a reference that *refers* to the value of `s1` +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. + +Likewise, the signature of the function uses `&` to indicate that it takes a +reference as an argument. Let’s add some explanatory annotations: + +```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. +``` + +The scope in which the variable `s` is valid is the same as any function +argument's scope, but we don’t drop what the reference points to when it goes +out of scope because we don’t have ownership. Functions that take references as +arguments instead of the actual values mean we won’t need to return the values +in order to give back ownership, since we never had ownership. + +We call taking references as function arguments *borrowing*. As in real life, +if a person owns something, you can borrow it from them. When you’re done, you +have to give it back. + +So what happens if we try to modify something we’re borrowing? Try the code in +Listing 4-9. Spoiler alert: it doesn’t work! + +Filename: src/main.rs + +```rust,ignore +fn main() { + let s = String::from("hello"); + + change(&s); +} + +fn change(some_string: &String) { + some_string.push_str(", world"); +} +``` + + +Listing 4-9: Attempting to modify a borrowed value + + +Here’s the error: + +```text +error: cannot borrow immutable borrowed content `*some_string` as mutable + --> error.rs:8:5 + | +8 | some_string.push_str(", world"); + | ^^^^^^^^^^^ +``` + +Just as variables are immutable by default, so are references. We’re not +allowed to modify something we have a reference to. + +### Mutable References + +We can fix the error in the code from Listing 4-9 with just a small tweak: + +Filename: src/main.rs + +```rust +fn main() { + let mut s = String::from("hello"); + + change(&mut s); +} + +fn change(some_string: &mut String) { + some_string.push_str(", world"); +} +``` + +First, we had to change `s` to be `mut`. Then we had to create a mutable +reference with `&mut s` and accept a mutable reference with `some_string: &mut +String`. + +But mutable references have one big restriction: you can only have one mutable +reference to a particular piece of data in a particular scope. This code will +fail: + +Filename: src/main.rs + +```rust,ignore +let mut s = String::from("hello"); + +let r1 = &mut s; +let r2 = &mut s; +``` + +Here’s the error: + +```text +error[E0499]: cannot borrow `s` as mutable more than once at a time + --> borrow_twice.rs:5:19 + | +4 | let r1 = &mut s; + | - first mutable borrow occurs here +5 | let r2 = &mut s; + | ^ second mutable borrow occurs here +6 | } + | - first borrow ends here +``` + +This restriction allows for mutation but in a very controlled fashion. It’s +something that new Rustaceans struggle with, because most languages let you +mutate whenever you’d like. The benefit of having this restriction is that Rust +can prevent data races at compile time. + +A *data race* is a particular type of race condition in which these three +behaviors occur: + +1. Two or more pointers access the same data at the same time. +1. At least one of the pointers is being used to write to the data. +1. There’s no mechanism being used to synchronize access to the data. + +Data races cause undefined behavior and can be difficult to diagnose and fix +when you’re trying to track them down at runtime; Rust prevents this problem +from happening because it won’t even compile code with data races! + +As always, we can use curly brackets to create a new scope, allowing for +multiple mutable references, just not *simultaneous* ones: + +```rust +let mut s = String::from("hello"); + +{ + let r1 = &mut s; + +} // r1 goes out of scope here, so we can make a new reference with no problems. + +let r2 = &mut s; +``` + +A similar rule exists for combining mutable and immutable references. This code +results in an error: + +```rust,ignore +let mut s = String::from("hello"); + +let r1 = &s; // no problem +let r2 = &s; // no problem +let r3 = &mut s; // BIG PROBLEM +``` + +Here’s the error: + +```text +error[E0502]: cannot borrow `s` as mutable because it is also borrowed as +immutable + --> borrow_thrice.rs:6:19 + | +4 | let r1 = &s; // no problem + | - immutable borrow occurs here +5 | let r2 = &s; // no problem +6 | let r3 = &mut s; // BIG PROBLEM + | ^ mutable borrow occurs here +7 | } + | - immutable borrow ends here +``` + +Whew! We *also* cannot have a mutable reference while we have an immutable one. +Users of an immutable reference don’t expect the values to suddenly change out +from under them! However, multiple immutable references are okay because no one +who is just reading the data has the ability to affect anyone else’s reading of +the data. + +Even though these errors may be frustrating at times, remember that it’s the +Rust compiler pointing out a potential bug early (at compile time rather than +at runtime) and showing you exactly where the problem is instead of you having +to track down why sometimes your data isn’t what you thought it should be. + +### Dangling References + +In languages with pointers, it’s easy to erroneously create a *dangling +pointer*, a pointer that references a location in memory that may have been +given to someone else, by freeing some memory while preserving a pointer to +that memory. In Rust, by contrast, the compiler guarantees that references will +never be dangling references: if we have a reference to some data, the compiler +will ensure that the data will not go out of scope before the reference to the +data does. + +Let’s try to create a dangling reference: + +Filename: src/main.rs + +```rust,ignore +fn main() { + let reference_to_nothing = dangle(); +} + +fn dangle() -> &String { + let s = String::from("hello"); + + &s +} +``` + +Here’s the error: + +```text +error[E0106]: missing lifetime specifier + --> dangle.rs:5:16 + | +5 | fn dangle() -> &String { + | ^^^^^^^ + | + = help: this function's return type contains a borrowed value, but there is no + value for it to be borrowed from + = help: consider giving it a 'static lifetime + +error: aborting due to previous error +``` + +This error message refers to a feature we haven’t covered yet: *lifetimes*. +We’ll discuss lifetimes in detail in Chapter 10. But, if you disregard the +parts about lifetimes, the message does contain the key to why this code is a +problem: + +``` +this function's return type contains a borrowed value, but there is no value +for it to be borrowed from. +``` + +Let’s take a closer look at exactly what’s happening at each stage of our +`dangle` code: + +```rust,ignore +fn dangle() -> &String { // dangle returns a reference to a String + + let s = String::from("hello"); // s is a new String + + &s // we return a reference to the String, s +} // Here, s goes out of scope, and is dropped. Its memory goes away. + // Danger! +``` + +Because `s` is created inside `dangle`, when the code of `dangle` is finished, +`s` will be deallocated. But we tried to return a reference to it. That means +this reference would be pointing to an invalid `String`! That’s no good. Rust +won’t let us do this. + +The correct code here is to return the `String` directly: + +```rust +fn no_dangle() -> String { + let s = String::from("hello"); + + s +} +``` + +This works without any problems. Ownership is moved out, and nothing is +deallocated. + +### The Rules of References + +Let’s recap what we’ve discussed about references: + +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. + +Next, we’ll look at a different kind of reference: slices. + +## Slices + +Another data type that does not have ownership is the *slice*. Slices let you +reference a contiguous sequence of elements in a collection rather than the +whole collection. + +Here’s a small programming problem: write a function that takes a string and +returns the first word it finds in that string. If the function doesn’t find a +space in the string, it means the whole string is one word, so the entire +string should be returned. + +Let’s think about the signature of this function: + +```rust,ignore +fn first_word(s: &String) -> ? +``` + +This function, `first_word`, takes a `&String` as an argument. We don’t want +ownership, so this is fine. But what should we return? We don’t really have a +way to talk about *part* of a string. However, we could return the index of the +end of the word. Let’s try that as shown in Listing 4-10: + +Filename: src/main.rs + +```rust +fn first_word(s: &String) -> usize { + let bytes = s.as_bytes(); + + for (i, &item) in bytes.iter().enumerate() { + if item == b' ' { + return i; + } + } + + s.len() +} +``` + + +Listing 4-10: The `first_word` function that returns a byte index value into +the `String` argument + + +Let’s break down this code a bit: + +```rust,ignore +let bytes = s.as_bytes(); +``` + +Because we need to go through the `String` element by element and check whether +a value is a space, we’ll convert our `String` to an array of bytes using the +`as_bytes` method: + +```rust,ignore +for (i, &item) in bytes.iter().enumerate() { +``` + +We’ll discuss iterators in more detail in Chapter 16. For now, know that `iter` +is a method that returns each element in a collection, and `enumerate` wraps +the result of `iter` and returns each element as part of a tuple instead. The +first element of the returned tuple is the index, and the second element is a +reference to the element. This is a bit more convenient than calculating the +index ourselves. + +Because the method returns a tuple, we can use patterns, just like everywhere +else in Rust. So we match against the tuple with `i` for the index and `&item` +for a single byte. Because we get a reference from `.iter().enumerate()`, we +use `&` in the pattern: + +```rust,ignore + if item == b' ' { + return i; + } +} +s.len() +``` + +We search for the byte that represents the space by using the byte literal +syntax. If we find a space, we return the position. Otherwise, we return the +length of the string by using `s.len()`. + +We now have a way to find out the index of the end of the first word in the +string, but there’s a problem. We’re returning a `usize` on its own, but it’s +only a meaningful number in the context of the `&String`. In other words, +because it’s a separate value from the `String`, there’s no guarantee that it +will still be valid in the future. Consider the program in Listing 4-11 that +uses the `first_word` function from Listing 4-10: + +Filename: src/main.rs + +```rust +fn main() { + let mut s = String::from("hello world"); + + let word = first_word(&s); // word will get the value 5. + + s.clear(); // This empties the String, making it equal to "". + + // word still has the value 5 here, but there's no more string that + // we could meaningfully use the value 5 with. word is now totally invalid! +} +``` + + +Listing 4-11: Storing the result from calling the `first_word` function then +changing the `String` contents + + +This program compiles without any errors and also would if we used `word` after +calling `s.clear()`. `word` isn’t connected to the state of `s` at all, so +`word` still contains the value `5`. We could use that value `5` with the +variable `s` to try to extract the first word out, but this would be a bug +because the contents of `s` have changed since we saved `5` in `word`. + +Having to worry about the index in `word` getting out of sync with the data in +`s` is tedious and error prone! Managing these indices is even more brittle if +we write a `second_word` function. Its signature would have to look like this: + +```rust,ignore +fn second_word(s: &String) -> (usize, usize) { +``` + +Now we’re tracking a start *and* an ending index, and we have even more values +that were calculated from data in a particular state but aren’t tied to that +state at all. We now have three unrelated variables floating around that need +to be kept in sync. + +Luckily, Rust has a solution to this problem: string slices. + +### String Slices + +A *string slice* is a reference to part of a `String`, and looks like this: + +```rust +let s = String::from("hello world"); + +let hello = &s[0..5]; +let world = &s[6..11]; +``` + +This is similar to taking a reference to the whole `String` but with the extra +`[0..5]` bit. Rather than a reference to the entire `String`, it’s a reference +to an internal position in the `String` and the number of elements that it +refers to. + +We create slices with a range of `[starting_index..ending_index]`, but the +slice data structure actually stores the starting position and the length of +the slice. So in the case of `let world = &s[6..11];`, `world` would be a slice +that contains a pointer to the 6th byte of `s` and a length value of 5. + +Figure 4-12 shows this in a diagram. + +world containing a pointer to the 6th byte of String s and a length 5 + + +Figure 4-12: String slice referring to part of a `String` + + +With Rust’s `..` range syntax, if you want to start at the first index (zero), +you can drop the value before the two periods. In other words, these are equal: + +```rust +let s = String::from("hello"); + +let slice = &s[0..2]; +let slice = &s[..2]; +``` + +By the same token, if your slice includes the last byte of the `String`, you +can drop the trailing number. That means these are equal: + +```rust +let s = String::from("hello"); + +let len = s.len(); + +let slice = &s[3..len]; +let slice = &s[3..]; +``` + +You can also drop both values to take a slice of the entire string. So these +are equal: + +```rust +let s = String::from("hello"); + +let len = s.len(); + +let slice = &s[0..len]; +let slice = &s[..]; +``` + +With all this information in mind, let’s rewrite `first_word` to return a +slice. The type that signifies “string slice” is written as `&str`: + +Filename: src/main.rs + +```rust +fn first_word(s: &String) -> &str { + let bytes = s.as_bytes(); + + for (i, &item) in bytes.iter().enumerate() { + if item == b' ' { + return &s[0..i]; + } + } + + &s[..] +} +``` + +We get the index for the end of the word in the same way as we did in Listing +4-10, by looking for the first occurrence of a space. When we find a space, we +return a string slice using the start of the string and the index of the space +as the starting and ending indices. + +Now when we call `first_word`, we get back a single value that is tied to the +underlying data. The value is made up of a reference to the starting point of +the slice and the number of elements in the slice. + +Returning a slice would also work for a `second_word` function: + +```rust,ignore +fn second_word(s: &String) -> &str { +``` + +We now have a straightforward API that’s much harder to mess up, since the +compiler will ensure the references into the `String` remain valid. Remember +the bug in the program in Listing 4-11, when we got the index to the end of the +first word but then cleared the string so our index was invalid? That code was +logically incorrect but didn’t show any immediate errors. The problems would +show up later if we kept trying to use the first word index with an emptied +string. Slices make this bug impossible and let us know we have a problem with +our code much sooner. Using the slice version of `first_word` will throw a +compile time error: + +Filename: src/main.rs + +```rust,ignore +fn main() { + let mut s = String::from("hello world"); + + let word = first_word(&s); + + s.clear(); // Error! +} +``` + +Here’s the compiler error: + +```text +17:6 error: cannot borrow `s` as mutable because it is also borrowed as + immutable [E0502] + s.clear(); // Error! + ^ +15:29 note: previous borrow of `s` occurs here; the immutable borrow prevents + subsequent moves or mutable borrows of `s` until the borrow ends + let word = first_word(&s); + ^ +18:2 note: previous borrow ends here +fn main() { + +} +^ +``` + +Recall from the borrowing rules that if we have an immutable reference to +something, we cannot also take a mutable reference. Because `clear` needs to +truncate the `String`, it tries to take a mutable reference, which fails. Not +only has Rust made our API easier to use, but it has also eliminated an entire +class of errors at compile time! + +#### String Literals Are Slices + +Recall that we talked about string literals being stored inside the binary. Now +that we know about slices, we can properly understand string literals: + +```rust +let s = "Hello, world!"; +``` + +The type of `s` here is `&str`: it’s a slice pointing to that specific point of +the binary. This is also why string literals are immutable; `&str` is an +immutable reference. + +#### String Slices as Arguments + +Knowing that you can take slices of literals and `String`s leads us to one more +improvement on `first_word`, and that’s its signature: + +```rust,ignore +fn first_word(s: &String) -> &str { +``` + +A more experienced Rustacean would write the following line instead because it +allows us to use the same function on both `String`s and `&str`s: + +```rust,ignore +fn first_word(s: &str) -> &str { +``` + +If we have a string slice, we can pass that as the argument directly. If we +have a `String`, we can pass a slice of the entire `String`. Defining a +function to take a string slice argument instead of a reference to a String +makes our API more general and useful without losing any functionality: + +Filename: src/main.rs + +```rust +fn main() { + let my_string = String::from("hello world"); + + // first_word works on slices of `String`s + let word = first_word(&my_string[..]); + + let my_string_literal = "hello world"; + + // first_word works on slices of string literals + let word = first_word(&my_string_literal[..]); + + // since string literals *are* string slices already, + // this works too, without the slice syntax! + let word = first_word(my_string_literal); +} +``` + +### Other Slices + +String slices, as you might imagine, are specific to strings. But there’s a +more general slice type, too. Consider this array: + +```rust +let a = [1, 2, 3, 4, 5]; +``` + +Just like we might want to refer to a part of a string, we might want to refer +to part of an array and would do so like this: + +```rust +let a = [1, 2, 3, 4, 5]; + +let slice = &a[1..3]; +``` + +This slice has the type `&[i32]`. It works the same way as string slices do, by +storing a reference to the first element and a length. You’ll use this kind of +slice for all sorts of other collections. We’ll discuss these collections in +detail when we talk about vectors in Chapter 8. + +## Summary + +The concepts of ownership, borrowing, and slices are what ensure memory safety +in Rust programs at compile time. The Rust language gives you control over your +memory usage like other systems programming languages, but having the owner of +data automatically clean up that data when the owner goes out of scope means +you don’t have to write and debug extra code to get this control. + +Ownership affects how lots of other parts of Rust work, so we’ll talk about +these concepts further throughout the rest of the book. Let’s move on to the +next chapter and look at grouping pieces of data together in a `struct`. diff --git a/src/doc/book/second-edition/nostarch/chapter05.md b/src/doc/book/second-edition/nostarch/chapter05.md new file mode 100644 index 0000000000..18094bdeb8 --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter05.md @@ -0,0 +1,615 @@ + +[TOC] + +# Structs + +A `struct`, short for *structure*, is a custom data type that lets us name and +package together multiple related values that make up a meaningful group. If +you come from an object-oriented language, a `struct` is like an object’s data +attributes. In the next section of this chapter, we’ll talk about how to define +methods on our structs; methods are how you specify the *behavior* that goes +along with a struct’s data. The `struct` and `enum` (that we will talk about in +Chapter 6) concepts are the building blocks for creating new types in your +program’s domain in order to take full advantage of Rust’s compile-time type +checking. + +One way of thinking about structs is that they are similar to tuples, which we +talked about in Chapter 3. Like tuples, the pieces of a struct can be different +types. Unlike tuples, we name each piece of data so that it’s clearer what the +values mean. Structs are more flexible as a result of these names: we don’t +have to rely on the order of the data to specify or access the values of an +instance. + +To define a struct, we enter the keyword `struct` and give the whole struct a +name. A struct’s name should describe what the significance is of these pieces +of data being grouped together. Then, inside curly braces, we define the names +of the pieces of data, which we call *fields*, and specify each field’s type. +For example, Listing 5-1 shows a struct to store information about a user +account: + +```rust +struct User { + username: String, + email: String, + sign_in_count: u64, + active: bool, +} +``` + + +Listing 5-1: A `User` struct definition + + +To use a struct once we've defined it, we create an *instance* of that struct +by specifying concrete values for each of the fields. Creating an instance is +done by stating the name of the struct, then curly braces with `key: value` +pairs inside it where the keys are the names of the fields and the values are +the data we want to store in those fields. The fields don’t have to be +specified in the same order in which the struct declared them. In other words, +the struct definition is like a general template for the type, and instances +fill in that template with particular data to create values of the type. For +example, we can declare a particular user like this: + +```rust +let user1 = User { + email: String::from("someone@example.com"), + username: String::from("someusername123"), + active: true, + sign_in_count: 1, +}; +``` + +To get a particular value out of a struct, we can use dot notation. If we +wanted just this user’s email address, we can say `user1.email`. + +## Ownership of Struct Data + +In the `User` struct definition in Listing 5-1, we used the owned `String` type +rather than the `&str` string slice type. This is a deliberate choice because +we want instances of this struct to own all of its data, and for that data to +be valid for as long as the entire struct is valid. + +It is possible for structs to store references to data owned by something else, +but to do so requires the use of *lifetimes*, a feature of Rust that we'll +discuss in Chapter 10. Lifetimes ensure that the data a struct references is +valid for as long as the struct is. If you try to store a reference in a struct +without specifying lifetimes, like this: + +Filename: src/main.rs + +```rust,ignore +struct User { + username: &str, + email: &str, + sign_in_count: u64, + active: bool, +} + +fn main() { + let user1 = User { + email: "someone@example.com", + username: "someusername123", + active: true, + sign_in_count: 1, + }; +} +``` + +The compiler will complain that it needs lifetime specifiers: + +```text +error[E0106]: missing lifetime specifier + --> + | +2 | username: &str, + | ^ expected lifetime parameter + +error[E0106]: missing lifetime specifier + --> + | +3 | email: &str, + | ^ expected lifetime parameter +``` + +We will talk about how to fix these errors in order to store references in +structs in Chapter 10, but for now, fix errors like these by switching to owned +types like `String` instead of references like `&str`. + +## An Example Program + +To understand when we might want to use structs, let’s write a program that +calculates the area of a rectangle. We’ll start off with single variables, then +refactor our program until we’re using structs instead. + +Let’s make a new binary project with Cargo called *rectangles* that will take +the length and width of a rectangle specified in pixels and will calculate the +area of the rectangle. Listing 5-2 has a short program with one way of doing +just that in our project’s *src/main.rs*: + +Filename: src/main.rs + +```rust +fn main() { + let length1 = 50; + let width1 = 30; + + println!( + "The area of the rectangle is {} square pixels.", + area(length1, width1) + ); +} + +fn area(length: u32, width: u32) -> u32 { + length * width +} +``` + + +Listing 5-2: Calculating the area of a rectangle specified by its length and +width in separate variables + + +Let’s try running this program with `cargo run`: + +```text +The area of the rectangle is 1500 square pixels. +``` + +### Refactoring with Tuples + +Our little program works okay; it figures out the area of the rectangle by +calling the `area` function with each dimension. But we can do better. The +length and the width are related to each other since together they describe one +rectangle. + +The issue with this method is evident in the signature of `area`: + +```rust,ignore +fn area(length: u32, width: u32) -> u32 { +``` + +The `area` function is supposed to calculate the area of one rectangle, but our +function takes two arguments. The arguments are related, but that’s not +expressed anywhere in our program itself. It would be more readable and more +manageable to group length and width together. + +We’ve already discussed one way we might do that in Chapter 3: tuples. Listing +5-3 has a version of our program which uses tuples: + +Filename: src/main.rs + +```rust +fn main() { + let rect1 = (50, 30); + + println!( + "The area of the rectangle is {} square pixels.", + area(rect1) + ); +} + +fn area(dimensions: (u32, u32)) -> u32 { + dimensions.0 * dimensions.1 +} +``` + + +Listing 5-3: Specifying the length and width of the rectangle with a tuple + + + + +In one way, this is a little better. Tuples let us add a bit of structure, and +we’re now passing just one argument. But in another way this method less clear: +tuples don’t give names to their elements, so our calculation has gotten more +confusing because we have to index into the parts of the tuple: + + + +```rust,ignore +dimensions.0 * dimensions.1 +``` + +It doesn’t matter if we mix up length and width for the area calculation, but +if we were to draw the rectangle on the screen it would matter! We would have +to remember that `length` was the tuple index `0` and `width` was the tuple +index `1`. If someone else was to work on this code, they would have to figure +this out and remember it as well. It would be easy to forget or mix these +values up and cause errors, since we haven’t conveyed the meaning of our data +in our code. + +### Refactoring with Structs: Adding More Meaning + +Here is where we bring in structs. We can transform our tuple into a data type +with a name for the whole as well as names for the parts, as shown in Listing +5-4: + +Filename: src/main.rs + +```rust +struct Rectangle { + length: u32, + width: u32, +} + +fn main() { + let rect1 = Rectangle { length: 50, width: 30 }; + + println!( + "The area of the rectangle is {} square pixels.", + area(&rect1) + ); +} + +fn area(rectangle: &Rectangle) -> u32 { + rectangle.length * rectangle.width +} +``` + + +Listing 5-4: Defining a `Rectangle` struct + + + + +Here we’ve defined a struct and given it the name `Rectangle`. Inside the `{}` +we defined the fields to be `length` and `width`, both of which have type +`u32`. Then in `main`, we create a particular instance of a `Rectangle` that +has a length of 50 and a width of 30. + +Our `area` function now takes one argument that we’ve named `rectangle` whose +type is an immutable borrow of a struct `Rectangle` instance. As we covered in +Chapter 4, we want to borrow the struct rather than take ownership of it so +that `main` keeps its ownership and can continue using `rect1`, so that’s why +we have the `&` in the function signature and at the call site. + +The `area` function accesses the `length` and `width` fields of the `Rectangle` +instance it got as an argument. Our function signature for `area` now says +exactly what we mean: calculate the area of a `Rectangle`, using its `length` +and `width` fields. This conveys that the length and width are related to each +other, and gives descriptive names to the values rather than using the tuple +index values of `0` and `1`. This is a win for clarity. + +### Adding Useful Functionality with Derived Traits + +It’d be nice to be able to print out an instance of our `Rectangle` while we’re +debugging our program and see the values for all its fields. Listing 5-5 tries +using the `println!` macro as we have been: + +Filename: src/main.rs + +```rust,ignore +struct Rectangle { + length: u32, + width: u32, +} + +fn main() { + let rect1 = Rectangle { length: 50, width: 30 }; + + println!("rect1 is {}", rect1); +} +``` + + +Listing 5-5: Attempting to print a `Rectangle` instance + + +If we run this, we get an error with this core message: + +```text +error[E0277]: the trait bound `Rectangle: std::fmt::Display` is not satisfied +``` + +The `println!` macro can do many kinds of formatting, and by default, `{}` +tells `println!` to use formatting known as `Display`: output intended for +direct end-user consumption. The primitive types we’ve seen so far implement +`Display` by default, as there’s only one way you’d want to show a `1` or any +other primitive type to a user. But with structs, the way `println!` should +format the output is less clear as there are more display possibilities: Do you +want commas or not? Do you want to print the struct `{}`s? Should all the +fields be shown? Because of this ambiguity, Rust doesn’t try to guess what we +want and structs do not have a provided implementation of `Display`. + +If we keep reading the errors, though, we’ll find this helpful note: + +```text +note: `Rectangle` cannot be formatted with the default formatter; try using +`:?` instead if you are using a format string +``` + +Let’s try it! The `println!` will now look like +`println!("rect1 is {:?}", rect1);`. Putting the specifier `:?` inside +the `{}` tells `println!` we want to use an output format called `Debug`. +`Debug` is a trait that enables us to print out our struct in a way that is +useful for developers so that we can see its value while we are debugging our +code. + +Let’s try running with this change and… drat. We still get an error: + +```text +error: the trait bound `Rectangle: std::fmt::Debug` is not satisfied +``` + +Again, though, the compiler has given us a helpful note! + +```text +note: `Rectangle` cannot be formatted using `:?`; if it is defined in your +crate, add `#[derive(Debug)]` or manually implement it +``` + +Rust *does* include functionality to print out debugging information, but we +have to explicitly opt-in to having that functionality be available for our +struct. To do that, we add the annotation `#[derive(Debug)]` just before our +struct definition, as shown in Listing 5-6: + +```rust +#[derive(Debug)] +struct Rectangle { + length: u32, + width: u32, +} + +fn main() { + let rect1 = Rectangle { length: 50, width: 30 }; + + println!("rect1 is {:?}", rect1); +} +``` + + +Listing 5-6: Adding the annotation to derive the `Debug` trait and printing the +`Rectangle` instance using debug formatting + + +At this point, if we run this program, we won’t get any errors and we’ll see +the following output: + +```text +rect1 is Rectangle { length: 50, width: 30 } +``` + +Nice! It’s not the prettiest output, but it shows the values of all the fields +for this instance, which would definitely help during debugging. If we want +output that is a bit prettier and easier to read, which can be helpful with +larger structs, we can use `{:#?}` in place of `{:?}` in the `println!` string. +If we use the pretty debug style in this example, the output will look like: + +``` +rect1 is Rectangle { + length: 50, + width: 30 +} +``` + +There are a number of traits Rust has provided for us to use with the `derive` +annotation that can add useful behavior to our custom types. Those traits and +their behaviors are listed in Appendix C. We’ll be covering how to implement +these traits with custom behavior, as well as creating your own traits, in +Chapter 10. + +Our `area` function is pretty specific—it only computes the area of rectangles. +It would be nice to tie this behavior together more closely with our +`Rectangle` struct, since it’s behavior that our `Rectangle` type has +specifically. Let’s now look at how we can continue to refactor this code by +turning the `area` function into an `area` *method* defined on our `Rectangle` +type. + +## Method Syntax + +*Methods* are similar to functions: they’re declared with the `fn` keyword and +their name, they can take arguments and return values, and they contain some +code that gets run when they’re called from somewhere else. Methods are +different from functions, however, because they’re defined within the context +of a struct (or an enum or a trait object, which we will cover in Chapters 6 +and 13, respectively), and their first argument is always `self`, which +represents the instance of the struct that the method is being called on. + +### Defining Methods + +Let’s change our `area` function that takes a `Rectangle` instance as an +argument and instead make an `area` method defined on the `Rectangle` struct, +as shown in Listing 5-7: + +Filename: src/main.rs + +```rust +#[derive(Debug)] +struct Rectangle { + length: u32, + width: u32, +} + +impl Rectangle { + fn area(&self) -> u32 { + self.length * self.width + } +} + +fn main() { + let rect1 = Rectangle { length: 50, width: 30 }; + + println!( + "The area of the rectangle is {} square pixels.", + rect1.area() + ); +} +``` + + +Listing 5-7: Defining an `area` method on the `Rectangle` struct + + + + +In order to make the function be defined within the context of `Rectangle`, we +start an `impl` block (`impl` is short for *implementation*). Then we move the +function within the `impl` curly braces, and change the first (and in this +case, only) argument to be `self` in the signature and everywhere within the +body. Then in `main` where we called the `area` function and passed `rect1` as +an argument, we can instead use *method syntax* to call the `area` method on +our `Rectangle` instance. Method syntax is taking an instance and adding a dot +followed by the method name, parentheses, and any arguments. + +In the signature for `area`, we get to use `&self` instead of `rectangle: +&Rectangle` because Rust knows the type of `self` is `Rectangle` due to this +method being inside the `impl Rectangle` context. Note we still need to have +the `&` before `self`, just like we had `&Rectangle`. Methods can choose to +take ownership of `self`, borrow `self` immutably as we’ve done here, or borrow +`self` mutably, just like any other argument. + +We’ve chosen `&self` here for the same reason we used `&Rectangle` in the +function version: we don’t want to take ownership, and we just want to be able +to read the data in the struct, not write to it. If we wanted to be able to +change the instance that we’ve called the method on as part of what the method +does, we’d put `&mut self` as the first argument instead. Having a method that +takes ownership of the instance by having just `self` as the first argument is +rarer; this is usually used when the method transforms `self` into something +else and we want to prevent the caller from using the original instance after +the transformation. + +The main benefit of using methods over functions, in addition to getting to use +method syntax and not having to repeat the type of `self` in every method’s +signature, is for organization. We’ve put all the things we can do with an +instance of a type together in one `impl` block, rather than make future users +of our code search for capabilities of `Rectangle` all over the place. + +PROD: START BOX + +### Where’s the `->` Operator? + +In languages like C++, there are two different operators for calling methods: +`.` if you’re calling a method on the object directly, and `->` if you’re +calling the method on a pointer to the object and thus need to dereference the +pointer first. In other words, if `object` is a pointer, `object->something()` +is like `(*object).something()`. + +Rust doesn’t have an equivalent to the `->` operator; instead, Rust has a +feature called *automatic referencing and dereferencing*. Calling methods is +one of the few places in Rust that has behavior like this. + +Here’s how it works: when you call a method with `object.something()`, Rust +will automatically add in `&`, `&mut`, or `*` so that `object` matches the +signature of the method. In other words, these are the same: + +```rust +p1.distance(&p2); +(&p1).distance(&p2); +``` + +The first one looks much, much cleaner. This automatic referencing behavior +works because methods have a clear receiver — the type of `self`. Given the +receiver and name of a method, Rust can figure out definitively whether the +method is just reading (so needs `&self`), mutating (so `&mut self`), or +consuming (so `self`). The fact that Rust makes borrowing implicit for method +receivers is a big part of making ownership ergonomic in practice. + +PROD: END BOX + +### Methods with More Arguments + +Let’s practice some more with methods by implementing a second method on our +`Rectangle` struct. This time, we’d like for an instance of `Rectangle` to take +another instance of `Rectangle` and return `true` if the second rectangle could +fit completely within `self` and `false` if it would not. That is, if we run +the code in Listing 5-8, once we've defined the `can_hold` method: + +Filename: src/main.rs + +```rust,ignore +fn main() { + let rect1 = Rectangle { length: 50, width: 30 }; + let rect2 = Rectangle { length: 40, width: 10 }; + let rect3 = Rectangle { length: 45, width: 60 }; + + println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2)); + println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3)); +} +``` + + +Listing 5-8: Demonstration of using the as-yet-unwritten `can_hold` method + + +We want to see this output, since both of `rect2`’s dimensions are smaller than +`rect1`’s, but `rect3` is wider than `rect1`: + +```text +Can rect1 hold rect2? true +Can rect1 hold rect3? false +``` + +We know we want to define a method, so it will be within the `impl Rectangle` +block. The method name will be `can_hold`, and it will take an immutable borrow +of another `Rectangle` as an argument. We can tell what the type of the +argument will be by looking at a call site: `rect1.can_hold(&rect2)` passes in +`&rect2`, which is an immutable borrow to `rect2`, an instance of `Rectangle`. +This makes sense, since we only need to read `rect2` (rather than write, which +would mean we’d need a mutable borrow) and we want `main` to keep ownership of +`rect2` so that we could use it again after calling this method. The return +value of `can_hold` will be a boolean, and the implementation will check to see +if `self`’s length and width are both greater than the length and width of the +other `Rectangle`, respectively. Let’s add this new method to the `impl` block +from Listing 5-7: + +Filename: src/main.rs + +```rust +impl Rectangle { + fn area(&self) -> u32 { + self.length * self.width + } + + fn can_hold(&self, other: &Rectangle) -> bool { + self.length > other.length && self.width > other.width + } +} +``` + + + +If we run this with the `main` from Listing 5-8, we will get our desired output! +Methods can take multiple arguments that we add to the signature after the +`self` parameter, and those arguments work just like arguments in functions do. + +### Associated Functions + +One more useful feature of `impl` blocks: we’re allowed to define functions +within `impl` blocks that *don’t* take `self` as a parameter. These are called +*associated functions*, since they’re associated with the struct. They’re still +functions though, not methods, since they don’t have an instance of the struct +to work with. You’ve already used an associated function: `String::from`. + +Associated functions are often used for constructors that will return a new +instance of the struct. For example, we could provide an associated function +that would take one dimension argument and use that as both length and width, +thus making it easier to create a square `Rectangle` rather than having to +specify the same value twice: + +Filename: src/main.rs + +```rust +impl Rectangle { + fn square(size: u32) -> Rectangle { + Rectangle { length: size, width: size } + } +} +``` + +To call this associated function, we use the `::` syntax with the struct name: +`let sq = Rectange::square(3);`, for example. This function is namespaced by +the struct: the `::` syntax is used for both associated functions and +namespaces created by modules, which we’ll learn about in Chapter 7. + +## Summary + +Structs let us create custom types that are meaningful for our domain. By using +structs, we can keep associated pieces of data connected to each other and name +each piece to make our code clear. Methods let us specify the behavior that +instances of our structs have, and associated functions let us namespace +functionality that is particular to our struct without having an instance +available. + +Structs aren’t the only way we can create custom types, though; let’s turn to +the `enum` feature of Rust and add another tool to our toolbox. diff --git a/src/doc/book/second-edition/nostarch/chapter06.md b/src/doc/book/second-edition/nostarch/chapter06.md new file mode 100644 index 0000000000..914fe3dc36 --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter06.md @@ -0,0 +1,772 @@ + +[TOC] + +# Enums and Pattern Matching + +In this chapter we’ll look at *enumerations*, also referred to as *enums*. +Enums allow you to define a type by enumerating its possible values. First, +we’ll define and use an enum to show how an enum can encode meaning along with +data. Next, we’ll explore a particularly useful enum, called `Option`, which +expresses that a value can be either something or nothing. Then we’ll look at +how pattern matching in the `match` expression makes it easy to run different +code for different values of an enum. Finally, we’ll cover how the `if let` +construct is another convenient and concise idiom available to you to handle +enums in your code. + +Enums are a feature in many languages, but their capabilities differ in each +language. Rust’s enums are most similar to *algebraic data types* in functional +languages like F#, OCaml, and Haskell. + +## Defining an Enum + +Let’s look at a situation we might want to express in code and see why enums +are useful and more appropriate than structs in this case. Say we need to work +with IP addresses. Currently, two major standards are used for IP addresses: +version four and version six. These are the only possibilities for an IP +address that our program will come across: we can *enumerate* all possible +values, which is where enumeration gets its name. + +Any IP address can be either a version four or a version six address but not +both at the same time. That property of IP addresses makes the enum data +structure appropriate for this case, because enum values can only be one of the +variants. Both version four and version six addresses are still fundamentally +IP addresses, so they should be treated as the same type when the code is +handling situations that apply to any kind of IP address. + +We can express this concept in code by defining an `IpAddrKind` enumeration and +listing the possible kinds an IP address can be, `V4` and `V6`. These are known +as the *variants* of the enum: + +```rust +enum IpAddrKind { + V4, + V6, +} +``` + +`IpAddrKind` is now a custom data type that we can use elsewhere in our code. + +### Enum Values + +We can create instances of each of the two variants of `IpAddrKind` like this: + +```rust +let four = IpAddrKind::V4; +let six = IpAddrKind::V6; +``` + +Note that the variants of the enum are namespaced under its identifier, and we +use a double colon to separate the two. The reason this is useful is that now +both values `IpAddrKind::V4` and `IpAddrKind::V6` are of the same type: +`IpAddrKind`. We can then, for instance, define a function that takes any +`IpAddrKind`: + +```rust +fn route(ip_type: IpAddrKind) { } +``` + +And we can call this function with either variant: + +```rust +route(IpAddrKind::V4); +route(IpAddrKind::V6); +``` + +Using enums has even more advantages. Thinking more about our IP address type, +at the moment we don’t have a way to store the actual IP address *data*; we +only know what *kind* it is. Given that you just learned about structs in +Chapter 5, you might tackle this problem as shown in Listing 6-1: + +```rust +enum IpAddrKind { + V4, + V6, +} + +struct IpAddr { + kind: IpAddrKind, + address: String, +} + +let home = IpAddr { + kind: IpAddrKind::V4, + address: String::from("127.0.0.1"), +}; + +let loopback = IpAddr { + kind: IpAddrKind::V6, + address: String::from("::1"), +}; +``` + + +Listing 6-1: Storing the data and `IpAddrKind` variant of an IP address using a +`struct` + + +Here, we’ve defined a struct `IpAddr` that has two fields: a `kind` field that +is of type `IpAddrKind` (the enum we defined previously) and an `address` field +of type `String`. We have two instances of this struct. The first, `home`, has +the value `IpAddrKind::V4` as its `kind` with associated address data of +`127.0.0.1`. The second instance, `loopback`, has the other variant of +`IpAddrKind` as its `kind` value, `V6`, and has address `::1` associated with +it. We’ve used a struct to bundle the `kind` and `address` values together, so +now the variant is associated with the value. + +We can represent the same concept in a more concise way using just an enum +rather than an enum as part of a struct by putting data directly into each enum +variant. This new definition of the `IpAddr` enum says that both `V4` and `V6` +variants will have associated `String` values: + +```rust +enum IpAddr { + V4(String), + V6(String), +} + +let home = IpAddr::V4(String::from("127.0.0.1")); + +let loopback = IpAddr::V6(String::from("::1")); +``` + +We attach data to each variant of the enum directly, so there is no need for an +extra struct. + +There’s another advantage to using an enum rather than a struct: each variant +can have different types and amounts of associated data. Version four type IP +addresses will always have four numeric components that will have values +between 0 and 255. If we wanted to store `V4` addresses as four `u8` values but +still express `V6` addresses as one `String` value, we wouldn’t be able to with +a struct. Enums handle this case with ease: + +```rust +enum IpAddr { + V4(u8, u8, u8, u8), + V6(String), +} + +let home = IpAddr::V4(127, 0, 0, 1); + +let loopback = IpAddr::V6(String::from("::1")); +``` + +We’ve shown several different possibilities that we could define in our code +for storing IP addresses of the two different varieties using an enum. However, +as it turns out, wanting to store IP addresses and encode which kind they are +is so common that the standard library has a definition we can use! Let’s look +at how the standard library defines `IpAddr`: it has the exact enum and +variants that we’ve defined and used, but it embeds the address data inside the +variants in the form of two different structs, which are defined differently +for each variant: + +```rust +struct Ipv4Addr { + // details elided +} + +struct Ipv6Addr { + // details elided +} + +enum IpAddr { + V4(Ipv4Addr), + V6(Ipv6Addr), +} +``` + +This code illustrates that you can put any kind of data inside an enum variant: +strings, numeric types, or structs, for example. You can even include another +enum! Also, standard library types are often not much more complicated than +what you might come up with. + +Note that even though the standard library contains a definition for `IpAddr`, +we can still create and use our own definition without conflict because we +haven’t brought the standard library’s definition into our scope. We’ll talk +more about importing types in Chapter 7. + +Let’s look at another example of an enum in Listing 6-2: this one has a wide +variety of types embedded in its variants: + +```rust +enum Message { + Quit, + Move { x: i32, y: i32 }, + Write(String), + ChangeColor(i32, i32, i32), +} +``` + + +Listing 6-2: A `Message` enum whose variants each store different amounts and +types of values + + +This enum has four variants with different types: + +* `Quit` has no data associated with it at all. +* `Move` includes an anonymous struct inside it. +* `Write` includes a single `String`. +* `ChangeColor` includes three `i32`s. + +Defining an enum with variants like the ones in Listing 6-2 is similar to +defining different kinds of struct definitions except the enum doesn’t use the +`struct` keyword and all the variants are grouped together under the `Message` +type. The following structs could hold the same data that the preceding enum +variants hold: + +```rust +struct QuitMessage; // unit struct +struct MoveMessage { + x: i32, + y: i32, +} +struct WriteMessage(String); // tuple struct +struct ChangeColorMessage(i32, i32, i32); // tuple struct +``` + +But if we used the different structs, which each have their own type, we +wouldn’t be able to as easily define a function that could take any of these +kinds of messages as we could with the `Message` enum defined in Listing 6-2, +which is a single type. + +There is one more similarity between enums and structs: just as we’re able to +define methods on structs using `impl`, we’re also able to define methods on +enums. Here’s a method named `call` that we could define on our `Message` enum: + +```rust +impl Message { + fn call(&self) { + // method body would be defined here + } +} + +let m = Message::Write(String::from("hello")); +m.call(); +``` + +The body of the method would use `self` to get the value that we called the +method on. In this example, we’ve created a variable `m` that has the value +`Message::Write("hello")`, and that is what `self` will be in the body of the +`call` method when `m.call()` runs. + +Let’s look at another enum in the standard library that is very common and +useful: `Option`. + +### The `Option` Enum and Its Advantages Over Null Values + +In the previous section, we looked at how the `IpAddr` enum let us use Rust’s +type system to encode more information than just the data into our program. +This section explores a case study of `Option`, which is another enum defined +by the standard library. The `Option` type is used in many places because it +encodes the very common scenario in which a value could be something or it +could be nothing. Expressing this concept in terms of the type system means the +compiler can check that you’ve handled all the cases you should be handling, +which can prevent bugs that are extremely common in other programming languages. + +Programming language design is often thought of in terms of which features you +include, but the features you exclude are important too. Rust doesn’t have the +null feature that many other languages have. *Null* is a value that means there +is no value there. In languages with null, variables can always be in one of +two states: null or not-null. + +In “Null References: The Billion Dollar Mistake,” Tony Hoare, the inventor of +null, has this to say: + +> I call it my billion-dollar mistake. At that time, I was designing the first +> comprehensive type system for references in an object-oriented language. My +> goal was to ensure that all use of references should be absolutely safe, with +> checking performed automatically by the compiler. But I couldn't resist the +> temptation to put in a null reference, simply because it was so easy to +> implement. This has led to innumerable errors, vulnerabilities, and system +> crashes, which have probably caused a billion dollars of pain and damage in +> the last forty years. + +The problem with null values is that if you try to actually use a value that’s +null as if it is a not-null value, you’ll get an error of some kind. Because +this null or not-null property is pervasive, it’s extremely easy to make this +kind of error. + +However, the concept that null is trying to express is still a useful one: a +null is a value that is currently invalid or absent for some reason. + +The problem isn’t with the actual concept but with the particular +implementation. As such, Rust does not have nulls, but it does have an enum +that can encode the concept of a value being present or absent. This enum is +`Option`, and it is defined by the standard library as follows: + +```rust +enum Option { + Some(T), + None, +} +``` + +The `Option` enum is so useful that it’s even included in the prelude; you +don’t need to import it explicitly. In addition, so are its variants: you can +use `Some` and `None` directly without prefixing them with `Option::`. +`Option` is still just a regular enum, and `Some(T)` and `None` are still +variants of type `Option`. + +The `` syntax is a feature of Rust we haven’t talked about yet. It’s a +generic type parameter, and we’ll cover generics in more detail in Chapter 10. +For now, all you need to know is that `` means the `Some` variant of the +`Option` enum can hold one piece of data of any type. Here are some examples of +using `Option` values to hold number types and string types: + +```rust +let some_number = Some(5); +let some_string = Some("a string"); + +let absent_number: Option = None; +``` + +If we use `None` rather than `Some`, we need to tell Rust what type of +`Option` we have, because the compiler can't infer the type that the `Some` +variant will hold by looking only at a `None` value. + +When we have a `Some` value, we know that a value is present, and the value is +held within the `Some`. When we have a `None` value, in some sense, it means +the same thing as null: we don’t have a valid value. So why is having +`Option` any better than having null? + +In short, because `Option` and `T` (where `T` can be any type) are different +types, the compiler won’t let us use an `Option` value as if it was +definitely a valid value. For example, this code won’t compile because it’s +trying to compare an `Option` to an `i8`: + +```rust,ignore +let x: i8 = 5; +let y: Option = Some(5); + +let sum = x + y; +``` + +If we run this code, we get an error message like this: + +```text +error[E0277]: the trait bound `i8: std::ops::Add>` is +not satisfied + --> + | +7 | let sum = x + y; + | ^^^^^ + | +``` + +Intense! In effect, this error message means that Rust doesn’t understand how +to add an `Option` and an `i8`, because they’re different types. When we +have a value of a type like `i8` in Rust, the compiler will ensure that we +always have a valid value. We can proceed confidently without having to check +for null before using that value. Only when we have an `Option` (or +whatever type of value we’re working with) do we have to worry about possibly +not having a value, and the compiler will make sure we handle that case before +using the value. + +In other words, you have to convert an `Option` to a `T` before you can +perform `T` operations with it. Generally, this helps catch one of the most +common issues with null: assuming that something isn’t null when it actually +is. + +Not having to worry about missing an assumption of having a not-null value +helps you to be more confident in your code. In order to have a value that can +possibly be null, you must explicitly opt in by making the type of that value +`Option`. Then, when you use that value, you are required to explicitly +handle the case when the value is null. Everywhere that a value has a type that +isn’t an `Option`, you *can* safely assume that the value isn’t null. This +was a deliberate design decision for Rust to limit null’s pervasiveness and +increase the safety of Rust code. + +So, how do you get the `T` value out of a `Some` variant when you have a value +of type `Option` so you can use that value? The `Option` enum has a large +number of methods that are useful in a variety of situations; you can check +them out in its documentation. Becoming familiar with the methods on +`Option` will be extremely useful in your journey with Rust. + +In general, in order to use an `Option` value, we want to have code that +will handle each variant. We want some code that will run only when we have a +`Some(T)` value, and this code is allowed to use the inner `T`. We want some +other code to run if we have a `None` value, and that code doesn’t have a `T` +value available. The `match` expression is a control flow construct that does +just this when used with enums: it will run different code depending on which +variant of the enum it has, and that code can use the data inside the matching +value. + +## The `match` Control Flow Operator + +Rust has an extremely powerful control-flow operator called `match` that 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; Chapter 18 will be about all the +different kinds of patterns and what they do. The power of `match` comes from +the expressiveness of the patterns and the compiler checks that make sure all +possible cases are handled. + +Think of a `match` expression kind of like a coin sorting machine: coins slide +down a track with variously sized holes along it, and each coin falls through +the first hole it encounters that it fits into. In the same way, values go +through each pattern in a `match`, and at the first pattern the value “fits,” +the value will fall into the associated code block to be used during execution. + +Because we just mentioned coins, let’s use them as an example using `match`! We +can write a function that can take an unknown United States coin and, in a +similar way as the counting machine, determine which coin it is and return its +value in cents, as shown here in Listing 6-3: + +```rust +enum Coin { + Penny, + Nickel, + Dime, + Quarter, +} + +fn value_in_cents(coin: Coin) -> i32 { + match coin { + Coin::Penny => 1, + Coin::Nickel => 5, + Coin::Dime => 10, + Coin::Quarter => 25, + } +} +``` + + +Listing 6-3: An enum and a `match` expression that has the variants of the enum +as its patterns. + + +Let’s break down the `match` in the `value_in_cents` function. First, we list +the `match` keyword followed by an expression, which in this case is the value +`coin`. This seems very similar to an expression used with `if`, but there’s a +big difference: with `if`, the expression needs to return a boolean value. +Here, it can be any type. The type of `coin` in this example is the `Coin` enum +that we defined in Listing 6-3. + +Next are the `match` arms. An arm has two parts: a pattern and some code. The +first arm here has a pattern that is the value `Coin::Penny` and then the `=>` +operator that separates the pattern and the code to run. The code in this case +is just the value `1`. Each arm is separated from the next with a comma. + +When the `match` expression executes, it compares the resulting value against +the pattern of each arm, in order. If a pattern matches the value, the code +associated with that pattern is executed. If that pattern doesn’t match the +value, execution continues to the next arm, much like a coin sorting machine. +We can have as many arms as we need: in Listing 6-3, our `match` has four arms. + +The code associated with each arm is an expression, and the resulting value of +the expression in the matching arm is the value that gets returned for the +entire `match` expression. + +Curly braces typically aren’t used if the match arm code is short, as it is in +Listing 6-3 where each arm just returns a value. If you want to run multiple +lines of code in a match arm, you can use curly braces. For example, the +following code would print out “Lucky penny!” every time the method was called +with a `Coin::Penny` but would still return the last value of the block, `1`: + +```rust +fn value_in_cents(coin: Coin) -> i32 { + match coin { + Coin::Penny => { + println!("Lucky penny!"); + 1 + }, + Coin::Nickel => 5, + Coin::Dime => 10, + Coin::Quarter => 25, + } +} +``` + +### Patterns that Bind to Values + +Another useful feature of match arms is that they can bind to parts of the +values that match the pattern. This is how we can extract values out of enum +variants. + +As an example, let’s change one of our enum variants to hold data inside it. +From 1999 through 2008, the United States printed quarters with different +designs for each of the 50 states on one side. No other coins got state +designs, so only quarters have this extra value. We can add this information to +our `enum` by changing the `Quarter` variant to include a `State` value stored +inside it, which we've done here in Listing 6-4: + +```rust +#[derive(Debug)] // So we can inspect the state in a minute +enum UsState { + Alabama, + Alaska, + // ... etc +} + +enum Coin { + Penny, + Nickel, + Dime, + Quarter(UsState), +} +``` + + +Listing 6-4: A `Coin` enum where the `Quarter` variant also holds a `UsState` +value + + +Let’s imagine that a friend of ours is trying to collect all 50 state quarters. +While we sort our loose change by coin type, we’ll also call out the name of +the state associated with each quarter so if it’s one our friend doesn’t have, +they can add it to their collection. + +In the match expression for this code, we add a variable called `state` to the +pattern that matches values of the variant `Coin::Quarter`. When a +`Coin::Quarter` matches, the `state` variable will bind to the value of that +quarter’s state. Then we can use `state` in the code for that arm, like so: + +```rust +fn value_in_cents(coin: Coin) -> i32 { + match coin { + Coin::Penny => 1, + Coin::Nickel => 5, + Coin::Dime => 10, + Coin::Quarter(state) => { + println!("State quarter from {:?}!", state); + 25 + }, + } +} +``` + +If we were to call `value_in_cents(Coin::Quarter(UsState::Alaska))`, `coin` +would be `Coin::Quarter(UsState::Alaska)`. When we compare that value with each +of the match arms, none of them match until we reach `Coin::Quarter(state)`. At +that point, the binding for `state` will be the value `UsState::Alaska`. We can +then use that binding in the `println!` expression, thus getting the inner +state value out of the `Coin` enum variant for `Quarter`. + +### Matching with `Option` + +In the previous section we wanted to get the inner `T` value out of the `Some` +case when using `Option`; we can also handle `Option` using `match` as we +did with the `Coin` enum! Instead of comparing coins, we’ll compare the +variants of `Option`, but the way that the `match` expression works remains +the same. + +Let’s say we want to write a function that takes an `Option`, and if +there’s a value inside, adds one to that value. If there isn’t a value inside, +the function should return the `None` value and not attempt to perform any +operations. + +This function is very easy to write, thanks to `match`, and will look like +Listing 6-5: + +```rust +fn plus_one(x: Option) -> Option { + match x { + None => None, + Some(i) => Some(i + 1), + } +} + +let five = Some(5); +let six = plus_one(five); +let none = plus_one(None); +``` + + +Listing 6-5: A function that uses a `match` expression on an `Option` + + +#### Matching `Some(T)` + +Let’s examine the first execution of `plus_one` in more detail. When we call +`plus_one(five)` w, the variable `x` in the body of `plus_one` will have the +value `Some(5)`. We then compare that against each match arm. + +```rust,ignore +None => None, +``` + +The `Some(5)` value doesn’t match the pattern `None` u, so we continue to the +next arm. + +```rust,ignore +Some(i) => Some(i + 1), +``` + +Does `Some(5)` match `Some(i)` v? Why yes it does! We have the same variant. +The `i` binds to the value contained in `Some`, so `i` takes the value `5`. The +code in the match arm is then executed, so we add one to the value of `i` and +create a new `Some` value with our total `6` inside. + +#### Matching `None` + +Now let’s consider the second call of `plus_one` in Listing 6-5 where `x` is +`None` x. We enter the `match` and compare to the first arm u. + +```rust,ignore +None => None, +``` + +It matches! There’s no value to add to, so the program stops and returns the +`None` value on the right side of `=>`. Because the first arm matched, no other +arms are compared. + +Combining `match` and enums is useful in many situations. You’ll see this +pattern a lot in Rust code: `match` against an enum, bind a variable to the +data inside, and then execute code based on it. It’s a bit tricky at first, but +once you get used to it, you’ll wish you had it in all languages. It’s +consistently a user favorite. + +### Matches Are Exhaustive + +There’s one other aspect of `match` we need to discuss. Consider this version +of our `plus_one` function: + +```rust,ignore +fn plus_one(x: Option) -> Option { + match x { + Some(i) => Some(i + 1), + } +} +``` + +We didn’t handle the `None` case, so this code will cause a bug. Luckily, it’s +a bug Rust knows how to catch. If we try to compile this code, we’ll get this +error: + +```text +error[E0004]: non-exhaustive patterns: `None` not covered + --> + | +6 | match x { + | ^ pattern `None` not covered +``` + +Rust knows that we didn’t cover every possible case and even knows which +pattern we forgot! Matches in Rust are *exhaustive*: we must exhaust every last +possibility in order for the code to be valid. Especially in the case of +`Option`, when Rust prevents us from forgetting to explicitly handle the +`None` case, it protects us from assuming that we have a value when we might +have null, thus making the billion dollar mistake discussed earlier. + +### The `_` Placeholder + +Rust also has a pattern we can use in situations when we don’t want to list all +possible values. For example, a `u8` can have valid values of 0 through 255. If +we only care about the values 1, 3, 5, and 7, we don’t want to have to list out +0, 2, 4, 6, 8, 9 all the way up to 255. Fortunately, we don’t have to: we can +use the special pattern `_` instead: + +```rust +let some_u8_value = 0u8; +match some_u8_value { + 1 => println!("one"), + 3 => println!("three"), + 5 => println!("five"), + 7 => println!("seven"), + _ => (), +} +``` + +The `_` pattern will match any value. By putting it after our other arms, the +`_` will match all the possible cases that aren’t specified before it. The `()` +is just the unit value, so nothing will happen in the `_` case. As a result, we +can say that we want to do nothing for all the possible values that we don’t +list before the `_` placeholder. + +However, the `match` expression can be a bit wordy in a situation in which we +only care about *one* of the cases. For this situation, Rust provides `if let`. + +## Concise Control Flow with `if let` + +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. Consider the program +in Listing 6-6 that matches on an `Option` value but only wants to execute +code if the value is three: + +```rust +let some_u8_value = Some(0u8); +match some_u8_value { + Some(3) => println!("three"), + _ => (), +} +``` + + +Listing 6-6: A `match` that only cares about executing code when the value is +`Some(3)` + + +We want to do something with the `Some(3)` match but do nothing with any other +`Some` value or the `None` value. To satisfy the `match` expression, we +have to add `_ => ()` after processing just one variant, which is a lot of +boilerplate code to add. + +Instead, we could write this in a shorter way using `if let`. The following +code behaves the same as the `match` in Listing 6-6: + +```rust +if let Some(3) = some_u8_value { + println!("three"); +} +``` + +`if let` takes a pattern and an expression separated by an `=`. It works the +same way as a `match`, where the expression is given to the `match` and the +pattern is its first arm. + +Using `if let` means you have less to type, less indentation, and less +boilerplate code. However, we’ve lost the exhaustive checking that `match` +enforces. Choosing between `match` and `if let` depends on what you’re doing in +your particular situation and if gaining conciseness is an appropriate +trade-off for losing exhaustive checking. + +In other words, you can think of `if let` as syntax sugar for a `match` that +runs code when the value matches one pattern and then ignores all other values. + +We can include an `else` with an `if let`. The block of code that goes with the +`else` is the same as the block of code that would go with the `_` case in the +`match` expression that is equivalent to the `if let` and `else`. Recall the +`Coin` enum definition in Listing 6-4, where the `Quarter` variant also held a +`UsState` value. If we wanted to count all non-quarter coins we see while also +announcing the state of the quarters, we could do that with a `match` +expression like this: + +```rust +let mut count = 0; +match coin { + Coin::Quarter(state) => println!("State quarter from {:?}!", state), + _ => count += 1, +} +``` + +Or we could use an `if let` and `else` expression like this: + +```rust +let mut count = 0; +if let Coin::Quarter(state) = coin { + println!("State quarter from {:?}!", state); +} else { + count += 1; +} +``` + +If you have a situation in which your program has logic that is too verbose to +express using a `match`, remember that `if let` is in your Rust toolbox as well. + +## Summary + +We’ve now covered how to use enums to create custom types that can be one of a +set of enumerated values. We’ve shown how the standard library’s `Option` +type helps you use the type system to prevent errors. When enum values have +data inside them, you can use `match` or `if let` to extract and use those +values, depending on how many cases you need to handle. + +Your Rust programs can now express concepts in your domain using structs and +enums. Creating custom types to use in your API ensures type safety: the +compiler will make certain your functions only get values of the type each +function expects. + +In order to provide a well-organized API to your users that is straightforward +to use and only exposes exactly what your users will need, let’s now turn to +Rust’s modules. + diff --git a/src/doc/book/second-edition/nostarch/chapter07.md b/src/doc/book/second-edition/nostarch/chapter07.md new file mode 100644 index 0000000000..81b19d1349 --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter07.md @@ -0,0 +1,1098 @@ + +[TOC] + +# Modules + +When you start writing programs in Rust, your code might live solely in the +`main` function. As your code grows, you’ll eventually move functionality out +into other functions, both for re-use and for better organization. By splitting +your code up into smaller chunks, each chunk is easier to understand on its +own. But what happens if you find yourself with too many functions? Rust has a +module system that handles the problem of wanting to re-use code while keeping +your code organized. + +In the same way that you extract lines of code into a function, you can extract +functions (and other code like structs and enums too) into different modules. 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). Here’s an overview of how modules work: + +* You declare a new module with the keyword `mod` +* By default, everything is set as private (including modules). You can use the + `pub` keyword to make a module public and therefore visible outside of its + namespace. +* The `use` keyword allows you to bring modules, or the definitions inside + modules, into scope so that it’s easier to refer to them. + +We’ll take a look at each of these parts and see how they fit into the whole. + +## `mod` and the Filesystem + +We’ll start our module example by making a new project with Cargo, but instead +of creating a binary crate, we’re going to make a library crate: a project that +other people can pull into their projects as a dependency. We saw this with the +`rand` crate in Chapter 2. + +We’ll create a skeleton of a library that provides some general networking +functionality; we’re going to concentrate on the organization of the modules +and functions, but not worry about what code goes in the function bodies. We’ll +call our library `communicator`. By default, cargo will create a library unless +another type of project is specified, so if we leave off the `--bin` option +that we’ve been using so far our project will be a library: + +```text +$ cargo new communicator +$ cd communicator +``` + +Notice that Cargo generated *src/lib.rs* instead of *src/main.rs*. Inside +*src/lib.rs* we’ll find this: + +Filename: src/lib.rs + +```rust +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + } +} +``` + +Cargo creates an empty test to help us get our library started, rather than the +“Hello, world!” binary that we get with the `--bin` option. We’ll look at the +`#[]` and `mod tests` syntax a little later, but for now just make sure to +leave it in your *src/lib.rs*. + +Since we don’t have a *src/main.rs*, there’s nothing for Cargo to execute with +the `cargo run` command. Therefore, we will be using the `cargo build` command +to only compile our library crate’s code. + +We’re going to look at different options for organizing your library’s code +which will be suitable in a variety of situations, depending on the intentions +you have for your code. + +### Module Definitions + +For our `communicator` networking library, we’re first going to define a module +named `network` that contains the definition of a function called `connect`. +Every module definition in Rust starts with the `mod` keyword. Add this code to +the beginning of the *src/lib.rs* file, above the test code: + +Filename: src/lib.rs + +```rust +mod network { + fn connect() { + } +} +``` + +After the `mod` keyword, we put the name of the module, `network`, then a block +of code in curly braces. Everything inside this block is inside the namespace +`network`. In this case, we have a single function, `connect`. If we wanted to +call this function from a script outside the `network` module, we would need to +specify the module and use the namespace syntax `::`, like so: +`network::connect()`, rather than just `connect()`. + +We can also have multiple modules, side-by-side, in the same *src/lib.rs* file. +For example, to have a `client` module too, that also has a function named +`connect`, we can add it as shown in Listing 7-1: + +
+Filename: src/lib.rs + +```rust +mod network { + fn connect() { + } +} + +mod client { + fn connect() { + } +} +``` + +
+ +Listing 7-1: The `network` module and the `client` module defined side-by-side +in *src/lib.rs* + +
+
+ +Now we have a `network::connect` function and a `client::connect` function. +These can have completely different functionality, and the function names do +not conflict with each other since they’re in different modules. + +While in this case, we’re building a library, there's nothing special about +*src/lib.rs*. We could also make use of submodules in *src/main.rs* as well. In +fact, we can also put modules inside of modules. This can be useful as your +modules grow to keep related functionality organized together and separate +functionality apart. The choice of how you organize your code depends on how +you think about the relationship between the parts of your code. For instance, +the `client` code and its `connect` function might make more sense to users of +our library if it was inside the `network` namespace instead, like in Listing +7-2: + +
+Filename: src/lib.rs + +```rust +mod network { + fn connect() { + } + + mod client { + fn connect() { + } + } +} +``` + +
+ +Listing 7-2: Moving the `client` module inside of the `network` module + +
+
+ +In your *src/lib.rs* file, replace the existing `mod network` and `mod client` +definitions with this one that has the `client` module as an inner module of +`network`. Now we have the functions `network::connect` and +`network::client::connect`: again, the two functions named `connect` don’t +conflict with each other since they’re in different namespaces. + +In this way, modules form a hierarchy. The contents of *src/lib.rs* are at the +topmost level, and the submodules are at lower levels. Here’s what the +organization of our example from Listing 7-1 looks like when thought of this +way: + +```text +communicator + ├── network + └── client +``` + +And here’s the example from Listing 7-2: + +```text +communicator + └── network + └── client +``` + +You can see that in Listing 7-2, `client` is a child of the `network` module, +rather than a sibling. More complicated projects can have a lot of modules, and +they’ll need to be organized logically in order to keep track of them. What +“logically” means in your project is up to you and depends on how you and users +of your library think about your project’s domain. Use the techniques we’ve +shown here to create side-by-side modules and nested modules in whatever +structure you would like. + +### Moving Modules to Other Files + +Modules form a hierarchical structure, much like another structure in computing +that you’re used to: file systems! We can use Rust’s module system along with +multiple files to split Rust projects up so that not everything lives in +*src/lib.rs*. For this example, we will start with the code in Listing 7-3: + +
+Filename: src/lib.rs + +```rust +mod client { + fn connect() { + } +} + +mod network { + fn connect() { + } + + mod server { + fn connect() { + } + } +} +``` + +
+ +Listing 7-3: Three modules, `client`, `network`, and `network::server`, all +defined in *src/lib.rs* + +
+
+ +which has this module hierarchy: + +```text +communicator + ├── client + └── network + └── server +``` + +If these modules had many functions, and those functions were getting long, it +would be difficult to scroll through this file to find the code we wanted to +work with. Because the functions are nested inside one or more mod blocks, the +lines of code inside the functions will start getting long as well. These would +be good reasons to pull each of the `client`, `network`, and `server` modules +out of *src/lib.rs* and into their own files. + +Let’s start by extracting the `client` module into another file. First, replace +the `client` module code in *src/lib.rs* with the following: + +Filename: src/lib.rs + +```rust,ignore +mod client; + +mod network { + fn connect() { + } + + mod server { + fn connect() { + } + } +} +``` + +We’re still *defining* the `client` module here, but by removing the curly +braces and definitions inside the `client` module and replacing them with a +semicolon, we’re letting Rust know to look in another location for the code +defined inside that module. + +So now we need to create the external file with that module name. Create a +*client.rs* file in your *src/* directory, then open it up and enter the +following, which is the `connect` function in the `client` module that we +removed in the previous step: + +Filename: src/client.rs + +```rust +fn connect() { +} +``` + +Note that we don’t need a `mod` declaration in this file; that’s because we +already declared the `client` module with `mod` in *src/lib.rs*. This file just +provides the *contents* of the `client` module. If we put a `mod client` here, +we’d be giving the `client` module its own submodule named `client`! + +Rust only knows to look in *src/lib.rs* by default. If we want to add more +files to our project, we need to tell Rust in *src/lib.rs* to look in other +files; this is why `mod client` needs to be defined in *src/lib.rs* and can’t +be defined in *src/client.rs*. + +Now, everything should compile successfully, though you’ll get a few warnings. +Remember to use `cargo build` instead of `cargo run` since we have a library +crate rather than a binary crate: + +```text +$ cargo build + Compiling communicator v0.1.0 (file:///projects/communicator) + +warning: function is never used: `connect`, #[warn(dead_code)] on by default + --> src/client.rs:1:1 + | +1 | fn connect() { + | ^ + +warning: function is never used: `connect`, #[warn(dead_code)] on by default + --> src/lib.rs:4:5 + | +4 | fn connect() { + | ^ + +warning: function is never used: `connect`, #[warn(dead_code)] on by default + --> src/lib.rs:8:9 + | +8 | fn connect() { + | ^ +``` + +These warnings tell us that we have functions that are never used. Don’t worry +about those warnings for now; we’ll address them later in the chapter. The good +news is that they’re just warnings; our project was built successfully! + +Let’s extract the `network` module into its own file next, using the same +pattern. In *src/lib.rs*, delete the body of the `network` module and add a +semicolon to the declaration, like so: + +Filename: src/lib.rs + +```rust,ignore +mod client; + +mod network; +``` + +Then create a new *src/network.rs* file and enter the following: + +Filename: src/network.rs + +```rust +fn connect() { +} + +mod server { + fn connect() { + } +} +``` + +Notice that we still have a `mod` declaration within this module file; this is +because we still want `server` to be a sub-module of `network`. + +Now run `cargo build` again. Success! We have one more module to extract: +`server`. Because it’s a sub-module—that is, a module within a module—our +current tactic of extracting a module into a file named after that module won’t +work. We’re going to try anyway so that we can see the error. First change +*src/network.rs* to have `mod server;` instead of the `server` module’s +contents: + +Filename: src/network.rs + +```rust,ignore +fn connect() { +} + +mod server; +``` + +Then create a *src/server.rs* file and enter the contents of the `server` +module that we extracted: + +Filename: src/server.rs + +```rust +fn connect() { +} +``` + +When we try to `cargo build`, we’ll get the error shown in Listing 7-4: + +
+ +```text +$ cargo build + Compiling communicator v0.1.0 (file:///projects/communicator) +error: cannot declare a new module at this location + --> src/network.rs:4:5 + | +4 | mod server; + | ^^^^^^ + | +note: maybe move this module `network` to its own directory via `network/mod.rs` + --> src/network.rs:4:5 + | +4 | mod server; + | ^^^^^^ +note: ... or maybe `use` the module `server` instead of possibly redeclaring it + --> src/network.rs:4:5 + | +4 | mod server; + | ^^^^^^ +``` + +
+ +Listing 7-4: Error when trying to extract the `server` submodule into +*src/server.rs* + +
+
+ +The error says we `cannot declare a new module at this location` and is +pointing to the `mod server;` line in *src/network.rs*. So *src/network.rs* is +different than *src/lib.rs* somehow; let’s keep reading to understand why. + +The note in the middle of Listing 7-4 is actually pretty helpful, as it points +out something we haven’t yet talked about doing: + +```text +note: maybe move this module `network` to its own directory via `network/mod.rs` +``` + +Instead of continuing to follow the same file naming pattern we used +previously, we can do what the note suggests: + +1. Make a new *directory* named *network*, the parent module’s name +2. Move the *src/network.rs* file into the new *network* directory and rename + it so that it is now *src/network/mod.rs* +3. Move the submodule file *src/server.rs* into the *network* directory + +Here are commands to carry out these steps: + +```text +$ mkdir src/network +$ mv src/network.rs src/network/mod.rs +$ mv src/server.rs src/network +``` + +Now if we try to `cargo build`, compilation will work (we’ll still have +warnings though). Our module layout still looks like this, which is exactly the +same as it did when we had all the code in *src/lib.rs* in Listing 7-3: + +```text +communicator + ├── client + └── network + └── server +``` + +The corresponding file layout now looks like this: + +```text +├── src +│   ├── client.rs +│   ├── lib.rs +│   └── network +│   ├── mod.rs +│   └── server.rs +``` + +So when we wanted to extract the `network::server` module, why did we have to +also change the *src/network.rs* file into the *src/network/mod.rs* file, and +put the code for `network::server` in the *network* directory in +*src/network/server.rs*, instead of just being able to extract the +`network::server` module into *src/server.rs*? The reason is that Rust wouldn’t +be able to tell that `server` was supposed to be a submodule of `network` if +the *server.rs* file was in the *src* directory. To make it clearer why Rust +can’t tell, let’s consider a different example with the following module +hierarchy, where all the definitions are in *src/lib.rs*: + +```text +communicator + ├── client + └── network + └── client +``` + +In this example, we have three modules again, `client`, `network`, and +`network::client`. If we follow the same steps we originally did above for +extracting modules into files, for the `client` module we would create +*src/client.rs*. For the `network` module, we would create *src/network.rs*. +Then we wouldn’t be able to extract the `network::client` module into a +*src/client.rs* file, because that already exists for the top-level `client` +module! If we put the code in both the `client` and `network::client` modules +in the *src/client.rs* file, Rust would not have any way to know whether the +code was for `client` or for `network::client`. + +Therefore, once we wanted to extract a file for the `network::client` submodule +of the `network` module, we needed to create a directory for the `network` +module instead of a *src/network.rs* file. The code that is in the `network` +module then goes into the *src/network/mod.rs* file, and the submodule +`network::client` can have its own *src/network/client.rs* file. Now the +top-level *src/client.rs* is unambiguously the code that belongs to the +`client` module. + +### Rules of Module File Systems + +In summary, these are the rules of modules with regards to files: + +* If a module named `foo` has no submodules, you should put the declarations + for `foo` in a file named *foo.rs*. +* If a module named `foo` does have submodules, you should put the declarations + for `foo` in a file named *foo/mod.rs*. + +These rules apply recursively, so that if a module named `foo` has a submodule +named `bar` and `bar` does not have submodules, you should have the following +files in your *src* directory: + +```text +├── foo +│   ├── bar.rs (contains the declarations in `foo::bar`) +│   └── mod.rs (contains the declarations in `foo`, including `mod bar`) +``` + +The modules themselves should be declared in their parent module’s file using +the `mod` keyword. + +Next, we’ll talk about the `pub` keyword, and get rid of those warnings! + +## Controlling Visibility with `pub` + +We resolved the error messages shown in Listing 7-4 by moving the `network` and +`network::server` code into the *src/network/mod.rs* and +*src/network/server.rs* files, respectively. At that point, `cargo build` was +able to build our project, but we still get some warning messages about the +`client::connect`, `network::connect`, and `network::server::connect` functions +not being used: + +```text +warning: function is never used: `connect`, #[warn(dead_code)] on by default +src/client.rs:1:1 + | +1 | fn connect() { + | ^ + +warning: function is never used: `connect`, #[warn(dead_code)] on by default + --> src/network/mod.rs:1:1 + | +1 | fn connect() { + | ^ + +warning: function is never used: `connect`, #[warn(dead_code)] on by default + --> src/network/server.rs:1:1 + | +1 | fn connect() { + | ^ +``` + +So why are we receiving these warnings? After all, we’re building a library +with functions that are intended to be used by our *users*, and not necessarily +by us within our own project, so it shouldn’t matter that these `connect` +functions go unused. The point of creating them is that they will be used by +another project and not our own. + +To understand why this program invokes these warnings, let’s try using the +`connect` library as if we were another project, calling it externally. To do +that, we’ll create a binary crate in the same directory as our library crate, +by making a *src/main.rs* file containing this code: + +Filename: src/main.rs + +```rust,ignore +extern crate communicator; + +fn main() { + communicator::client::connect(); +} +``` + +We use the `extern crate` command to bring the `communicator` library crate +into scope, because our package actually now contains *two* crates. Cargo +treats *src/main.rs* as the root file of a binary crate, which is separate from +the existing library crate whose root file is *src/lib.rs*. This pattern is +quite common for executable projects: most functionality is in a library crate, +and the binary crate uses that library crate. This way, other programs can also +use the library crate, and it’s a nice separation of concerns. + +From the point of view of a crate outside of the `communicator` library looking +in, all of the modules we've been creating are within a module that has the +same name as the crate, `communicator`. We call the top-level module of a crate +the *root module*. + +Also note that even if we're using an external crate within a submodule of our +project, the `extern crate` should go in our root module (so in *src/main.rs* +or *src/lib.rs*). Then, in our submodules, we can refer to items from external +crates as if the items are top-level modules. + +Our binary crate right now just calls our library’s `connect` function from the +`client` module. However, invoking `cargo build` will now give us an error +after the warnings: + +```text +error: module `client` is private + --> src/main.rs:4:5 + | +4 | communicator::client::connect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``` + +Ah ha! This tells us that the `client` module is private, and this is the crux +of the warnings. It’s also the first time we’ve run into the concepts of +*public* and *private* in the context of Rust. The default state of all code in +Rust is private: no one else is allowed to use the code. If you don’t use a +private function within your own program, since your own program is the only +code allowed to use that function, Rust will warn you that the function has +gone unused. + +Once we specify that a function like `client::connect` is public, not only will +our call to that function from our binary crate be allowed, the warning that +the function is unused will go away. Marking something public lets Rust know +that we intend for the function to be used by code outside of our program. Rust +considers the theoretical external usage that’s now possible as the function +“being used.” Thus, when something is marked as public, Rust will not require +that it’s used in our own program and will stop warning that the item is unused. + +### Making a Function Public + +To tell Rust to make something public, we add the `pub` keyword to the start of +the declaration of the item we want to make public. We’ll focus on fixing the +warning that tells us that `client::connect` has gone unused for now, as well +as the “module `client` is private” error from our binary crate. Modify +*src/lib.rs* to make the `client` module public, like so: + +Filename: src/lib.rs + +```rust,ignore +pub mod client; + +mod network; +``` + +The `pub` goes right before `mod`. Let’s try building again: + +```text + +error: function `connect` is private + --> src/main.rs:4:5 + | +4 | communicator::client::connect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``` + +Hooray! We have a different error! Yes, different error messages are a cause +for celebration. The new error says “function `connect` is private”, so let’s +edit *src/client.rs* to make `client::connect` public too: + +Filename: src/client.rs + +```rust +pub fn connect() { +} +``` + +And run `cargo build` again: + +```text +warning: function is never used: `connect`, #[warn(dead_code)] on by default + --> src/network/mod.rs:1:1 + | +1 | fn connect() { + | ^ + +warning: function is never used: `connect`, #[warn(dead_code)] on by default + --> src/network/server.rs:1:1 + | +1 | fn connect() { + | ^ +``` + +It compiled, and the warning about `client::connect` not being used is gone! + +Unused code warnings don’t always indicate that something needs to be made +public: if you *didn’t* want these functions to be part of your public API, +unused code warnings could be alerting you to code you no longer needed and can +safely delete. They could also be alerting you to a bug, if you had just +accidentally removed all places within your library where this function is +called. + +In our case though, we *do* want the other two functions to be part of our +crate’s public API, so let’s mark them as `pub` as well to try to get rid of +the remaining warnings. Modify *src/network/mod.rs* to be: + +Filename: src/network/mod.rs + +```rust,ignore +pub fn connect() { +} + +mod server; +``` + +And compile: + +```text +warning: function is never used: `connect`, #[warn(dead_code)] on by default + --> src/network/mod.rs:1:1 + | +1 | pub fn connect() { + | ^ + +warning: function is never used: `connect`, #[warn(dead_code)] on by default + --> src/network/server.rs:1:1 + | +1 | fn connect() { + | ^ +``` + +Hmmm, we’re still getting an unused function warning even though +`network::connect` is set to `pub`. This is because the function is public +within the module, but the `network` module that the function resides in is not +public. We’re working from the interior of the library out this time, where +with `client::connect` we worked from the outside in. We need to change +*src/lib.rs* to make `network` public too: + +Filename: src/lib.rs + +```rust,ignore +pub mod client; + +pub mod network; +``` + +Now if we compile, that warning is gone: + +```text +warning: function is never used: `connect`, #[warn(dead_code)] on by default + --> src/network/server.rs:1:1 + | +1 | fn connect() { + | ^ +``` + +Only one warning left! Try to fix this one on your own! + +### Privacy Rules + +Overall, these are the rules for item visibility: + +1. If an item is public, it can be accessed through any of its parent modules. +2. If an item is private, it may be accessed only by the current module and its + child modules. + +### Privacy Examples + +Let’s look at a few more examples to get some practice. Create a new library +project and enter the code in Listing 7-5 into your new project’s *src/lib.rs*: + +
+Filename: src/lib.rs + +```rust,ignore +mod outermost { + pub fn middle_function() {} + + fn middle_secret_function() {} + + mod inside { + pub fn inner_function() {} + + fn secret_function() {} + } +} + +fn try_me() { + outermost::middle_function(); + outermost::middle_secret_function(); + outermost::inside::inner_function(); + outermost::inside::secret_function(); +} +``` + +
+ +Listing 7-5: Examples of private and public functions, some of which are +incorrect + +
+
+ +Before you try to compile this code, make a guess about which lines in `try_me` +function will have errors. Then try compiling to see if you were right, and +read on for discussion of the errors! + +#### Looking at the Errors + +The `try_me` function is in the root module of our project. The module named +`outermost` is private, but the second privacy rule says the `try_me` function +is allowed to access the `outermost` module since `outermost` is in the current +(root) module, as is `try_me`. + +The call to `outermost::middle_function` will work. This is because +`middle_function` is public, and `try_me` is accessing `middle_function` +through its parent module, `outermost`. We determined in the previous paragraph +that this module is accessible. + +The call to `outermost::middle_secret_function` will cause a compilation error. +`middle_secret_function` is private, so the second rule applies. The root +module is neither the current module of `middle_secret_function` (`outermost` +is), nor is it a child module of the current module of `middle_secret_function`. + +The module named `inside` is private and has no child modules, so it can only +be accessed by its current module, `outermost`. That means the `try_me` +function is not allowed to call `outermost::inside::inner_function` or +`outermost::inside::secret_function` either. + +#### Fixing the Errors + +Here are some suggestions for changing the code in an attempt to fix the +errors. Before you try each one, make a guess as to whether it will fix the +errors, then compile to see if you’re right and use the privacy rules to +understand why. + +* What if the `inside` module was public? +* What if `outermost` was public and `inside` was private? +* What if, in the body of `inner_function`, you called + `::outermost::middle_secret_function()`? (The two colons at the beginning mean + that we want to refer to the modules starting from the root module.) + +Feel free to design more experiments and try them out! + +Next, let’s talk about bringing items into a scope with the `use` keyword. + +## Importing Names + +We’ve covered how to call functions defined within a module using the module +name as part of the call, as in the call to the `nested_modules` function shown +here in Listing 7-6. + +
+Filename: src/main.rs + +```rust +pub mod a { + pub mod series { + pub mod of { + pub fn nested_modules() {} + } + } +} + +fn main() { + a::series::of::nested_modules(); +} +``` + +
+ +Listing 7-6: Calling a function by fully specifying its enclosing module’s +namespaces + +
+
+ +As you can see, referring to the fully qualified name can get quite lengthy. +Luckily, Rust has a keyword to make these calls more concise. + +### Concise Imports with `use` + +Rust’s `use` keyword works to shorten lengthy function calls by bringing the +modules of the function you want to call into a scope. Here’s an example of +bringing the `a::series::of` module into a binary crate’s root scope: + +Filename: src/main.rs + +```rust +pub mod a { + pub mod series { + pub mod of { + pub fn nested_modules() {} + } + } +} + +use a::series::of; + +fn main() { + of::nested_modules(); +} +``` + +The line `use a::series::of;` means that rather than using the full +`a::series::of` path wherever we want to refer to the `of` module, we can use +`of`. + +The `use` keyword brings only what we have specified into scope; it does not +bring children of modules into scope. That’s why we still have to say +`of::nested_modules` when we want to call the `nested_modules` function. + +We could have chosen to bring the function itself into scope, by instead +specifying the function in the `use` as follows: + +```rust +pub mod a { + pub mod series { + pub mod of { + pub fn nested_modules() {} + } + } +} + +use a::series::of::nested_modules; + +fn main() { + nested_modules(); +} +``` + +This allows us to exclude all of the modules and reference the function +directly. + +Since enums also form a sort of namespace like modules, we can import an enum’s +variants with `use` as well. For any kind of `use` statement, if you’re +importing multiple items from one namespace, you can list them using curly +braces and commas in the last position, like so: + +```rust +enum TrafficLight { + Red, + Yellow, + Green, +} + +use TrafficLight::{Red, Yellow}; + +fn main() { + let red = Red; + let yellow = Yellow; + let green = TrafficLight::Green; // because we didn’t `use` TrafficLight::Green +} +``` + +### Glob Imports with `*` + +To import all the items in a namespace at once, we can use the `*` syntax. For +example: + +```rust +enum TrafficLight { + Red, + Yellow, + Green, +} + +use TrafficLight::*; + +fn main() { + let red = Red; + let yellow = Yellow; + let green = Green; +} +``` + +The `*` is called a *glob*, and it will import everything that’s visible inside +of the namespace. Globs should be used sparingly: they are convenient, but you +might also pull in more things than you expected and cause naming conflicts. + +### Using `super` to Access a Parent Module + +As you now know, when you create a library crate, Cargo makes a `tests` module +for you. Let’s go into more detail about that now. In your `communicator` +project, open *src/lib.rs*. + +Filename: src/lib.rs + +```rust,ignore +pub mod client; + +pub mod network; + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + } +} +``` + +We’ll explain more about testing in Chapter 12, but parts of this should make +sense now: we have a module named `tests` that lives next to our other modules +and contains one function named `it_works`. Even though there are special +annotations, the `tests` module is just another module! So our module hierarchy +looks like this: + +```text +communicator + ├── client + ├── network + | └── client + └── tests +``` + +Tests are for exercising the code within our library, so let’s try to call our +`client::connect` function from this `it_works` function, even though we’re not +going to be checking any functionality right now: + +Filename: src/lib.rs + +```rust +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + client::connect(); + } +} +``` + +Run the tests by invoking the `cargo test` command: + +```text +$ cargo test + Compiling communicator v0.1.0 (file:///projects/communicator) +error[E0433]: failed to resolve. Use of undeclared type or module `client` + --> src/lib.rs:9:9 + | +9 | client::connect(); + | ^^^^^^^^^^^^^^^ Use of undeclared type or module `client` + +warning: function is never used: `connect`, #[warn(dead_code)] on by default + --> src/network/server.rs:1:1 + | +1 | fn connect() { + | ^ +``` + +The compilation failed, but why? We don’t need to place `communicator::` in +front of the function like we did in *src/main.rs* because we are definitely +within the `communicator` library crate here. The reason is that paths are +always relative to the current module, which here is `tests`. The only +exception is in a `use` statement, where paths are relative to the crate root +by default. Our `tests` module needs the `client` module in its scope! + +So how do we get back up one module in the module hierarchy to be able to call +the `client::connect` function in the `tests` module? In the `tests` module, we +can either use leading colons to let Rust know that we want to start from the +root and list the whole path: + +```rust,ignore +::client::connect(); +``` + +Or we can use `super` to move up one module in the hierarchy from our current +module: + +```rust,ignore +super::client::connect(); +``` + +These two options don’t look all that different in this example, but if you’re +deeper in a module hierarchy, starting from the root every time would get long. +In those cases, using `super` to get from the current module to sibling modules +is a good shortcut. Plus, if you’ve specified the path from the root in many +places in your code and then you rearrange your modules by moving a subtree to +another place, you’d end up needing to update the path in a lot of places, +which would be tedious. + +It would also be annoying to have to type `super::` all the time in each test, +but you’ve already seen the tool for that solution: `use`! The `super::` +functionality changes the path you give to `use` so that it is relative to the +parent module instead of to the root module. + +For these reasons, in the `tests` module especially, `use super::something` is +usually the way to go. So now our test looks like this: + +Filename: src/lib.rs + +```rust +#[cfg(test)] +mod tests { + use super::client; + + #[test] + fn it_works() { + client::connect(); + } +} +``` + +If we run `cargo test` again, the test will pass and the first part of the test +result output will be: + +```text +$ cargo test + Compiling communicator v0.1.0 (file:///projects/communicator) + Running target/debug/communicator-92007ddb5330fa5a + +running 1 test +test tests::it_works ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured +``` + +## Summary + +Now you know techniques for organizing your code! Use these to group related +functionality together, keep files from getting too long, and present a tidy +public API to users of your library. + +Next, let’s look at some collection data structures in the standard library +that you can make use of in your nice, neat code! diff --git a/src/doc/book/second-edition/nostarch/chapter08.md b/src/doc/book/second-edition/nostarch/chapter08.md new file mode 100644 index 0000000000..b8a260cded --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter08.md @@ -0,0 +1,932 @@ + +[TOC] + +# Common Collections + +Rust’s standard library includes a number of really useful data structures +called *collections*. Most other data types represent one specific value, but +collections can contain multiple values. Unlike the built-in array and tuple +types, the data these collections point to is stored on the heap, which means +the amount of data does not need to be known at compile time and can grow or +shrink as the program runs. Each kind of collection has different capabilities +and costs, and choosing an appropriate one for the situation you’re in is a +skill you’ll develop over time. In this chapter, we’ll go over three +collections which are used very often in Rust programs: + +* A *vector* allows us to store a variable number of values next to each other. +* A *string* is a collection of characters. We’ve seen the `String` type + before, but we’ll talk about it in depth now. +* A *hash map* allows us to associate a value with a particular key. It's a + particular implementation of the more general data structure called a *map*. + +To learn about the other kinds of collections provided by the standard library, +see the documentation at *https://doc.rust-lang.org/stable/std/collections*. + +We’re going to discuss how to create and update vectors, strings, and hash +maps, as well as what makes each special. + +## Vectors + +The first type we’ll look at is `Vec`, also known as a *vector*. Vectors +allow us to 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. They are useful in situations where you have a list of items, such +as the lines of text in a file or the prices of items in a shopping cart. + +### Creating a New Vector + +To create a new, empty vector, we can call the `Vec::new` function: + +```rust +let v: Vec = Vec::new(); +``` + +Note that we added a type annotation here. Since we aren’t inserting any values +into this vector, Rust doesn’t know what kind of elements we intend to store. +This is an important point. Vectors are homogeneous: they may store many +values, but those values must all be the same type. Vectors are implemented +using generics, which Chapter 10 will cover how to use in your own types. For +now, all you need to know is that the `Vec` type provided by the standard +library can hold any type, and when a specific `Vec` holds a specific type, the +type goes within angle brackets. We’ve told Rust that the `Vec` in `v` will +hold elements of the `i32` type. + +In real code, Rust can infer the type of value we want to store once we insert +values, so you rarely need to do this type annotation. It’s more common to +create a `Vec` that has initial values, and Rust provides the `vec!` macro for +convenience. The macro will create a new `Vec` that holds the values we give +it. This will create a new `Vec` that holds the values `1`, `2`, and `3`: + +```rust +let v = vec![1, 2, 3]; +``` + +Because we’ve given initial `i32` values, Rust can infer that the type of `v` +is `Vec`, and the type annotation isn’t necessary. Let’s look at how to +modify a vector next. + +### Updating a Vector + +To create a vector then add elements to it, we can use the `push` method: + +```rust +let mut v = Vec::new(); + +v.push(5); +v.push(6); +v.push(7); +v.push(8); +``` + +As with any variable as we discussed in Chapter 3, if we want to be able to +change its value, we need to make it mutable with the `mut` keyword. The +numbers we place inside are all of type `i32`, and Rust infers this from the +data, so we don’t need the `Vec` annotation. + +### Dropping a Vector Drops its Elements + +Like any other `struct`, a vector will be freed when it goes out of scope: + +```rust +{ + let v = vec![1, 2, 3, 4]; + + // do stuff with v + +} // <- v goes out of scope and is freed here +``` + +When the vector gets dropped, all of its contents will also be dropped, meaning +those integers it holds will be cleaned up. This may seem like a +straightforward point, but can get a little more complicated once we start to +introduce references to the elements of the vector. Let’s tackle that next! + +### Reading Elements of Vectors + +Now that you know how to create, update, and destroy vectors, knowing how to +read their contents is a good next step. There are two ways to reference a +value stored in a vector. In the examples, we’ve annotated the types of the +values that are returned from these functions for extra clarity. + +This example shows both methods of accessing a value in a vector either with +indexing syntax or the `get` method: + +```rust +let v = vec![1, 2, 3, 4, 5]; + +let third: &i32 = &v[2]; +let third: Option<&i32> = v.get(2); +``` + +There are a few things to note here. First, that we use the index value of `2` +to get the third element: vectors are indexed by number, starting at zero. +Second, the two different ways to get the third element are: using `&` and +`[]`, which gives us a reference, or using the `get` method with the index +passed as an argument, which gives us an `Option<&T>`. + +The reason Rust has two ways to reference an element is so that you can choose +how the program behaves when you try to use an index value that the vector +doesn’t have an element for. As an example, what should a program do if it has +a vector that holds five elements then tries to access an element at index 100 +like this: + +```rust,should_panic +let v = vec![1, 2, 3, 4, 5]; + +let does_not_exist = &v[100]; +let does_not_exist = v.get(100); +``` + +When you run this, you will find that with the first `[]` method, Rust will +cause a `panic!` when a non-existent element is referenced. This method would +be preferable if you want your program to consider an attempt to access an +element past the end of the vector to be a fatal error that should crash the +program. + +When the `get` method is passed an index that is outside the array, it will +return `None` without panicking. You would use this if accessing an element +beyond the range of the vector will happen occasionally under normal +circumstances. Your code can then have logic to handle having either +`Some(&element)` or `None`, as we discussed in Chapter 6. For example, the +index could be coming from a person entering a number. If they accidentally +enter a number that’s too large and your program gets a `None` value, you could +tell the user how many items are in the current `Vec` and give them another +chance to enter a valid value. That would be more user-friendly than crashing +the program for a typo! + +#### Invalid References + +Once the program has a valid reference, the borrow checker will enforce the +ownership and borrowing rules covered in Chapter 4 to ensure this reference and +any other references to the contents of the vector stay valid. Recall the rule +that says we can’t have mutable and immutable references in the same scope. +That rule applies in this example, where we hold an immutable reference to the +first element in a vector and try to add an element to the end: + +```rust,ignore +let mut v = vec![1, 2, 3, 4, 5]; + +let first = &v[0]; + +v.push(6); +``` + +Compiling this will give us this error: + +``` +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as +immutable + | +4 | let first = &v[0]; + | - immutable borrow occurs here +5 | +6 | v.push(6); + | ^ mutable borrow occurs here +7 | } + | - immutable borrow ends here +``` + +This code might look like it should work: why should a reference to the first +element care about what changes about the end of the vector? The reason why +this code isn’t allowed is due to the way vectors work. Adding a new element +onto the end of the vector might require allocating new memory and copying the +old elements over to the new space, in the circumstance that there isn’t enough +room to put all the elements next to each other where the vector was. In that +case, the reference 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 this, see The Nomicon at +*https://doc.rust-lang.org/stable/nomicon/vec.html*. + +### Using an Enum to Store Multiple Types + +At the beginning of this chapter, we said that vectors can only store values +that are all the same type. This can be inconvenient; there are definitely use +cases for needing to store a list of things of different types. Luckily, the +variants of an enum are all defined under the same enum type, so when we need +to store elements of a different type in a vector, we can define and use an +enum! + +For example, let’s say we want to get values from a row in a spreadsheet, where +some of the columns in the row contain integers, some floating point numbers, +and some strings. We can define an enum whose variants will hold the different +value types, and then all of the enum variants will be considered the same +type, that of the enum. Then we can create a vector that holds that enum and +so, ultimately, holds different types: + +```rust +enum SpreadsheetCell { + Int(i32), + Float(f64), + Text(String), +} + +let row = vec![ + SpreadsheetCell::Int(3), + SpreadsheetCell::Text(String::from("blue")), + SpreadsheetCell::Float(10.12), +]; +``` + +The reason Rust needs to know exactly what types will be in the vector at +compile time is so that it knows exactly how much memory on the heap will be +needed to store each element. A secondary advantage to this is that we can be +explicit about what types are allowed in this vector. If Rust allowed a vector +to hold any type, there would be a chance that one or more of the types would +cause errors with the operations performed on the elements of the vector. Using +an enum plus a `match` means that Rust will ensure at compile time that we +always handle every possible case, as we discussed in Chapter 6. + +If you don’t know at the time that you’re writing a program the exhaustive set +of types the program will get at runtime to store in a vector, the enum +technique won’t work. Instead, you can use a trait object, which we’ll cover in +Chapter 17. + +Now that we’ve gone over some of the most common ways to use vectors, be sure +to take a look at the API documentation for all of the many useful methods +defined on `Vec` by the standard library. For example, in addition to `push` +there’s a `pop` method that will remove and return the last element. Let’s move +on to the next collection type: `String`! + +## Strings + +We’ve already talked about strings a bunch in Chapter 4, but let’s take a more +in-depth look at them now. Strings are an area that new Rustaceans commonly get +stuck on. This is due to a combination of three things: Rust’s propensity for +making sure to expose possible errors, strings being a more complicated data +structure than many programmers give them credit for, and UTF-8. These things +combine in a way that can seem difficult when coming from other languages. + +The reason strings are in the collections chapter is that strings are +implemented as a collection of bytes plus some methods to provide useful +functionality when those bytes are interpreted as text. In this section, we’ll +talk about the operations on `String` that every collection type has, like +creating, updating, and reading. We’ll also discuss the ways in which `String` +is different than the other collections, namely how indexing into a `String` is +complicated by the differences in which people and computers interpret `String` +data. + +### What is a String? + +Before we can dig into those aspects, we need to talk about what exactly we +mean by the term *string*. Rust actually only has one string type in the core +language itself: `str`, the string slice, which is usually seen in its borrowed +form, `&str`. We talked about *string slices* in Chapter 4: these are a +reference to some UTF-8 encoded string data stored elsewhere. String literals, +for example, are stored in the binary output of the program, and are therefore +string slices. + +The type called `String` is provided in Rust’s standard library rather than +coded into the core language, and is a growable, mutable, owned, UTF-8 encoded +string type. When Rustaceans talk about “strings” in Rust, they usually mean +both the `String` and the string slice `&str` types, not just one of those. +This section is largely about `String`, but both these types are used heavily +in Rust’s standard library. Both `String` and string slices are UTF-8 encoded. + +Rust’s standard library also includes a number of other string types, such as +`OsString`, `OsStr`, `CString`, and `CStr`. Library crates may provide even +more options for storing string data. Similar to the `*String`/`*Str` naming, +they often provide an owned and borrowed variant, just like `String`/`&str`. +These string types may store different encodings or be represented in memory in +a different way, for example. We won’t be talking about these other string +types in this chapter; see their API documentation for more about how to use +them and when each is appropriate. + +### Creating a New String + +Many of the same operations available with `Vec` are available with `String` as +well, starting with the `new` function to create a string, like so: + +```rust +let s = String::new(); +``` + +This creates a new empty string called `s` that we can then load data into. + +Often, we’ll have some initial data that we’d like to start the string off +with. For that, we use the `to_string` method, which is available on any type +that implements the `Display` trait, which string literals do: + +```rust +let data = "initial contents"; + +let s = data.to_string(); + +// the method also works on a literal directly: +let s = "initial contents".to_string(); +``` + +This creates a string containing `initial contents`. + +We can also use the function `String::from` to create a `String` from a string +literal. This is equivalent to using `to_string`: + +```rust +let s = String::from("initial contents"); +``` + +Because strings are used for so many things, there are many different generic +APIs that can be used for strings, so there are a lot of options. Some of them +can feel redundant, but they all have their place! In this case, `String::from` +and `.to_string` end up doing the exact same thing, so which you choose is a +matter of style. + +Remember that strings are UTF-8 encoded, so we can include any properly encoded +data in them: + +```rust +let hello = "السلام عليكم"; +let hello = "Dobrý den"; +let hello = "Hello"; +let hello = "שָׁלוֹם"; +let hello = "नमस्ते"; +let hello = "こんにちは"; +let hello = "안녕하세요"; +let hello = "你好"; +let hello = "Olá"; +let hello = "Здравствуйте"; +let hello = "Hola"; +``` + +### Updating a String + +A `String` can grow in size and its contents can change just like the contents +of a `Vec`, by pushing more data into it. In addition, `String` has +concatenation operations implemented with the `+` operator for convenience. + +#### Appending to a String with Push + +We can grow a `String` by using the `push_str` method to append a string slice: + +```rust +let mut s = String::from("foo"); +s.push_str("bar"); +``` + +`s` will contain “foobar” after these two lines. The `push_str` method takes a +string slice because we don’t necessarily want to take ownership of the +parameter. For example, it would be unfortunate if we weren’t able to use `s2` +after appending its contents to `s1`: + +```rust +let mut s1 = String::from("foo"); +let s2 = String::from("bar"); +s1.push_str(&s2); +``` + +The `push` method is defined to have a single character as a parameter and add +it to the `String`: + +```rust +let mut s = String::from("lo"); +s.push('l'); +``` + +After this, `s` will contain “lol”. + +#### Concatenation with the + Operator or the `format!` Macro + +Often, we’ll want to combine two existing strings together. One way is to use +the `+` operator like this: + +```rust +let s1 = String::from("Hello, "); +let s2 = String::from("world!"); +let s3 = s1 + &s2; // Note that s1 has been moved here and can no longer be used +``` + +After this code the String `s3` will contain `Hello, world!`. The reason that +`s1` is no longer valid after the addition and the reason that we used a +reference to `s2` has to do with the signature of the method that gets called +when we use the `+` operator. The `+` operator uses the `add` method, whose +signature looks something like this: + +``` +fn add(self, s: &str) -> String { +``` + +This isn’t the exact signature that’s in the standard library; there `add` is +defined using generics. Here, we’re looking at the signature of `add` with +concrete types substituted for the generic ones, which is what happens when we +call this method with `String` values. We'll be discussing generics in Chapter +10. This signature gives us the clues we need to understand the tricky bits of +the `+` operator. + +First of all, `s2` has an `&`, meaning that we are adding a *reference* of the +second string to the first string. This is because of the `s` parameter in the +`add` function: we can only add a `&str` to a `String`, we can’t add two +`String` values together. Remember back in Chapter 4 when we talked about how +`&String` will coerce to `&str`: we write `&s2` so that the `String` will +coerce to the proper type, `&str`. Because this method does not take ownership +of the parameter, `s2` will still be valid after this operation. + +Second, we can see in the signature that `add` takes ownership of `self`, +because `self` does *not* have an `&`. This means `s1` in the above example +will be moved into the `add` call and no longer be valid after that. So while +`let s3 = s1 + &s2;` looks like it will copy both strings and create a new one, +this statement actually takes ownership of `s1`, appends a copy of the contents +of `s2`, then returns ownership of the result. In other words, it looks like +it’s making a lot of copies, but isn’t: the implementation is more efficient +than copying. + +If we need to concatenate multiple strings, the behavior of `+` gets unwieldy: + +```rust +let s1 = String::from("tic"); +let s2 = String::from("tac"); +let s3 = String::from("toe"); + +let s = s1 + "-" + &s2 + "-" + &s3; +``` + +`s` will be “tic-tac-toe” at this point. With all of the `+` and `"` +characters, it gets hard to see what’s going on. For more complicated string +combining, we can use the `format!` macro: + +```rust +let s1 = String::from("tic"); +let s2 = String::from("tac"); +let s3 = String::from("toe"); + +let s = format!("{}-{}-{}", s1, s2, s3); +``` + +This code will also set `s` to “tic-tac-toe”. The `format!` macro works in the +same way as `println!`, but instead of printing the output to the screen, it +returns a `String` with the contents. This version is much easier to read, and +also does not take ownership of any of its parameters. + +### Indexing into Strings + +In many other languages, accessing individual characters in a string by +referencing them by index is a valid and common operation. In Rust, however, if +we try to access parts of a `String` using indexing syntax, we’ll get an error. +That is, this code: + +```rust,ignore +let s1 = String::from("hello"); +let h = s1[0]; +``` + +will result in this error: + +```text +error: the trait bound `std::string::String: std::ops::Index<_>` is not +satisfied [--explain E0277] + |> + |> let h = s1[0]; + |> ^^^^^ +note: the type `std::string::String` cannot be indexed by `_` +``` + +The error and the note tell the story: Rust strings don’t support indexing. So +the follow-up question is, why not? In order to answer that, we have to talk a +bit about how Rust stores strings in memory. + +#### Internal Representation + +A `String` is a wrapper over a `Vec`. Let’s take a look at some of our +properly-encoded UTF-8 example strings from before. First, this one: + +```rust +let len = String::from("Hola").len(); +``` + +In this case, `len` will be four, which means the `Vec` storing the string +“Hola” is four bytes long: each of these letters takes one byte when encoded in +UTF-8. What about this example, though? + +```rust +let len = String::from("Здравствуйте").len(); +``` + +A person asked how long the string is might say 12. However, Rust’s answer is +24. This is the number of bytes that it takes to encode “Здравствуйте” in +UTF-8, since each Unicode scalar value takes two bytes of storage. Therefore, +an index into the string’s bytes will not always correlate to a valid Unicode +scalar value. + +To demonstrate, consider this invalid Rust code: + +```rust,ignore +let hello = "Здравствуйте"; +let answer = &hello[0]; +``` + +What should the value of `answer` be? Should it be `З`, the first letter? When +encoded in UTF-8, the first byte of `З` is `208`, and the second is `151`, so +`answer` should in fact be `208`, but `208` is not a valid character on its +own. Returning `208` is likely not what a person would want if they asked for +the first letter of this string, but that’s the only data that Rust has at byte +index 0. Returning the byte value is probably not what people want, even with +only Latin letters: `&"hello"[0]` would return `104`, not `h`. To avoid +returning an unexpected value and causing bugs that might not be discovered +immediately, Rust chooses to not compile this code at all and prevent +misunderstandings earlier. + +#### Bytes and Scalar Values and Grapheme Clusters! Oh my! + +This leads to another point about UTF-8: there are really three relevant ways +to look at strings, from Rust’s perspective: as bytes, scalar values, and +grapheme clusters (the closest thing to what people would call *letters*). + +If we look at the Hindi word “नमस्ते” written in the Devanagari script, it is +ultimately stored as a `Vec` of `u8` values that looks like this: + +``` +[224, 164, 168, 224, 164, 174, 224, 164, 184, 224, 165, 141, 224, 164, 164, +224, 165, 135] +``` + +That’s 18 bytes, and is how computers ultimately store this data. If we look at +them as Unicode scalar values, which are what Rust’s `char` type is, those +bytes look like this: + +```text +['न', 'म', 'स', '्', 'त', 'े'] +``` + +There are six `char` values here, but the fourth and sixth are not letters, +they’re diacritics that don’t make sense on their own. Finally, if we look at +them as grapheme clusters, we’d get what a person would call the four letters +that make up this word: + +```text +["न", "म", "स्", "ते"] +``` + +Rust provides different ways of interpreting the raw string data that computers +store so that each program can choose the interpretation it needs, no matter +what human language the data is in. + +A final reason Rust does not allow you to index into a `String` to get a +character is that indexing operations are expected to always take constant time +(O(1)). It isn’t possible to guarantee that performance with a `String`, +though, since Rust would have to walk through the contents from the beginning +to the index to determine how many valid characters there were. + +### Slicing Strings + +Because it's not clear what the return type of string indexing should be, and +it is often a bad idea to index into a string, Rust dissuades you from doing so +by asking you to be more specific if you really need it. The way you can be +more specific than indexing using `[]` with a single number is using `[]` with +a range to create a string slice containing particular bytes: + +```rust +let hello = "Здравствуйте"; + +let s = &hello[0..4]; +``` + +Here, `s` will be a `&str` that contains the first four bytes of the string. +Earlier, we mentioned that each of these characters was two bytes, so that +means that `s` will be “Зд”. + +What would happen if we did `&hello[0..1]`? The answer: it will panic at +runtime, in the same way that accessing an invalid index in a vector does: + +```text +thread 'main' panicked at 'index 0 and/or 1 in `Здравствуйте` do not lie on +character boundary', ../src/libcore/str/mod.rs:1694 +``` + +You should use this with caution, since it can cause your program to crash. + +### Methods for Iterating Over Strings + +Luckily, there are other ways we can access elements in a String. + +If we need to perform operations on individual Unicode scalar values, the best +way to do so is to use the `chars` method. Calling `chars` on “नमस्ते” +separates out and returns six values of type `char`, and you can iterate over +the result in order to access each element: + +```rust +for c in "नमस्ते".chars() { + println!("{}", c); +} +``` + +This code will print: + +```text +न +म +स +् +त +े +``` + +The `bytes` method returns each raw byte, which might be appropriate for your +domain: + +```rust +for b in "नमस्ते".bytes() { + println!("{}", b); +} +``` + +This code will print the 18 bytes that make up this `String`, starting with: + +```text +224 +164 +168 +224 +// ... etc +``` + +But make sure to remember that valid Unicode scalar values may be made up of +more than one byte. + +Getting grapheme clusters from strings is complex, so this functionality is not +provided by the standard library. There are crates available on crates.io if +this is the functionality you need. + +### Strings are Not so Simple + +To summarize, strings are complicated. Different programming languages make +different choices about how to present this complexity to the programmer. Rust +has chosen to make the correct handling of `String` data the default behavior +for all Rust programs, which does mean programmers have to put more thought +into handling UTF-8 data upfront. This tradeoff exposes more of the complexity +of strings than other programming languages do, but this will prevent you from +having to handle errors involving non-ASCII characters later in your +development lifecycle. + +Let’s switch to something a bit less complex: hash map! + +## Hash Maps + +The last of our common collections is the *hash map*. The type `HashMap` +stores a mapping of keys of type `K` to values of type `V`. It does this via a +*hashing function*, which determines how it places these keys and values into +memory. Many different programming languages support this kind of data +structure, but often with a different name: hash, map, object, hash table, or +associative array, just to name a few. + +Hash maps are useful for when you want to be able to look up data not by an +index, as you can with vectors, but by using a key that can be of any type. For +example, in a game, you could keep track of each team’s score in a hash map +where each key is a team’s name and the values are each team’s score. Given a +team name, you can retrieve their score. + +We’ll go over the basic API of hash maps in this chapter, but there are many +more goodies hiding in the functions defined on `HashMap` by the standard +library. As always, check the standard library documentation for more +information. + +### Creating a New Hash Map + +We can create an empty `HashMap` with `new`, and add elements with `insert`. +Here we’re keeping track of the scores of two teams whose names are Blue and +Yellow. The Blue team will start with 10 points and the Yellow team starts with +50: + +```rust +use std::collections::HashMap; + +let mut scores = HashMap::new(); + +scores.insert(String::from("Blue"), 10); +scores.insert(String::from("Yellow"), 50); +``` + +Note that we need to first `use` the `HashMap` from the collections portion of +the standard library. Of our three common collections, this one is the least +often used, so it’s not included in the features imported automatically in the +prelude. Hash maps also have less support from the standard library; there’s no +built-in macro to construct them, for example. + +Just like vectors, hash maps store their data on the heap. This `HashMap` has +keys of type `String` and values of type `i32`. Like vectors, hash maps are +homogeneous: all of the keys must have the same type, and all of the values +must have the same type. + +Another way of constructing a hash map is by using the `collect` method on a +vector of tuples, where each tuple consists of a key and its value. The +`collect` method gathers up data into a number of collection types, including +`HashMap`. For example, if we had the team names and initial scores in two +separate vectors, we can use the `zip` method to create a vector of tuples +where “Blue” is paired with 10, and so forth. Then we can use the `collect` +method to turn that vector of tuples into a `HashMap`: + +```rust +use std::collections::HashMap; + +let teams = vec![String::from("Blue"), String::from("Yellow")]; +let initial_scores = vec![10, 50]; + +let scores: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect(); +``` + +The type annotation `HashMap<_, _>` is needed here because it’s possible to +`collect` into many different data structures, and Rust doesn’t know which you +want unless you specify. For the type parameters for the key and value types, +however, we use underscores and Rust can infer the types that the hash map +contains based on the types of the data in the vector. + +### Hash Maps and Ownership + +For types that implement the `Copy` trait, like `i32`, the values are copied +into the hash map. For owned values like `String`, the values will be moved and +the hash map will be the owner of those values: + +```rust +use std::collections::HashMap; + +let field_name = String::from("Favorite color"); +let field_value = String::from("Blue"); + +let mut map = HashMap::new(); +map.insert(field_name, field_value); +// field_name and field_value are invalid at this point +``` + +We would not be able to use the bindings `field_name` and `field_value` after +they have been moved into the hash map with the call to `insert`. + +If we insert references to values into the hash map, the values themselves will +not be moved into the hash map. The values that the references point to must be +valid for at least as long as the hash map is valid, though. We will talk more +about these issues in the Lifetimes section of Chapter 10. + +### Accessing Values in a Hash Map + +We can get a value out of the hash map by providing its key to the `get` method: + +```rust +use std::collections::HashMap; + +let mut scores = HashMap::new(); + +scores.insert(String::from("Blue"), 10); +scores.insert(String::from("Yellow"), 50); + +let team_name = String::from("Blue"); +let score = scores.get(&team_name); +``` + +Here, `score` will have the value that’s associated with the Blue team, and the +result will be `Some(10)`. The result is wrapped in `Some` because `get` +returns an `Option`; if there’s no value for that key in the hash map, `get` +will return `None`. The program will need to handle the `Option` in one of the +ways that we covered in Chapter 6. + +We can iterate over each key/value pair in a hash map in a similar manner as we +do with vectors, using a `for` loop: + +```rust +use std::collections::HashMap; + +let mut scores = HashMap::new(); + +scores.insert(String::from("Blue"), 10); +scores.insert(String::from("Yellow"), 50); + +for (key, value) in &scores { + println!("{}: {}", key, value); +} +``` + +This will print each pair, in an arbitrary order: + +```text +Yellow: 50 +Blue: 10 +``` + +### Updating a Hash Map + +While the number of keys and values is growable, each individual key can only +have one value associated with it at a time. When we want to change the data in +a hash map, we have to decide how to handle the case when a key already has a +value assigned. We could choose to replace the old value with the new value, +completely disregarding the old value. We could choose to keep the old value +and ignore the new value, and only add the new value if the key *doesn’t* +already have a value. Or we could combine the old value and the new value. +Let’s look at how to do each of these! + +#### Overwriting a Value + +If we insert a key and a value into a hash map, then insert that same key with +a different value, the value associated with that key will be replaced. Even +though this following code calls `insert` twice, the hash map will only contain +one key/value pair because we’re inserting the value for the Blue team’s key +both times: + +```rust +use std::collections::HashMap; + +let mut scores = HashMap::new(); + +scores.insert(String::from("Blue"), 10); +scores.insert(String::from("Blue"), 25); + +println!("{:?}", scores); +``` + +This will print `{"Blue": 25}`. The original value of 10 has been overwritten. + +#### Only Insert If the Key Has No Value + +It’s common to want to check if a particular key has a value and, if it does +not, insert a value for it. Hash maps have a special API for this, called +`entry`, that takes the key we want to check as an argument. The return value +of the `entry` function is an enum, `Entry`, that represents a value that might +or might not exist. Let’s say that we want to check if the key for the Yellow +team has a value associated with it. If it doesn’t, we want to insert the value +50, and the same for the Blue team. With the entry API, the code for this looks +like: + +```rust +use std::collections::HashMap; + +let mut scores = HashMap::new(); +scores.insert(String::from("Blue"), 10); + +scores.entry(String::from("Yellow")).or_insert(50); +scores.entry(String::from("Blue")).or_insert(50); + +println!("{:?}", scores); +``` + +The `or_insert` method on `Entry` returns the value for the corresponding +`Entry` key if it exists, and if not, inserts its argument as the new value for +this key and returns the modified `Entry`. This is much cleaner than writing +the logic ourselves, and in addition, plays more nicely with the borrow checker. + +This code will print `{"Yellow": 50, "Blue": 10}`. The first call to `entry` +will insert the key for the Yellow team with the value 50, since the Yellow +team doesn’t have a value already. The second call to `entry` will not change +the hash map since the Blue team already has the value 10. + +#### Update a Value Based on the Old Value + +Another common use case for hash maps is to look up a key’s value then update +it, based on the old value. For instance, if we wanted to count how many times +each word appeared in some text, we could use a hash map with the words as keys +and increment the value to keep track of how many times we’ve seen that word. +If this is the first time we’ve seen a word, we’ll first insert the value `0`. + +```rust +use std::collections::HashMap; + +let text = "hello world wonderful world"; + +let mut map = HashMap::new(); + +for word in text.split_whitespace() { + let count = map.entry(word).or_insert(0); + *count += 1; +} + +println!("{:?}", map); +``` + +This will print `{"world": 2, "hello": 1, "wonderful": 1}`. The `or_insert` +method actually returns a mutable reference (`&mut V`) to the value for this +key. Here we store that mutable reference in the `count` variable, so in order +to assign to that value we must first dereference `count` using the asterisk +(`*`). The mutable reference goes out of scope at the end of the `for` loop, so +all of these changes are safe and allowed by the borrowing rules. + +### Hashing Function + +By default, `HashMap` uses a cryptographically secure hashing function that can +provide resistance to Denial of Service (DoS) attacks. This is not the fastest +hashing algorithm out there, but the tradeoff for better security that comes +with the drop in performance is worth it. If you profile your code and find +that the default hash function is too slow for your purposes, you can switch to +another function by specifying a different *hasher*. A hasher is a type that +implements the `BuildHasher` trait. We’ll be talking about traits and how to +implement them in Chapter 10. You don't necessarily have to implement your own +hasher from scratch; crates.io has libraries that others have shared that +provide hashers implementing many common hashing algorithms. + +## Summary + +Vectors, strings, and hash maps will take you far in programs where you need to +store, access, and modify data. Here are some exercises you should now be +equipped to solve: + +* Given a list of integers, use a vector and return the mean (average), median + (when sorted, the value in the middle position), and mode (the value that + occurs most often; a hash map will be helpful here) of the list. +* Convert strings to Pig Latin, where the first consonant of each word is moved + to the end of the word with an added “ay”, so “first” becomes “irst-fay”. + Words that start with a vowel get “hay” added to the end instead (“apple” + becomes “apple-hay”). Remember about UTF-8 encoding! +* Using a hash map and vectors, create a text interface to allow a user to add + employee names to a department in the company. For example, “Add Sally to + Engineering” or “Add Amir to Sales”. Then let the user retrieve a list of all + people in a department or all people in the company by department, sorted + alphabetically. + +The standard library API documentation describes methods these types have that +will be helpful for these exercises! + +We’re getting into more complex programs where operations can fail, which means +it’s a perfect time to go over error handling next! diff --git a/src/doc/book/second-edition/nostarch/chapter09.md b/src/doc/book/second-edition/nostarch/chapter09.md new file mode 100644 index 0000000000..363ff26b53 --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter09.md @@ -0,0 +1,935 @@ + +[TOC] + +# Error Handling + +Rust’s commitment to reliability extends to error handling. Errors are a fact +of life in software, so Rust has a number of features for handling situations +in which something goes wrong. In many cases, Rust will require you to +acknowledge the possibility of an error occurring and take some action before +your code will compile. This makes your program more robust by ensuring that +you won’t only discover errors after you’ve deployed your code to production. + +Rust groups errors into two major categories: *recoverable* and *unrecoverable* +errors. Recoverable errors are situations when it’s usually reasonable to +report the problem to the user and retry the operation, like a file not being +found. Unrecoverable errors are always symptoms of bugs, like trying to access +a location beyond the end of an array. + +Most languages don’t distinguish between the 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 +the `panic!` macro that stops execution when it encounters unrecoverable +errors. This chapter will cover calling `panic!` first, then talk about +returning `Result` values. Finally, we’ll discuss considerations to take +into account when deciding whether to try to recover from an error or to stop +execution. + +## Unrecoverable Errors with `panic!` + +Sometimes, bad things happen, and there’s nothing that you can do about it. For +these cases, Rust has the `panic!` macro. When this macro executes, your +program will print a failure message, unwind and clean up the stack, and then +quit. The most common situation this occurs in is when a bug of some kind has +been detected and it’s not clear to the programmer how to handle the error. + +> ### Unwinding the Stack Versus Aborting on Panic +> +> By default, when a `panic!` occurs, the program starts +> *unwinding*, which means Rust walks back up the stack and cleans up the data +> from each function it encounters, but this walking and cleanup is a lot of +> work. The alternative is to immediately *abort*, which ends the program +> without cleaning up. Memory that the program was using will then need to be +> cleaned up by the operating system. If in your project you need to make the +> resulting binary as small as possible, you can switch from unwinding to +> aborting on panic by adding `panic = 'abort'` to the appropriate `[profile]` +> sections in your *Cargo.toml*. For example, if you want to abort on panic in +> release mode: +> +> ```toml +> [profile.release] +> panic = 'abort' +> ``` + +Let’s try calling `panic!` with a simple program: + +Filename: src/main.rs + +```rust,should_panic +fn main() { + panic!("crash and burn"); +} +``` + +If you run it, you’ll see something like this: + +```text +$ cargo run + Compiling panic v0.1.0 (file:///projects/panic) + Finished debug [unoptimized + debuginfo] target(s) in 0.25 secs + Running `target/debug/panic` +thread 'main' panicked at 'crash and burn', src/main.rs:2 +note: Run with `RUST_BACKTRACE=1` for a backtrace. +error: Process didn't exit successfully: `target/debug/panic` (exit code: 101) +``` + +The last three lines contain the error message caused by the call to `panic!`. +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. + +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 be in +code that our code calls. The filename and line number reported by the error +message will be someone else’s code where the `panic!` macro is called, not the +line of our code that eventually led to the `panic!`. We can use the backtrace +of the functions the `panic!` call came from to figure this out. + +### Using a `panic!` Backtrace + +Let’s look at another example to see what it’s like when a `panic!` call comes +from a library because of a bug in our code instead of from our code calling +the macro directly: + +Filename: src/main.rs + +```rust,should_panic +fn main() { + let v = vec![1, 2, 3]; + + v[100]; +} +``` + +We’re attempting to access the hundredth element of our vector, but it only has +three elements. In this situation, Rust will panic. Using `[]` is supposed to +return an element, but if you pass an invalid index, there’s no element that +Rust could return here that would be correct. + +Other languages like C will attempt to give you exactly what you asked for in +this situation, even though it isn’t what you want: you’ll get whatever is at +the location in memory that would correspond to that element in the vector, +even though the memory doesn’t belong to the vector. This is called a *buffer +overread*, and can lead to security vulnerabilities if an attacker can +manipulate the index in such a way as to read data they shouldn’t be allowed to +that is stored after the array. + +In order to protect your program from this sort of vulnerability, if you try to +read an element at an index that doesn’t exist, Rust will stop execution and +refuse to continue. Let’s try it and see: + +```text +$ cargo run + Compiling panic v0.1.0 (file:///projects/panic) + Finished debug [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 +note: Run with `RUST_BACKTRACE=1` for a backtrace. +error: Process didn't exit successfully: `target/debug/panic` (exit code: 101) +``` + +This 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. + +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. Let’s +try that. Listing 9-1 shows output similar to what you'll see: + +
+ +```text +$ RUST_BACKTRACE=1 cargo run + Finished debug [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', /stable-dist-rustc/build/src/libcollections/vec.rs:1395 +stack backtrace: + 1: 0x10922522c - +std::sys::imp::backtrace::tracing::imp::write::h1204ab053b688140 + 2: 0x10922649e - +std::panicking::default_hook::{{closure}}::h1204ab053b688140 + 3: 0x109226140 - std::panicking::default_hook::h1204ab053b688140 + 4: 0x109226897 - +std::panicking::rust_panic_with_hook::h1204ab053b688140 + 5: 0x1092266f4 - std::panicking::begin_panic::h1204ab053b688140 + 6: 0x109226662 - std::panicking::begin_panic_fmt::h1204ab053b688140 + 7: 0x1092265c7 - rust_begin_unwind + 8: 0x1092486f0 - core::panicking::panic_fmt::h1204ab053b688140 + 9: 0x109248668 - +core::panicking::panic_bounds_check::h1204ab053b688140 + 10: 0x1092205b5 - as +core::ops::Index>::index::h1204ab053b688140 + 11: 0x10922066a - panic::main::h1204ab053b688140 + 12: 0x1092282ba - __rust_maybe_catch_panic + 13: 0x109226b16 - std::rt::lang_start::h1204ab053b688140 + 14: 0x1092206e9 - main +``` + +
+ +Listing 9-1: The backtrace generated by a call to `panic!` displayed when the +environment variable `RUST_BACKTRACE` is set + +
+
+ +That’s a lot of output! Line 11 of the backtrace points to the line in our +project causing the problem: *src/main.rs*, line four. A backtrace is a list of +all the functions that have been called to get to this point. Backtraces in +Rust work like they do in other languages: the key to reading the backtrace is +to start from the top and read until you see files you wrote. That’s the spot +where the problem originated. The lines above the lines mentioning your files +are code that your code called; the lines below are code that called your code. +These lines might include core Rust code, standard library code, or crates that +you’re using. + +If we don’t want our program to panic, the location pointed to by the first +line mentioning a file we wrote is where we should start investigating in order +to figure out how we got to this location with values that caused the panic. In +our example 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 try to +request an element at index 100 from a vector that only contains three items. +When your code panics in the future, you’ll need to figure out for your +particular case what action the code is taking with what values that causes the +panic and what the code should do instead. + +We’ll come back to `panic!` and when we should and should not use these methods +later in the chapter. Next, we’ll now look at how to recover from an error with +`Result`. + +## Recoverable Errors with `Result` + +Most errors aren’t serious enough to require the program to stop entirely. +Sometimes, when a function fails, it’s for a reason that we can easily +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 from Chapter 2 the section on “Handling Potential Failure with the +`Result` Type” that the `Result` enum is defined as having two variants, `Ok` +and `Err`, as follows: + +```rust +enum Result { + Ok(T), + Err(E), +} +``` + +The `T` and `E` are generic type parameters; we’ll go into generics in more +detail in Chapter 10. What you need to know right now is that `T` represents +the type of the value that will be returned in a success case within the `Ok` +variant, and `E` represents the type of the error that will be returned in a +failure case within the `Err` variant. Because `Result` has these generic type +parameters, we can use the `Result` type and the functions that the standard +library has defined on it in many different situations where the successful +value and error value we want to return may differ. + +Let’s call a function that returns a `Result` value because the function could +fail: opening a file, shown in Listing 9-2. + +
+Filename: src/main.rs + +```rust +use std::fs::File; + +fn main() { + let f = File::open("hello.txt"); +} +``` + +
+ +Listing 9-2: Opening a file + +
+
+ +How do we know `File::open` returns a `Result`? We could look at the standard +library API documentation, or we could ask the compiler! If we give `f` a type +annotation of some type that we know the return type of the function is *not*, +then we try to compile the code, the compiler will tell us that the types don’t +match. The error message will then tell us what the type of `f` *is*! Let’s try +it: we know that the return type of `File::open` isn’t of type `u32`, so let’s +change the `let f` statement to: + +```rust,ignore +let f: u32 = File::open("hello.txt"); +``` + +Attempting to compile now gives us: + +```text +error[E0308]: mismatched types + --> src/main.rs:4:18 + | +4 | let f: u32 = File::open("hello.txt"); + | ^^^^^^^^^^^^^^^^^^^^^^^ expected u32, found enum +`std::result::Result` + | + = note: expected type `u32` + = note: found type `std::result::Result` +``` + +This tells us the return type of the `File::open` function is a `Result`. +The generic parameter `T` has been filled in here with the type of the success +value, `std::fs::File`, which is a file handle. The type of `E` used in the +error value is `std::io::Error`. + +This return type means the call to `File::open` might succeed and return to us +a file handle that we can read from or write to. The function call also might +fail: for example, the file might not exist, or we might not have permission to +access the file. The `File::open` function needs to have a way to tell us +whether it succeeded or failed, and at the same time give us either the file +handle or error information. This information is exactly what the `Result` enum +conveys. + +In the case where `File::open` succeeds, the value we will have in the variable +`f` will be an instance of `Ok` that contains a file handle. In the case where +it fails, the value in `f` will be an instance of `Err` that contains more +information about the kind of error that happened. + +We need to add to the code from Listing 9-2 to take different actions depending +on the value `File::open` returned. Listing 9-3 shows one way to handle the +`Result` with a basic tool: the `match` expression that we learned about in +Chapter 6. + +
+Filename: src/main.rs + +```rust,should_panic +use std::fs::File; + +fn main() { + let f = File::open("hello.txt"); + + let f = match f { + Ok(file) => file, + Err(error) => { + panic!("There was a problem opening the file: {:?}", error) + }, + }; +} +``` + +
+ +Listing 9-3: Using a `match` expression to handle the `Result` variants we +might have + +
+
+ +Note that, like the `Option` enum, the `Result` enum and its variants have been +imported in the prelude, so we don’t need to specify `Result::` before the `Ok` +and `Err` variants in the `match` arms. + +Here we tell Rust that when the result is `Ok`, return the inner `file` value +out of the `Ok` variant, and we then assign that file handle value to the +variable `f`. After the `match`, we can then use the file handle for reading or +writing. + +The other arm of the `match` handles the case where we get an `Err` value from +`File::open`. In this example, we’ve chosen to call the `panic!` macro. If +there’s no file named *hello.txt* in our current directory and we run this +code, we’ll see the following output from the `panic!` macro: + +```text +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 +``` + +### Matching on Different Errors + +The code in Listing 9-3 will `panic!` no matter the reason that `File::open` +failed. What we’d really like to do instead is take different actions for +different failure reasons: if `File::open` failed because the file doesn’t +exist, we want to create the file and return the handle to the new file. If +`File::open` failed for any other reason, for example because we didn’t have +permission to open the file, we still want to `panic!` in the same way as we +did in Listing 9-3. Let’s look at Listing 9-4, which adds another arm to the +`match`: + +
+Filename: src/main.rs + +```rust,ignore +use std::fs::File; +use std::io::ErrorKind; + +fn main() { + let f = File::open("hello.txt"); + + let f = match f { + Ok(file) => file, + Err(ref error) if error.kind() == ErrorKind::NotFound => { + match File::create("hello.txt") { + Ok(fc) => fc, + Err(e) => { + panic!( + "Tried to create file but there was a problem: {:?}", + e + ) + }, + } + }, + Err(error) => { + panic!( + "There was a problem opening the file: {:?}", + error + ) + }, + }; +} +``` + +
+ +Listing 9-4: Handling different kinds of errors in different ways + +
+
+ +The type of the value that `File::open` returns inside the `Err` variant is +`io::Error`, which is a struct provided by the standard library. This struct +has a method `kind` that we can call to get an `io::ErrorKind` value. +`io::ErrorKind` is an enum provided by the standard library that has variants +representing the different kinds of errors that might result from an `io` +operation. The variant we’re interested in is `ErrorKind::NotFound`, which +indicates the file we’re trying to open doesn’t exist yet. + +The condition `if error.kind() == ErrorKind::NotFound` is called a *match +guard*: it’s an extra condition on a `match` arm that further refines the arm’s +pattern. This condition must be true in order for that arm’s code to get run; +otherwise, the pattern matching will move on to consider the next arm in the +`match`. The `ref` in the pattern is needed so that `error` is not moved into +the guard condition but is merely referenced by it. The reason `ref` is used to +take a reference in a pattern instead of `&` will be covered in detail in +Chapter 18. In short, in the context of a pattern, `&` matches a reference and +gives us its value, but `ref` matches a value and gives us a reference to it. + +The condition we want to check in the match guard is whether the value returned +by `error.kind()` is the `NotFound` variant of the `ErrorKind` enum. If it is, +we try to create the file with `File::create`. However, since `File::create` +could also fail, we need to add an inner `match` statement as well! When the +file can’t be opened, a different error message will be printed. The last arm +of the outer `match` stays the same so that the program panics on any error +besides the missing file error. + +### Shortcuts for Panic on Error: `unwrap` and `expect` + +Using `match` works well enough, but it can be a bit verbose and doesn’t always +communicate intent well. The `Result` type has many helper methods +defined on it to do various things. One of those methods, called `unwrap`, is a +shortcut method that is implemented just like the `match` statement we wrote in +Listing 9-3. If the `Result` value is the `Ok` variant, `unwrap` will return +the value inside the `Ok`. If the `Result` is the `Err` variant, `unwrap` will +call the `panic!` macro for us. + +```rust,should_panic +use std::fs::File; + +fn main() { + let f = File::open("hello.txt").unwrap(); +} +``` + +If we run this code without a *hello.txt* file, we’ll see an error message from +the `panic!` call that the `unwrap` method makes: + +```text +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 +``` + +There’s another method similar to `unwrap` that lets us also choose the +`panic!` error message: `expect`. Using `expect` instead of `unwrap` and +providing good error messages can convey your intent and make tracking down the +source of a panic easier. The syntax of `expect` looks like this: + +```rust,should_panic +use std::fs::File; + +fn main() { + let f = File::open("hello.txt").expect("Failed to open hello.txt"); +} +``` + +We use `expect` in the same way as `unwrap`: to return the file handle or call +the `panic!` macro. The error message that `expect` uses in its call to +`panic!` will be the parameter that we pass to `expect` instead of the default +`panic!` message that `unwrap` uses. Here’s what it looks like: + +```text +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 +``` + +### Propagating Errors + +When writing a function whose implementation calls something that might fail, +instead of handling the error within this function, you can choose to let your +caller know about the error so they can decide what to do. This is known as +*propagating* the error, and gives more control to the calling code where there +might be more information or logic that dictates how the error should be +handled than what you have available in the context of your code. + +For example, Listing 9-5 shows a function that reads a username from a file. If +the file doesn’t exist or can’t be read, this function will return those errors +to the code that called this function: + +
+ +```rust +use std::io; +use std::io::Read; +use std::fs::File; + +fn read_username_from_file() -> Result { + let f = File::open("hello.txt"); + + let mut f = match f { + Ok(file) => file, + Err(e) => return Err(e), + }; + + let mut s = String::new(); + + match f.read_to_string(&mut s) { + Ok(_) => Ok(s), + Err(e) => Err(e), + } +} +``` + +
+ +Listing 9-5: A function that returns errors to the calling code using `match` + +
+
+ +Let’s look at the return type of the function first: `Result`. This means that the function is returning a value of the type +`Result` where the generic parameter `T` has been filled in with the +concrete type `String`, and the generic type `E` has been filled in with the +concrete type `io::Error`. If this function succeeds without any problems, the +caller of this function will receive an `Ok` value that holds a `String` — the +username that this function read from the file. If this function encounters any +problems, the caller of this function will receive an `Err` value that holds an +instance of `io::Error` that contains more information about what the problems +were. We chose `io::Error` as the return type of this function because that +happens to be the type of the error value returned from both of the operations +we’re calling in this function’s body that might fail: the `File::open` +function and the `read_to_string` method. + +The body of the function starts by calling the `File::open` function. Then we +handle the `Result` value returned with a `match` similar to the `match` in +Listing 9-3, only instead of calling `panic!` in the `Err` case, we return +early from this function and pass the error value from `File::open` back to the +caller as this function’s error value. If `File::open` succeeds, we store the +file handle in the variable `f` and continue. + +Then we create a new `String` in variable `s` and call the `read_to_string` +method on the file handle in `f` in order to read the contents of the file into +`s`. The `read_to_string` method also returns a `Result` because it might fail, +even though `File::open` succeeded. So we need another `match` to handle that +`Result`: if `read_to_string` succeeds, then our function has succeeded, and we +return the username from the file that’s now in `s` wrapped in an `Ok`. If +`read_to_string` fails, we return the error value in the same way that we +returned the error value in the `match` that handled the return value of +`File::open`. We don’t need to explicitly say `return`, however, since this is +the last expression in the function. + +The code that calls this code will then handle getting either an `Ok` value +that contains a username or an `Err` value that contains an `io::Error`. We +don’t know what the caller will do with those values. If they get an `Err` +value, they could choose to call `panic!` and crash their program, use a +default username, or look up the username from somewhere other than a file, for +example. We don’t have enough information on what the caller is actually trying +to do, so we propagate all the success or error information upwards for them to +handle as they see fit. + +This pattern of propagating errors is so common in Rust that there is dedicated +syntax to make this easier: `?`. + +### A Shortcut for Propagating Errors: `?` + +Listing 9-6 shows an implementation of `read_username_from_file` that has the +same functionality as it had in Listing 9-5, but this implementation uses the +question mark operator: + +
+ +```rust +use std::io; +use std::fs::File; + +fn read_username_from_file() -> Result { + let mut f = File::open("hello.txt")?; + let mut s = String::new(); + f.read_to_string(&mut s)?; + Ok(s) +} +``` + +
+ +Listing 9-6: A function that returns errors to the calling code using `?` + +
+
+ +The `?` placed after a `Result` value is defined to work the exact same way as +the `match` expressions we defined to handle the `Result` values in Listing +9-5. If the value of the `Result` is an `Ok`, the value inside the `Ok` will +get returned from this expression and the program will continue. If the value +is an `Err`, the value inside the `Err` will be returned from the whole +function as if we had used the `return` keyword so that the error value gets +propagated to the caller. + +In the context of Listing 9-6, the `?` at the end of the `File::open` call will +return the value inside an `Ok` to the variable `f`. If an error occurs, `?` +will return early out of the whole function and give any `Err` value to our +caller. The same thing applies to the `?` at the end of the `read_to_string` +call. + +The `?` eliminates a lot of boilerplate and makes this function’s +implementation simpler. We could even shorten this code further by chaining +method calls immediately after the `?`: + +```rust +use std::io; +use std::io::Read; +use std::fs::File; + +fn read_username_from_file() -> Result { + let mut s = String::new(); + + File::open("hello.txt")?.read_to_string(&mut s)?; + + Ok(s) +} +``` + +We’ve moved the creation of the new `String` in `s` to the beginning of the +function; that part hasn’t changed. Instead of creating a variable `f`, we’ve +chained the call to `read_to_string` directly onto the result of +`File::open("hello.txt")?`. We still have a `?` at the end of the +`read_to_string` call, and we still return an `Ok` value containing the +username in `s` when both `File::open` and `read_to_string` succeed rather than +returning errors. The functionality is again the same as in Listing 9-5 and +Listing 9-6, this is just a different, more ergonomic way to write it. + +### `?` Can Only Be Used in Functions That Return `Result` + +The `?` can only be used in functions that have a return type of `Result`, +since it is defined to work in exactly the same way as the `match` expression +we defined in Listing 9-5. The part of the `match` that requires a return type +of `Result` is `return Err(e)`, so the return type of the function must be a +`Result` to be compatible with this `return`. + +Let’s look at what happens if use `?` in the `main` function, which you’ll +recall has a return type of `()`: + +```rust,ignore +use std::fs::File; + +fn main() { + let f = File::open("hello.txt")?; +} +``` + + + +When we compile this, we get the following error message: + +```text +error[E0308]: mismatched types + --> + | +3 | let f = File::open("hello.txt")?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum +`std::result::Result` + | + = note: expected type `()` + = note: found type `std::result::Result<_, _>` +``` + +This error is pointing out that we have mismatched types: the `main` function +has a return type of `()`, but the `?` might return a `Result`. In functions +that don’t return `Result`, when you call other functions that return `Result`, +you’ll need to use a `match` or one of the `Result` methods to handle it, +instead of using `?` to potentially propagate the error to the caller. + +Now that we’ve discussed the details of calling `panic!` or returning `Result`, +let’s return to the topic of how to decide which is appropriate to use in which +cases. + +## To `panic!` or Not To `panic!` + +So how do you decide when you should `panic!` and when you should return +`Result`? When code panics, there’s no way to recover. You could choose to call +`panic!` for any error situation, whether there’s a possible way to recover or +not, but then you’re making the decision for your callers that a situation is +unrecoverable. When you choose to return a `Result` value, you give your caller +options, rather than making the decision for them. They could choose to attempt +to recover in a way that’s appropriate for their situation, or they could +decide that actually, an `Err` value in this case is unrecoverable, so they can +call `panic!` and turn your recoverable error into an unrecoverable one. +Therefore, returning `Result` is a good default choice when you’re defining a +function that might fail. + +There are a few situations in which it’s more appropriate to write code that +panics instead of returning a `Result`, but they are less common. Let’s discuss +why it’s appropriate to panic in examples, prototype code, and tests, then +situations where you as a human can know a method won’t fail that the compiler +can’t reason about, and conclude with some general guidelines on how to decide +whether to panic in library code. + +### Examples, Prototype Code, and Tests: Perfectly Fine to Panic + +When you’re writing an example to illustrate some concept, having robust error +handling code in the example as well can make the example less clear. In +examples, it’s understood that a call to a method like `unwrap` that could +`panic!` is meant as a placeholder for the way that you’d actually like your +application to handle errors, which can differ based on what the rest of your +code is doing. + +Similarly, the `unwrap` and `expect` methods are very handy when prototyping, +before you’re ready to decide how to handle errors. They leave clear markers in +your code for when you’re ready to make your program more robust. + +If a method call fails in a test, we’d want the whole test to fail, even if +that method isn’t the functionality under test. Because `panic!` is how a test +gets marked as a failure, calling `unwrap` or `expect` is exactly what makes +sense to do. + +### Cases When You Have More Information Than The Compiler + +It would also be appropriate to call `unwrap` when you have some other logic +that ensures the `Result` will have an `Ok` value, but the logic isn’t +something the compiler understands. You’ll still have a `Result` value that you +need to handle: whatever operation you’re calling still has the possibility of +failing in general, even though it’s logically impossible in your particular +situation. If you can ensure by manually inspecting the code that you’ll never +have an `Err` variant, it is perfectly acceptable to call `unwrap`. Here’s an +example: + +```rust +use std::net::IpAddr; + +let home = "127.0.0.1".parse::().unwrap(); +``` + +We’re creating an `IpAddr` instance by parsing a hardcoded string. We can see +that `127.0.0.1` is a valid IP address, so it’s acceptable to use `unwrap` +here. However, having a hardcoded, valid string doesn’t change the return type +of the `parse` method: we still get a `Result` value, and the compiler will +still make us handle the `Result` as if the `Err` variant is still a +possibility since the compiler isn’t smart enough to see that this string is +always a valid IP address. If the IP address string came from a user instead of +being hardcoded into the program, and therefore *did* have a possibility of +failure, we’d definitely want to handle the `Result` in a more robust way +instead. + +### Guidelines for Error Handling + +It’s advisable to have your code `panic!` when it’s possible that you could end +up in a bad state—in this context, bad state is when some assumption, +guarantee, contract, or invariant has been broken, such as when invalid values, +contradictory values, or missing values are passed to your code—plus one or +more of the following: + +* The bad state is not something that’s *expected* to happen occasionally +* Your code after this point needs to rely on not being in this bad state +* There’s not a good way to encode this information in the types you use + +If someone calls your code and passes in values that don’t make sense, the best +thing might be to `panic!` and alert the person using your library to the bug +in their code so that they can fix it during development. Similarly, `panic!` +is often appropriate if you’re calling external code that is out of your +control, and it returns an invalid state that you have no way of fixing. + +When a bad state is reached, but it’s expected to happen no matter how well you +write your code, it’s still more appropriate to return a `Result` rather than +calling `panic!`. Examples of this include a parser being given malformed data, +or an HTTP request returning a status that indicates you have hit a rate limit. +In these cases, you should indicate that failure is an expected possibility by +returning a `Result` in order to propagate these bad states upwards so that the +caller can decide how they would like to handle the problem. To `panic!` +wouldn’t be the best way to handle these cases. + +When your code performs operations on values, your code should verify the +values are valid first, and `panic!` if the values aren’t valid. This is mostly +for safety reasons: attempting to operate on invalid data can expose your code +to vulnerabilities. This is the main reason that the standard library will +`panic!` if you attempt an out-of-bounds array access: trying to access memory +that doesn’t belong to the current data structure is a common security problem. +Functions often have *contracts*: their behavior is only guaranteed if the +inputs meet particular requirements. Panicking when the contract is violated +makes sense because a contract violation always indicates a caller-side bug, +and it is not a kind of error you want callers to have to explicitly handle. In +fact, there’s no reasonable way for calling code to recover: the calling +*programmers* need to fix the code. Contracts for a function, especially when a +violation will cause a panic, should be explained in the API documentation for +the function. + +Having lots of error checks in all of your functions would be verbose and +annoying, though. Luckily, you can use Rust’s type system (and thus the type +checking the compiler does) to do a lot of the checks for you. If your function +has a particular type as a parameter, you can proceed with your code’s logic +knowing that the compiler has already ensured you have a valid value. For +example, if you have a type rather than an `Option`, your program expects to +have *something* rather than *nothing*. Your code then doesn’t have to handle +two cases for the `Some` and `None` variants, it will only have one case for +definitely having a value. Code trying to pass nothing to your function won’t +even compile, so your function doesn’t have to check for that case at runtime. +Another example is using an unsigned integer type like `u32`, which ensures the +parameter is never negative. + +### Creating Custom Types for Validation + +Let’s take the idea of using Rust’s type system to ensure we have a valid value +one step further, and look at creating a custom type for validation. Recall the +guessing game in Chapter 2, where our code asked the user to guess a number +between 1 and 100. We actually never validated that the user’s guess was +between those numbers before checking it against our secret number, only that +it was positive. In this case, the consequences were not very dire: our output +of “Too high” or “Too low” would still be correct. It would be a useful +enhancement to guide the user towards valid guesses, though, and have different +behavior when a user guesses a number that’s out of range versus when a user +types, for example, letters instead. + +One way to do this would be to parse the guess as an `i32` instead of only a +`u32`, to allow potentially negative numbers, then add a check for the number +being in range: + +```rust,ignore +loop { + // snip + + let guess: i32 = match guess.trim().parse() { + Ok(num) => num, + Err(_) => continue, + }; + + if guess < 1 || guess > 100 { + println!("The secret number will be between 1 and 100."); + continue; + } + + match guess.cmp(&secret_number) { + // snip +} +``` + +The `if` expression checks to see if our value is out of range, tells the user +about the problem, and calls `continue` to start the next iteration of the loop +and ask for another guess. After the `if` expression, we can proceed with the +comparisons between `guess` and the secret number knowing that `guess` is +between 1 and 100. + +However, this is not an ideal solution: if it was absolutely critical that the +program only operated on values between 1 and 100, and it had many functions +with this requirement, it would be tedious (and potentially impact performance) +to have a check like this in every function. + +Instead, we can make a new type and put the validations in a function to create +an instance of the type rather than repeating the validations everywhere. That +way, it’s safe for functions to use the new type in their signatures and +confidently use the values they receive. Listing 9-8 shows one way to define a +`Guess` type that will only create an instance of `Guess` if the `new` function +receives a value between 1 and 100: + +
+ +```rust +struct Guess { + value: u32, +} + +impl Guess { + pub fn new(value: u32) -> Guess { + if value < 1 || value > 100 { + panic!("Guess value must be between 1 and 100, got {}.", value); + } + + Guess { + value: value, + } + } + + pub fn value(&self) -> u32 { + self.value + } +} +``` + +
+ +Listing 9-8: A `Guess` type that will only continue with values between 1 and +100 + +
+
+ +First, we define a struct named `Guess` that has a field named `value` that +holds a `u32`. This is where the number will be stored. + +Then we implement an associated function named `new` on `Guess` that creates +instances of `Guess` values. The `new` function is defined to have one +parameter named `value` of type `u32` and to return a `Guess`. The code in the +body of the `new` function tests `value` to make sure it is between 1 and 100. +If `value` doesn’t pass this test, we call `panic!`, which will alert the +programmer who is calling this code that they have a bug they need to fix, +since creating a `Guess` with a `value` outside this range would violate the +contract that `Guess::new` is relying on. The conditions in which `Guess::new` +might panic should be discussed in its public-facing API documentation; we’ll +cover documentation conventions around indicating the possibility of a `panic!` +in the API documentation that you create in Chapter 14. If `value` does pass +the test, we create a new `Guess` with its `value` field set to the `value` +parameter and return the `Guess`. + +Next, we implement a method named `value` that borrows `self`, doesn’t have any +other parameters, and returns a `u32`. This is a kind of method sometimes +called a *getter*, since its purpose is to get some data from its fields and +return it. This public method is necessary because the `value` field of the +`Guess` struct is private. It’s important that the `value` field is private so +that code using the `Guess` struct is not allowed to set `value` directly: +callers *must* use the `Guess::new` function to create an instance of `Guess`, +which ensures there’s no way for a `Guess` to have a `value` that hasn’t been +checked by the conditions in the `Guess::new` function. + +A function that has a parameter or returns only numbers between 1 and 100 could +then declare in its signature that it takes or returns a `Guess` rather than a +`u32`, and wouldn’t need to do any additional checks in its body. + +## Summary + +Rust’s error handling features are designed to help you write more robust code. +The `panic!` macro signals that your program is in a state it can’t handle, and +lets you tell the process to stop instead of trying to proceed with invalid or +incorrect values. The `Result` enum uses Rust’s type system to indicate that +operations might fail in a way that your code could recover from. You can use +`Result` to tell code that calls your code that it needs to handle potential +success or failure as well. Using `panic!` and `Result` in the appropriate +situations will make your code more reliable in the face of inevitable problems. + +Now that we’ve seen useful ways that the standard library uses generics with +the `Option` and `Result` enums, let’s talk about how generics work and how you +can make use of them in your code. diff --git a/src/doc/book/second-edition/nostarch/chapter10.md b/src/doc/book/second-edition/nostarch/chapter10.md new file mode 100644 index 0000000000..cc8553086a --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter10.md @@ -0,0 +1,1879 @@ + +[TOC] + +# Generic Types, Traits, and Lifetimes + +Every programming language has tools to deal effectively with duplication of +concepts; in Rust, one of those tools is *generics*. Generics are abstract +stand-ins for concrete types or other properties. We can express properties of +generics, such as their behavior or how they relate to other generics, without +needing to know when we're writing and compiling the code what will actually be +in their place. + +In the same way that a function takes parameters whose value we don't know in +order to write code once that will be run on multiple concrete values, we can +write functions that take parameters of some generic type instead of a concrete +type like `i32` or `String`. We've already used generics in Chapter 6 with +`Option`, Chapter 8 with `Vec` and `HashMap`, and Chapter 9 with +`Result`. In this chapter, we'll explore how to define our own types, +functions, and methods with generics! + +First, we're going to review the mechanics of extracting a function that +reduces code duplication. Then we'll use the same mechanics to make a generic +function out of two functions that only differ in the types of their +parameters. We'll go over using generic types in struct and enum definitions +too. + +After that, we'll discuss *traits*, which are a way to define behavior in a +generic way. Traits can be combined with generic types in order to constrain a +generic type to those types that have a particular behavior, rather than any +type at all. + +Finally, we'll discuss *lifetimes*, which are a kind of generic that let us +give the compiler information about how references are related to each other. +Lifetimes are the feature in Rust that allow us to borrow values in many +situations and still have the compiler check that references will be valid. + +## Removing Duplication by Extracting a Function + +Before getting into generics syntax, let's first review a technique for dealing +with duplication that doesn't use generic types: extracting a function. Once +that's fresh in our minds, we'll use the same mechanics with generics to +extract a generic function! In the same way that you recognize duplicated code +to extract into a function, you'll start to recognize duplicated code that can +use generics. + +Consider a small program that finds the largest number in a list, shown in +Listing 10-1: + +Filename: src/main.rs + +``` +fn main() { + let numbers = vec![34, 50, 25, 100, 65]; + + let mut largest = numbers[0]; + + for number in numbers { + if number > largest { + largest = number; + } + } + + println!("The largest number is {}", largest); +} +``` + +Listing 10-1: Code to find the largest number in a list of numbers + +This code takes a list of integers, stored here in the variable `numbers`. It +puts the first item in the list in a variable named `largest`. Then it iterates +through all the numbers in the list, and if the current value is greater than +the number stored in `largest`, it replaces the value in `largest`. If the +current value is smaller than the largest value seen so far, `largest` is not +changed. When all the items in the list have been considered, `largest` will +hold the largest value, which in this case is 100. + +If we needed to find the largest number in two different lists of numbers, we +could duplicate the code in Listing 10-1 and have the same logic exist in two +places in the program, as in Listing 10-2: + +Filename: src/main.rs + +``` +fn main() { + let numbers = vec![34, 50, 25, 100, 65]; + + let mut largest = numbers[0]; + + for number in numbers { + if number > largest { + largest = number; + } + } + + println!("The largest number is {}", largest); + + let numbers = vec![102, 34, 6000, 89, 54, 2, 43, 8]; + + let mut largest = numbers[0]; + + for number in numbers { + if number > largest { + largest = number; + } + } + + println!("The largest number is {}", largest); +} +``` + +Listing 10-2: Code to find the largest number in *two* lists of numbers + +While this code works, duplicating code is tedious and error-prone, and means +we have multiple places to update the logic if we need to change it. + + + + +To eliminate this duplication, we can create an abstraction, which in this case +will be in the form of a function that operates on any list of integers given +to the function in a parameter. This will increase the clarity of our code and +let us communicate and reason about the concept of finding the largest number +in a list independently of the specific places this concept is used. + +In the program in Listing 10-3, we've extracted the code that finds the largest +number into a function named `largest`. This program can find the largest +number in two different lists of numbers, but the code from Listing 10-1 only +exists in one spot: + +Filename: src/main.rs + +``` +fn largest(list: &[i32]) -> i32 { + let mut largest = list[0]; + + for &item in list.iter() { + if item > largest { + largest = item; + } + } + + largest +} + +fn main() { + let numbers = vec![34, 50, 25, 100, 65]; + + let result = largest(&numbers); + println!("The largest number is {}", result); + + let numbers = vec![102, 34, 6000, 89, 54, 2, 43, 8]; + + let result = largest(&numbers); + println!("The largest number is {}", result); +} +``` + +Listing 10-3: Abstracted code to find the largest number in two lists + +The function has a parameter, `list`, which represents any concrete slice of +`i32` values that we might pass into the function. The code in the function +definition operates on the `list` representation of any `&[i32]`. When we call +the `largest` function, the code actually runs on the specific values that we +pass in. + +The mechanics we went through to get from Listing 10-2 to Listing 10-3 were +these steps: + +1. We noticed there was duplicate code. +2. We extracted the duplicate code into the body of the function, and specified + the inputs and return values of that code in the function signature. +3. We replaced the two concrete places that had the duplicated code to call the + function instead. + +We can use these same steps with generics to reduce code duplication in +different ways in different scenarios. In the same way that the function body +is now operating on an abstract `list` instead of concrete values, code using +generics will operate on abstract types. The concepts powering generics are the +same concepts you already know that power functions, just applied in different +ways. + +What if we had two functions, one that found the largest item in a slice of +`i32` values and one that found the largest item in a slice of `char` values? +How would we get rid of that duplication? Let's find out! + +## Generic Data Types + +Using generics where we usually place types, like in function signatures or +structs, lets us create definitions that we can use for many different concrete +data types. Let's take a look at how to define functions, structs, enums, and +methods using generics, and at the end of this section we'll discuss the +performance of code using generics. + +### Using Generic Data Types in Function Definitions + +We can define functions that use generics in the signature of the function +where the data types of the parameters and return value go. In this way, the +code we write can be more flexible and provide more functionality to callers of +our function, while not introducing code duplication. + +Continuing with our `largest` function, Listing 10-4 shows two functions +providing the same functionality to find the largest value in a slice. The +first function is the one we extracted in Listing 10-3 that finds the largest +`i32` in a slice. The second function finds the largest `char` in a slice: + +Filename: src/main.rs + +``` +fn largest_i32(list: &[i32]) -> i32 { + let mut largest = list[0]; + + for &item in list.iter() { + if item > largest { + largest = item; + } + } + + largest +} + +fn largest_char(list: &[char]) -> char { + let mut largest = list[0]; + + for &item in list.iter() { + if item > largest { + largest = item; + } + } + + largest +} + +fn main() { + let numbers = vec![34, 50, 25, 100, 65]; + + let result = largest_i32(&numbers); + println!("The largest number is {}", result); + + let chars = vec!['y', 'm', 'a', 'q']; + + let result = largest_char(&chars); + println!("The largest char is {}", result); +} +``` + +Listing 10-4: Two functions that differ only in their names and the types in +their signatures + +Here, the functions `largest_i32` and `largest_char` have the exact same body, +so it would be nice if we could turn these two functions into one and get rid +of the duplication. Luckily, we can do that by introducing a generic type +parameter! + +To parameterize the types in the signature of the one function we're going to +define, we need to create a name for the type parameter, just like how we give +names for the value parameters to a function. We're going to choose the name +`T`. Any identifier can be used as a type parameter name, but we're choosing +`T` because Rust's type naming convention is CamelCase. Generic type parameter +names also tend to be short by convention, often just one letter. Short for +"type", `T` is the default choice of most Rust programmers. + +When we use a parameter in the body of the function, we have to declare the +parameter in the signature so that the compiler knows what that name in the +body means. Similarly, when we use a type parameter name in a function +signature, we have to declare the type parameter name before we use it. Type +name declarations go in angle brackets between the name of the function and the +parameter list. + +The function signature of the generic `largest` function we're going to define +will look like this: + +``` +fn largest(list: &[T]) -> T { +``` + +We would read this as: the function `largest` is generic over some type `T`. It +has one parameter named `list`, and the type of `list` is a slice of values of +type `T`. The `largest` function will return a value of the same type `T`. + +Listing 10-5 shows the unified `largest` function definition using the generic +data type in its signature, and shows how we'll be able to call `largest` with +either a slice of `i32` values or `char` values. Note that this code won't +compile yet! + +Filename: src/main.rs + +``` +fn largest(list: &[T]) -> T { + let mut largest = list[0]; + + for &item in list.iter() { + if item > largest { + largest = item; + } + } + + largest +} + +fn main() { + let numbers = vec![34, 50, 25, 100, 65]; + + let result = largest(&numbers); + println!("The largest number is {}", result); + + let chars = vec!['y', 'm', 'a', 'q']; + + let result = largest(&chars); + println!("The largest char is {}", result); +} +``` + +Listing 10-5: A definition of the `largest` function that uses generic type +parameters but doesn't compile yet + +If we try to compile this code right now, we'll get this error: + +``` +error[E0369]: binary operation `>` cannot be applied to type `T` + | +5 | if item > largest { + | ^^^^ + | +note: an implementation of `std::cmp::PartialOrd` might be missing for `T` +``` + +The note mentions `std::cmp::PartialOrd`, which is a *trait*. We're going to +talk about traits in the next section, but briefly, what this error is saying +is that the body of `largest` won't work for all possible types that `T` could +be; since we want to compare values of type `T` in the body, we can only use +types that know how to be ordered. The standard library has defined the trait +`std::cmp::PartialOrd` that types can implement to enable comparisons. We'll +come back to traits and how to specify that a generic type has a particular +trait in the next section, but let's set this example aside for a moment and +explore other places we can use generic type parameters first. + + + +### Using Generic Data Types in Struct Definitions + +We can define structs to use a generic type parameter in one or more of the +struct's fields with the `<>` syntax too. Listing 10-6 shows the definition and +use of a `Point` struct that can hold `x` and `y` coordinate values of any type: + +Filename: src/main.rs + +``` +struct Point { + x: T, + y: T, +} + +fn main() { + let integer = Point { x: 5, y: 10 }; + let float = Point { x: 1.0, y: 4.0 }; +} +``` + +Listing 10-6: A `Point` struct that holds `x` and `y` values of type `T` + +The syntax is similar to using generics in function definitions. First, we have +to declare the name of the type parameter within angle brackets just after the +name of the struct. Then we can use the generic type in the struct definition +where we would specify concrete data types. + +Note that because we've only used one generic type in the definition of +`Point`, what we're saying is that the `Point` struct is generic over some type +`T`, and the fields `x` and `y` are *both* that same type, whatever it ends up +being. If we try to create an instance of a `Point` that has values of +different types, as in Listing 10-7, our code won't compile: + +Filename: src/main.rs + +``` +struct Point { + x: T, + y: T, +} + +fn main() { + let wont_work = Point { x: 5, y: 4.0 }; +} +``` + +Listing 10-7: The fields `x` and `y` must be the same type because both have +the same generic data type `T` + +If we try to compile this, we'll get the following error: + +``` +error[E0308]: mismatched types + --> + | +7 | let wont_work = Point { x: 5, y: 4.0 }; + | ^^^ expected integral variable, found + floating-point variable + | + = note: expected type `{integer}` + = note: found type `{float}` +``` + +When we assigned the integer value 5 to `x`, the compiler then knows for this +instance of `Point` that the generic type `T` will be an integer. Then when we +specified 4.0 for `y`, which is defined to have the same type as `x`, we get a +type mismatch error. + +If we wanted to define a `Point` struct where `x` and `y` could have different +types but still have those types be generic, we can use multiple generic type +parameters. In listing 10-8, we've changed the definition of `Point` to be +generic over types `T` and `U`. The field `x` is of type `T`, and the field `y` +is of type `U`: + +Filename: src/main.rs + +``` +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 }; +} +``` + +Listing 10-8: A `Point` generic over two types so that `x` and `y` may be +values of different types + +Now all of these instances of `Point` are allowed! You can use as many generic +type parameters in a definition as you want, but using more than a few gets +hard to read and understand. If you get to a point of needing lots of generic +types, it's probably a sign that your code could use some restructuring to be +separated into smaller pieces. + +### Using Generic Data Types in Enum Definitions + +Similarly to structs, enums can be defined to hold generic data types in their +variants. We used the `Option` enum provided by the standard library in +Chapter 6, and now its definition should make more sense. Let's take another +look: + +``` +enum Option { + Some(T), + None, +} +``` + +In other words, `Option` is an enum generic in type `T`. It has two +variants: `Some`, which holds one value of type `T`, and a `None` variant that +doesn't hold any value. The standard library only has to have this one +definition to support the creation of values of this enum that have any +concrete type. The idea of "an optional value" is a more abstract concept than +one specific type, and Rust lets us express this abstract concept without lots +of duplication. + +Enums can use multiple generic types as well. The definition of the `Result` +enum that we used in Chapter 9 is one example: + +``` +enum Result { + Ok(T), + Err(E), +} +``` + +The `Result` enum is generic over two types, `T` and `E`. `Result` has two +variants: `Ok`, which holds a value of type `T`, and `Err`, which holds a value +of type `E`. This definition makes it convenient to use the `Result` enum +anywhere we have an operation that might succeed (and return a value of some +type `T`) or fail (and return an error of some type `E`). Recall Listing 9-2 +when we opened a file: in that case, `T` was filled in with the type +`std::fs::File` when the file was opened successfully and `E` was filled in +with the type `std::io::Error` when there were problems opening the file. + +When you recognize situations in your code with multiple struct or enum +definitions that differ only in the types of the values they hold, you can +remove the duplication by using the same process we used with the function +definitions to introduce generic types instead. + +### Using Generic Data Types in Method Definitions + +Like we did in Chapter 5, we can implement methods on structs and enums that +have generic types in their definitions. Listing 10-9 shows the `Point` +struct we defined in Listing 10-6. We've then defined a method named `x` on +`Point` that returns a reference to the data in the field `x`: + +Filename: src/main.rs + +``` +struct Point { + x: T, + y: T, +} + +impl Point { + fn x(&self) -> &T { + &self.x + } +} + +fn main() { + let p = Point { x: 5, y: 10 }; + + println!("p.x = {}", p.x()); +} +``` + +Listing 10-9: Implementing a method named `x` on the `Point` struct that +will return a reference to the `x` field, which is of type `T`. + +Note that we have to declare `T` just after `impl`, so that we can use it when +we specify that we're implementing methods on the type `Point`. + +Generic type parameters in a struct definition aren't always the same generic +type parameters you want to use in that struct's method signatures. Listing +10-10 defines a method `mixup` on the `Point` struct from Listing 10-8. +The method takes another `Point` as a parameter, which might have different +types than the `self` `Point` that we're calling `mixup` on. The method creates +a new `Point` instance that has the `x` value from the `self` `Point` (which is +of type `T`) and the `y` value from the passed-in `Point` (which is of type +`W`): + +Filename: src/main.rs + +``` +struct Point { + x: T, + y: U, +} + +impl Point { + fn mixup(&self, other: &Point) -> Point { + Point { + x: self.x, + y: other.y, + } + } +} + +fn main() { + let p1 = Point { x: 5, y: 10.4 }; + let p2 = Point { x: "Hello", y: 'c'}; + + let p3 = p1.mixup(p2); + + println!("p3.x = {}, p3.y = {}", p3.x, p3.y); +} +``` + +Listing 10-10: Methods that use different generic types than their struct's +definition + +In `main`, we've defined a `Point` that has an `i32` for `x` (with value `5`) +and an `f64` for `y` (with value `10.4`). `p2` is a `Point` that has a string +slice for `x` (with value `"Hello"`) and a `char` for `y` (with value `c`). +Calling `mixup` on `p1` with the argument `p2` gives us `p3`, which will have +an `i32` for `x`, since `x` came from `p1`. `p3` will have a `char` for `y`, +since `y` came from `p2`. The `println!` will print `p3.x = 5, p3.y = c`. + +Note that the generic parameters `T` and `U` are declared after `impl`, since +they go with the struct definition. The generic parameters `V` and `W` are +declared after `fn mixup`, since they are only relevant to the method. + +### Performance of Code Using Generics + +You may have been reading this section and wondering if there's a run-time cost +to using generic type parameters. Good news: the way that Rust has implemented +generics means that your code will not run any slower than if you had specified +concrete types instead of generic type parameters! + +Rust accomplishes this by performing *monomorphization* of code using generics +at compile time. Monomorphization is the process of turning generic code into +specific code with the concrete types that are actually used filled in. + +What the compiler does is the opposite of the steps that we performed to create +the generic function in Listing 10-5. The compiler looks at all the places that +generic code is called and generates code for the concrete types that the +generic code is called with. + +Let's work through an example that uses the standard library's `Option` enum: + +``` +let integer = Some(5); +let float = Some(5.0); +``` + +When Rust compiles this code, it will perform monomorphization. The compiler +will read the values that have been passed to `Option` and see that we have two +kinds of `Option`: one is `i32`, and one is `f64`. As such, it will expand +the generic definition of `Option` into `Option_i32` and `Option_f64`, +thereby replacing the generic definition with the specific ones. + +The monomorphized version of our code that the compiler generates looks like +this, with the uses of the generic `Option` replaced with the specific +definitions created by the compiler: + +Filename: src/main.rs + +``` +enum Option_i32 { + Some(i32), + None, +} + +enum Option_f64 { + Some(f64), + None, +} + +fn main() { + let integer = Option_i32::Some(5); + let float = Option_f64::Some(5.0); +} +``` + +We can write the non-duplicated code using generics, and Rust will compile that +into code that specifies the type in each instance. That means we pay no +runtime cost for using generics; when the code runs, it performs just like it +would if we had duplicated each particular definition by hand. The process of +monomorphization is what makes Rust's generics extremely efficient at runtime. + +## Traits: Defining Shared Behavior + +Traits allow us to use another kind of abstraction: they let us abstract over +behavior that types can have in common. A *trait* tells the Rust compiler about +functionality a particular type has and might share with other types. In +situations where we use generic type parameters, we can use *trait bounds* to +specify, at compile time, that the generic type may be any type that implements +a trait and therefore has the behavior we want to use in that situation. + +> Note: *Traits* are similar to a feature often called 'interfaces' in other +> languages, though with some differences. + +### Defining a Trait + +The behavior of a type consists of the methods we can call on that type. +Different types share the same behavior if we can call the same methods on all +of those types. Trait definitions are a way to group method signatures together +in order to define a set of behaviors necessary to accomplish some purpose. + +For example, say we have multiple structs that hold various kinds and amounts +of text: a `NewsArticle` struct that holds a news story filed in a particular +place in the world, and a `Tweet` that can have at most 140 characters in its +content along with metadata like whether it was a retweet or a reply to another +tweet. + +We want to make a media aggregator library that can display summaries of data +that might be stored in a `NewsArticle` or `Tweet` instance. The behavior we +need each struct to have is that it's able to be summarized, and that we can +ask for that summary by calling a `summary` method on an instance. Listing +10-11 shows the definition of a `Summarizable` trait that expresses this +concept: + +Filename: lib.rs + +``` +pub trait Summarizable { + fn summary(&self) -> String; +} +``` + +Listing 10-11: Definition of a `Summarizable` trait that consists of the +behavior provided by a `summary` method + +We declare a trait with the `trait` keyword, then the trait's name, in this +case `Summarizable`. Inside curly braces we declare the method signatures that +describe the behaviors that types that implement this trait will need to have, +in this case `fn summary(&self) -> String`. After the method signature, instead +of providing an implementation within curly braces, we put a semicolon. Each +type that implements this trait must then provide its own custom behavior for +the body of the method, but the compiler will enforce that any type that has +the `Summarizable` trait will have the method `summary` defined for it with +this signature exactly. + +A trait can have multiple methods in its body, with the method signatures +listed one per line and each line ending in a semicolon. + +### Implementing a Trait on a Type + +Now that we've defined the `Summarizable` trait, we can implement it on the +types in our media aggregator that we want to have this behavior. Listing 10-12 +shows an implementation of the `Summarizable` trait on the `NewsArticle` struct +that uses the headline, the author, and the location to create the return value +of `summary`. For the `Tweet` struct, we've chosen to define `summary` as the +username followed by the whole text of the tweet, assuming that tweet content +is already limited to 140 characters. + +Filename: lib.rs + +``` +pub struct NewsArticle { + pub headline: String, + pub location: String, + pub author: String, + pub content: String, +} + +impl Summarizable for NewsArticle { + fn summary(&self) -> String { + format!("{}, by {} ({})", self.headline, self.author, self.location) + } +} + +pub struct Tweet { + pub username: String, + pub content: String, + pub reply: bool, + pub retweet: bool, +} + +impl Summarizable for Tweet { + fn summary(&self) -> String { + format!("{}: {}", self.username, self.content) + } +} +``` + +Listing 10-12: Implementing the `Summarizable` trait on the `NewsArticle` and +`Tweet` types + +Implementing a trait on a type is similar to implementing methods that aren't +related to a trait. The difference is after `impl`, we put the trait name that +we want to implement, then say `for` and the name of the type that we want to +implement the trait for. Within the `impl` block, we put the method signatures +that the trait definition has defined, but instead of putting a semicolon after +each signature, we put curly braces and fill in the method body with the +specific behavior that we want the methods of the trait to have for the +particular type. + +Once we've implemented the trait, we can call the methods on instances of +`NewsArticle` and `Tweet` in the same manner that we call methods that aren't +part of a trait: + +``` +let tweet = Tweet { + username: String::from("horse_ebooks"), + content: String::from("of course, as you probably already know, people"), + reply: false, + retweet: false, +}; + +println!("1 new tweet: {}", tweet.summary()); +``` + +This will print `1 new tweet: horse_ebooks: of course, as you probably already +know, people`. + +Note that because we've defined the `Summarizable` trait and the `NewsArticle` +and `Tweet` types all in the same `lib.rs` in Listing 10-12, they're all in the +same scope. If this `lib.rs` is for a crate we've called `aggregator`, and +someone else wants to use our crate's functionality plus implement the +`Summarizable` trait on their `WeatherForecast` struct, their code would need +to import the `Summarizable` trait into their scope first before they could +implement it, like in Listing 10-13: + +Filename: lib.rs + +``` +extern crate aggregator; + +use aggregator::Summarizable; + +struct WeatherForecast { + high_temp: f64, + low_temp: f64, + chance_of_precipitation: f64, +} + +impl Summarizable for WeatherForecast { + fn summary(&self) -> String { + format!("The high will be {}, and the low will be {}. The chance of + precipitation is {}%.", self.high_temp, self.low_temp, + self.chance_of_precipitation) + } +} +``` + +Listing 10-13: Bringing the `Summarizable` trait from our `aggregator` crate +into scope in another crate + +This code also assumes `Summarizable` is a public trait, which it is because we +put the `pub` keyword before `trait` in Listing 10-11. + +One restriction to note with trait implementations: we may implement a trait on +a type as long as either the trait or the type are local to our crate. In other +words, we aren't allowed to implement external traits on external types. We +can't implement the `Display` trait on `Vec`, for example, since both `Display` +and `Vec` are defined in the standard library. We are allowed to implement +standard library traits like `Display` on a custom type like `Tweet` as part of +our `aggregator` crate functionality. We could also implement `Summarizable` on +`Vec` in our `aggregator` crate, since we've defined `Summarizable` there. This +restriction is part of what's called the *orphan rule*, which you can look up +if you're interested in type theory. Briefly, it's called the orphan rule +because the parent type is not present. Without this rule, two crates could +implement the same trait for the same type, and the two implementations would +conflict: Rust wouldn't know which implementation to use. Because Rust enforces +the orphan rule, other people's code can't break your code and vice versa. + +### Default Implementations + +Sometimes it's useful to have default behavior for some or all of the methods +in a trait, instead of making every implementation on every type define custom +behavior. When we implement the trait on a particular type, we can choose to +keep or override each method's default behavior. + +Listing 10-14 shows how we could have chosen to specify a default string for +the `summary` method of the `Summarize` trait instead of only choosing to only +define the method signature like we did in Listing 10-11: + +Filename: lib.rs + +``` +pub trait Summarizable { + fn summary(&self) -> String { + String::from("(Read more...)") + } +} +``` + +Listing 10-14: Definition of a `Summarizable` trait with a default +implementation of the `summary` method + +If we wanted to use this default implementation to summarize instances of +`NewsArticle` instead of defining a custom implementation like we did in +Listing 10-12, we would specify an empty `impl` block: + +``` +impl Summarizable for NewsArticle {} +``` + +Even though we're no longer choosing to define the `summary` method on +`NewsArticle` directly, since the `summary` method has a default implementation +and we specified that `NewsArticle` implements the `Summarizable` trait, we can +still call the `summary` method on an instance of `NewsArticle`: + +``` +let article = NewsArticle { + headline: String::from("Penguins win the Stanley Cup Championship!"), + location: String::from("Pittsburgh, PA, USA"), + author: String::from("Iceburgh"), + content: String::from("The Pittsburgh Penguins once again are the best + hockey team in the NHL."), +}; + +println!("New article available! {}", article.summary()); +``` + +This code prints `New article available! (Read more...)`. + +Changing the `Summarizable` trait to have a default implementation for +`summary` does not require us to change anything about the implementations of +`Summarizable` on `Tweet` in Listing 10-12 or `WeatherForecast` in Listing +10-13: the syntax for overriding a default implementation is exactly the same +as the syntax for implementing a trait method that doesn't have a default +implementation. + +Default implementations are allowed to call the other methods in the same +trait, even if those other methods don't have a default implementation. In this +way, a trait can provide a lot of useful functionality and only require +implementers to specify a small part of it. We could choose to have the +`Summarizable` trait also have an `author_summary` method whose implementation +is required, then a `summary` method that has a default implementation that +calls the `author_summary` method: + +``` +pub trait Summarizable { + fn author_summary(&self) -> String; + + fn summary(&self) -> String { + format!("(Read more from {}...)", self.author_summary()) + } +} +``` + +In order to use this version of `Summarizable`, we're only required to define +`author_summary` when we implement the trait on a type: + +``` +impl Summarizable for Tweet { + fn author_summary(&self) -> String { + format!("@{}", self.username) + } +} +``` + +Once we define `author_summary`, we can call `summary` on instances of the +`Tweet` struct, and the default implementation of `summary` will call the +definition of `author_summary` that we've provided. + +``` +let tweet = Tweet { + username: String::from("horse_ebooks"), + content: String::from("of course, as you probably already know, people"), + reply: false, + retweet: false, +}; + +println!("1 new tweet: {}", tweet.summary()); +``` + +This will print `1 new tweet: (Read more from @horse_ebooks...)`. + +Note that it is not possible to call the default implementation from an +overridden implementation. + +### Trait Bounds + +Now that we've defined traits and implemented those traits on types, we can use +traits with generic type parameters. We can constrain generic types so that +rather than being any type, the compiler will ensure that the type will be +limited to those types that implement a particular trait and thus have the +behavior that we need the types to have. This is called specifying *trait +bounds* on a generic type. + +For example, in Listing 10-12, we implemented the `Summarizable` trait on the +types `NewsArticle` and `Tweet`. We can define a function `notify` that calls +the `summary` method on its parameter `item`, which is of the generic type `T`. +To be able to call `summary` on `item` without getting an error, we can use +trait bounds on `T` to specify that `item` must be of a type that implements +the `Summarizable` trait: + +``` +pub fn notify(item: T) { + println!("Breaking news! {}", item.summary()); +} +``` + +Trait bounds go with the declaration of the generic type parameter, after a +colon and within the angle brackets. Because of the trait bound on `T`, we can +call `notify` and pass in any instance of `NewsArticle` or `Tweet`. The +external code from Listing 10-13 that's using our `aggregator` crate can call +our `notify` function and pass in an instance of `WeatherForecast`, since +`Summarizable` is implemented for `WeatherForecast` as well. Code that calls +`notify` with any other type, like a `String` or an `i32`, won't compile, since +those types do not implement `Summarizable`. + +We can specify multiple trait bounds on a generic type by using `+`. If we +needed to be able to use display formatting on the type `T` in a function as +well as the `summary` method, we can use the trait bounds `T: Summarizable + +Display`. This means `T` can be any type that implements both `Summarizable` +and `Display`. + +For functions that have multiple generic type parameters, each generic has its +own trait bounds. Specifying lots of trait bound information in the angle +brackets between a function's name and its parameter list can get hard to read, +so there's an alternate syntax for specifying trait bounds that lets us move +them to a `where` clause after the function signature. So instead of: + +``` +fn some_function(t: T, u: U) -> i32 { +``` + +We can write this instead with a `where` clause: + +``` +fn some_function(t: T, u: U) -> i32 + where T: Display + Clone, + U: Clone + Debug +{ +``` + +This is less cluttered and makes this function's signature look more similar to +a function without lots of trait bounds, in that the function name, parameter +list, and return type are close together. + +### Fixing the `largest` Function with Trait Bounds + +So any time you want to use behavior defined by a trait on a generic, you need +to specify that trait in the generic type parameter's type bounds. We can now +fix the definition of the `largest` function that uses a generic type parameter +from Listing 10-5! When we set that code aside, we were getting this error: + +``` +error[E0369]: binary operation `>` cannot be applied to type `T` + | +5 | if item > largest { + | ^^^^ + | +note: an implementation of `std::cmp::PartialOrd` might be missing for `T` +``` + +In the body of `largest` we wanted to be able to compare two values of type `T` +using the greater-than operator. That operator is defined as a default method +on the standard library trait `std::cmp::PartialOrd`. So in order to be able to +use the greater-than operator, we need to specify `PartialOrd` in the trait +bounds for `T` so that the `largest` function will work on slices of any type +that can be compared. We don't need to bring `PartialOrd` into scope because +it's in the prelude. + +``` +fn largest(list: &[T]) -> T { +``` + +If we try to compile this, we'll get different errors: + +``` +error[E0508]: cannot move out of type `[T]`, a non-copy array + --> src/main.rs:4:23 + | +4 | let mut largest = list[0]; + | ----------- ^^^^^^^ cannot move out of here + | | + | hint: to prevent move, use `ref largest` or `ref mut largest` + +error[E0507]: cannot move out of borrowed content + --> src/main.rs:6:9 + | +6 | for &item in list.iter() { + | ^---- + | || + | |hint: to prevent move, use `ref item` or `ref mut item` + | cannot move out of borrowed content +``` + +The key to this error is `cannot move out of type [T], a non-copy array`. +With our non-generic versions of the `largest` function, we were only trying to +find the largest `i32` or `char`. As we discussed in Chapter 4, types like +`i32` and `char` that have a known size can be stored on the stack, so they +implement the `Copy` trait. When we changed the `largest` function to be +generic, it's now possible that the `list` parameter could have types in it +that don't implement the `Copy` trait, which means we wouldn't be able to move +the value out of `list[0]` and into the `largest` variable. + +If we only want to be able to call this code with types that are `Copy`, we can +add `Copy` to the trait bounds of `T`! Listing 10-15 shows the complete code of +a generic `largest` function that will compile as long as the types of the +values in the slice that we pass into `largest` implement both the `PartialOrd` +and `Copy` traits, like `i32` and `char`: + +Filename: src/main.rs + +``` +use std::cmp::PartialOrd; + +fn largest(list: &[T]) -> T { + let mut largest = list[0]; + + for &item in list.iter() { + if item > largest { + largest = item; + } + } + + largest +} + +fn main() { + let numbers = vec![34, 50, 25, 100, 65]; + + let result = largest(&numbers); + println!("The largest number is {}", result); + + let chars = vec!['y', 'm', 'a', 'q']; + + let result = largest(&chars); + println!("The largest char is {}", result); +} +``` + +Listing 10-15: A working definition of the `largest` function that works on any +generic type that implements the `PartialOrd` and `Copy` traits + +If we don't want to restrict our `largest` function to only types that +implement the `Copy` trait, we could specify that `T` has the trait bound +`Clone` instead of `Copy` and clone each value in the slice when we want the +`largest` function to have ownership. Using the `clone` function means we're +potentially making more heap allocations, though, and heap allocations can be +slow if we're working with large amounts of data. Another way we could +implement `largest` is for the function to return a reference to a `T` value in +the slice. If we change the return type to be `&T` instead of `T` and change +the body of the function to return a reference, we wouldn't need either the +`Clone` or `Copy` trait bounds and we wouldn't be doing any heap allocations. +Try implementing these alternate solutions on your own! + +Traits and trait bounds let us write code that uses generic type parameters in +order to reduce duplication, but still specify to the compiler exactly what +behavior our code needs the generic type to have. Because we've given the trait +bound information to the compiler, it can check that all the concrete types +used with our code provide the right behavior. In dynamically typed languages, +if we tried to call a method on a type that the type didn't implement, we'd get +an error at runtime. Rust moves these errors to compile time so that we're +forced to fix the problems before our code is even able to run. Additionally, +we don't have to write code that checks for behavior at runtime since we've +already checked at compile time, which improves performance compared to other +languages without having to give up the flexibility of generics. + +There's another kind of generics that we've been using without even realizing +it called *lifetimes*. Rather than helping us ensure that a type has the +behavior we need it to have, lifetimes help us ensure that references are valid +as long as we need them to be. Let's learn how lifetimes do that. + +## Validating References with Lifetimes + +When we talked about references in Chapter 4, we left out an important detail: +every reference in Rust has a *lifetime*, which is the scope for which that +reference is valid. Most of the time lifetimes are implicit and inferred, just +like most of the time types are inferred. Similarly to when we have to annotate +types because multiple types are possible, there are cases where the lifetimes +of references could be related in a few different ways, so Rust needs us to +annotate the relationships using generic lifetime parameters so that it can +make sure the actual references used at runtime will definitely be valid. + +Yes, it's a bit unusual, and will be different to tools you've used in other +programming languages. Lifetimes are, in some ways, Rust's most distinctive +feature. + +Lifetimes are a big topic that can't be covered in entirety in this chapter, so +we'll cover common ways you might encounter lifetime syntax in this chapter to +get you familiar with the concepts. Chapter 19 will contain more advanced +information about everything lifetimes can do. + +### Lifetimes Prevent Dangling References + +The main aim of lifetimes is to prevent dangling references, which will cause a +program to reference data other than the data we're intending to reference. +Consider the program in Listing 10-16, with an outer scope and an inner scope. +The outer scope declares a variable named `r` with no initial value, and the +inner scope declares a variable named `x` with the initial value of 5. Inside +the inner scope, we attempt to set the value of `r` as a reference to `x`. Then +the inner scope ends, and we attempt to print out the value in `r`: + +``` +{ + let r; + + { + let x = 5; + r = &x; + } + + println!("r: {}", r); +} +``` + +Listing 10-16: An attempt to use a reference whose value has gone out of scope + +> #### Uninitialized Variables Cannot Be Used +> +> The next few examples declare variables without giving them an initial value, +> so that the variable name exists in the outer scope. This might appear to be +> in conflict with Rust not having null. However, if we try to use a variable +> before giving it a value, we'll get a compile-time error. Try it out! + +When we compile this code, we'll get an error: + +``` +error: `x` does not live long enough + | +6 | r = &x; + | - borrow occurs here +7 | } + | ^ `x` dropped here while still borrowed +... +10 | } + | - borrowed value needs to live until here +``` + +The variable `x` doesn't "live long enough." Why not? Well, `x` is going to go +out of scope when we hit the closing curly brace on line 7, ending the inner +scope. But `r` is valid for the outer scope; its scope is larger and we say +that it "lives longer." If Rust allowed this code to work, `r` would be +referencing memory that was deallocated when `x` went out of scope, and +anything we tried to do with `r` wouldn't work correctly. So how does Rust +determine that this code should not be allowed? + +#### The Borrow Checker + +The part of the compiler called the *borrow checker* compares scopes to +determine that all borrows are valid. Listing 10-17 shows the same example from +Listing 10-16 with annotations showing the lifetimes of the variables: + +``` +{ + let r; // -------+-- 'a + // | + { // | + let x = 5; // -+-----+-- 'b + r = &x; // | | + } // -+ | + // | + println!("r: {}", r); // | + // | + // -------+ +} +``` + +Listing 10-17: Annotations of the lifetimes of `x` and `r`, named `'a` and `'b` +respectively + + + + +We've annotated the lifetime of `r` with `'a` and the lifetime of `x` with +`'b`. As you can see, the inner `'b` block is much smaller than the outer `'a` +lifetime block. At compile time, Rust compares the size of the two lifetimes +and sees that `r` has a lifetime of `'a`, but that it refers to an object with +a lifetime of `'b`. The program is rejected because the lifetime `'b` is +shorter than the lifetime of `'a`: the subject of the reference does not live +as long as the reference. + +Let's look at an example in Listing 10-18 that doesn't try to make a dangling +reference and compiles without any errors: + +``` +{ + let x = 5; // -----+-- 'b + // | + let r = &x; // --+--+-- 'a + // | | + println!("r: {}", r); // | | + // --+ | +} // -----+ +``` + +Listing 10-18: A valid reference because the data has a longer lifetime than +the reference + +Here, `x` has the lifetime `'b`, which in this case is larger than `'a`. This +means `r` can reference `x`: Rust knows that the reference in `r` will always +be valid while `x` is valid. + +Now that we've shown where the lifetimes of references are in a concrete +example and discussed how Rust analyzes lifetimes to ensure references will +always be valid, let's talk about generic lifetimes of parameters and return +values in the context of functions. + +### Generic Lifetimes in Functions + +Let's write a function that will return the longest of two string slices. We +want to be able to call this function by passing it two string slices, and we +want to get back a string slice. The code in Listing 10-19 should print `The +longest string is abcd` once we've implemented the `longest` function: + +Filename: src/main.rs + +``` +fn main() { + let string1 = String::from("abcd"); + let string2 = "xyz"; + + let result = longest(string1.as_str(), string2); + println!("The longest string is {}", result); +} +``` + +Listing 10-19: A `main` function that calls the `longest` function to find the +longest of two string slices + +Note that we want the function to take string slices (which are references, as +we talked about in Chapter 4) since we don't want the `longest` function to +take ownership of its arguments. We want the function to be able to accept +slices of a `String` (which is the type of the variable `string1`) as well as +string literals (which is what variable `string2` contains). + + + + +Refer back to the "String Slices as Arguments" section of Chapter 4 for more +discussion about why these are the arguments we want. + +If we try to implement the `longest` function as shown in Listing 10-20, it +won't compile: + +Filename: src/main.rs + +``` +fn longest(x: &str, y: &str) -> &str { + if x.len() > y.len() { + x + } else { + y + } +} +``` + +Listing 10-20: An implementation of the `longest` function that returns the +longest of two string slices, but does not yet compile + +Instead we get the following error that talks about lifetimes: + +``` +error[E0106]: missing lifetime specifier + | +1 | fn longest(x: &str, y: &str) -> &str { + | ^ expected lifetime parameter + | + = help: this function's return type contains a borrowed value, but the + signature does not say whether it is borrowed from `x` or `y` +``` + +The help text is telling us that the return type needs a generic lifetime +parameter on it because Rust can't tell if the reference being returned refers +to `x` or `y`. Actually, we don't know either, since the `if` block in the body +of this function returns a reference to `x` and the `else` block returns a +reference to `y`! + +As we're defining this function, we don't know the concrete values that will be +passed into this function, so we don't know whether the `if` case or the `else` +case will execute. We also don't know the concrete lifetimes of the references +that will be passed in, so we can't look at the scopes like we did in Listings +10-17 and 10-18 in order to determine that the reference we return will always +be valid. The borrow checker can't determine this either, because it doesn't +know how the lifetimes of `x` and `y` relate to the lifetime of the return +value. We're going to add generic lifetime parameters that will define the +relationship between the references so that the borrow checker can perform its +analysis. + +### Lifetime Annotation Syntax + +Lifetime annotations don't change how long any of the references involved live. +In the same way that functions can accept any type when the signature specifies +a generic type parameter, functions can accept references with any lifetime +when the signature specifies a generic lifetime parameter. What lifetime +annotations do is relate the lifetimes of multiple references to each other. + +Lifetime annotations have a slightly unusual syntax: the names of lifetime +parameters must start with an apostrophe `'`. The names of lifetime parameters +are usually all lowercase, and like generic types, their names are usually very +short. `'a` is the name most people use as a default. Lifetime parameter +annotations go after the `&` of a reference, and a space separates the lifetime +annotation from the reference's type. + +Here's some examples: we've got a reference to an `i32` without a lifetime +parameter, a reference to an `i32` that has a lifetime parameter named `'a`, +and a mutable reference to an `i32` that also has the lifetime `'a`: + +``` +&i32 // a reference +&'a i32 // a reference with an explicit lifetime +&'a mut i32 // a mutable reference with an explicit lifetime +``` + +One lifetime annotation by itself doesn't have much meaning: lifetime +annotations tell Rust how the generic lifetime parameters of multiple +references relate to each other. If we have a function with the parameter +`first` that is a reference to an `i32` that has the lifetime `'a`, and the +function has another parameter named `second` that is another reference to an +`i32` that also has the lifetime `'a`, these two lifetime annotations that have +the same name indicate that the references `first` and `second` must both live +as long as the same generic lifetime. + +### Lifetime Annotations in Function Signatures + +Let's look at lifetime annotations in the context of the `longest` function +we're working on. Just like generic type parameters, generic lifetime +parameters need to be declared within angle brackets between the function name +and the parameter list. The constraint we want to tell Rust about for the +references in the parameters and the return value is that they all must have +the same lifetime, which we'll name `'a` and add to each reference as shown in +Listing 10-21: + +Filename: src/main.rs + +``` +fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { + if x.len() > y.len() { + x + } else { + y + } +} +``` + +Listing 10-21: The `longest` function definition that specifies all the +references in the signature must have the same lifetime, `'a` + +This will compile and will produce the result we want when used with the `main` +function in Listing 10-19. + +The function signature now says that for some lifetime `'a`, the function will +get two parameters, both of which are string slices that live at least as long +as the lifetime `'a`. The function will return a string slice that also will +last at least as long as the lifetime `'a`. This is the contract we are telling +Rust we want it to enforce. + +By specifying the lifetime parameters in this function signature, we are not +changing the lifetimes of any values passed in or returned, but we are saying +that any values that do not adhere to this contract should be rejected by the +borrow checker. This function does not know (or need to know) exactly how long +`x` and `y` will live, but only needs to knows that there is some scope that +can be substituted for `'a` that will satisfy this signature. + +When annotating lifetimes in functions, the annotations go on the function +signature, and not in any of the code in the function body. This is because +Rust is able analyze the code within the function without any help, but when a +function has references to or from code outside that function, the lifetimes of +the arguments or return values will potentially be different each time the +function is called. This would be incredibly costly and often impossible for +Rust to figure out. In this case, we need to annotate the lifetimes ourselves. + +When concrete references are passed to `longest`, the concrete lifetime that +gets substituted for `'a` is the part of the scope of `x` that overlaps with +the scope of `y`. Since scopes always nest, another way to say this is that the +generic lifetime `'a` will get the concrete lifetime equal to the smaller of +the lifetimes of `x` and `y`. Because we've annotated the returned reference +with the same lifetime parameter `'a`, the returned reference will therefore be +guaranteed to be valid as long as the shorter of the lifetimes of `x` and `y`. + +Let's see how this restricts the usage of the `longest` function by passing in +references that have different concrete lifetimes. Listing 10-22 is a +straightforward example that should match your intuition from any language: +`string1` is valid until the end of the outer scope, `string2` is valid until +the end of the inner scope, and `result` references something that is valid +until the end of the outer scope. The borrow checker approves of this code; it +will compile and print `The longest string is long string is long` when run: + +Filename: src/main.rs + +``` +fn main() { + let string1 = String::from("long string is long"); + + { + let string2 = String::from("xyz"); + let result = longest(string1.as_str(), string2.as_str()); + println!("The longest string is {}", result); + } +} +``` + +Listing 10-22: Using the `longest` function with references to `String` values +that have different concrete lifetimes + +Next, let's try an example that will show that the lifetime of the reference in +`result` must be the smaller lifetime of the two arguments. We'll move the +declaration of the `result` variable outside the inner scope, but leave the +assignment of the value to the `result` variable inside the scope with +`string2`. Next, we'll move the `println!` that uses `result` outside of the +inner scope, after it has ended. The code in Listing 10-23 will not compile: + +Filename: src/main.rs + +``` +fn main() { + let string1 = String::from("long string is long"); + let result; + { + let string2 = String::from("xyz"); + result = longest(string1.as_str(), string2.as_str()); + } + println!("The longest string is {}", result); +} +``` + +Listing 10-23: Attempting to use `result` after `string2` has gone out of scope +won't compile + +If we try to compile this, we'll get this error: + +``` +error: `string2` does not live long enough + | +6 | result = longest(string1.as_str(), string2.as_str()); + | ------- borrow occurs here +7 | } + | ^ `string2` dropped here while still borrowed +8 | println!("The longest string is {}", result); +9 | } + | - borrowed value needs to live until here +``` + +The error is saying that in order for `result` to be valid for the `println!`, +`string2` would need to be valid until the end of the outer scope. Rust knows +this because we annotated the lifetimes of the function parameters and return +values with the same lifetime parameter, `'a`. + +We can look at this code as humans and see that `string1` is longer, and +therefore `result` will contain a reference to `string1`. Because `string1` has +not gone out of scope yet, a reference to `string1` will still be valid for the +`println!`. However, what we've told Rust with the lifetime parameters is that +the lifetime of the reference returned by the `longest` function is the same as +the smaller of the lifetimes of the references passed in. Therefore, the borrow +checker disallows the code in Listing 10-23 as possibly having an invalid +reference. + +Try designing some more experiments that vary the values and lifetimes of the +references passed in to the `longest` function and how the returned reference +is used. Make hypotheses about whether your experiments will pass the borrow +checker or not before you compile, then check to see if you're right! + +### Thinking in Terms of Lifetimes + +The exact way to specify lifetime parameters depends on what your function is +doing. For example, if we changed the implementation of the `longest` function +to always return the first argument rather than the longest string slice, we +wouldn't need to specify a lifetime on the `y` parameter. This code compiles: + +Filename: src/main.rs + +``` +fn longest<'a>(x: &'a str, y: &str) -> &'a str { + x +} +``` + +In this example, we've specified a lifetime parameter `'a` for the parameter +`x` and the return type, but not for the parameter `y`, since the lifetime of +`y` does not have any relationship with the lifetime of `x` or the return value. + +When returning a reference from a function, the lifetime parameter for the +return type needs to match the lifetime parameter of one of the arguments. If +the reference returned does *not* refer to one of the arguments, the only other +possibility is that it refers to a value created within this function, which +would be a dangling reference since the value will go out of scope at the end +of the function. Consider this attempted implementation of the `longest` +function that won't compile: + +Filename: src/main.rs + +``` +fn longest<'a>(x: &str, y: &str) -> &'a str { + let result = String::from("really long string"); + result.as_str() +} +``` + +Even though we've specified a lifetime parameter `'a` for the return type, this +implementation fails to compile because the return value lifetime is not +related to the lifetime of the parameters at all. Here's the error message we +get: + +``` +error: `result` does not live long enough + | +3 | result.as_str() + | ^^^^^^ does not live long enough +4 | } + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the block +at 1:44... + | +1 | fn longest<'a>(x: &str, y: &str) -> &'a str { + | ^ +``` + +The problem is that `result` will go out of scope and get cleaned up at the end +of the `longest` function, and we're trying to return a reference to `result` +from the function. There's no way we can specify lifetime parameters that would +change the dangling reference, and Rust won't let us create a dangling +reference. In this case, the best fix would be to return an owned data type +rather than a reference so that the calling function is then responsible for +cleaning up the value. + +Ultimately, lifetime syntax is about connecting the lifetimes of various +arguments and return values of functions. Once they're connected, Rust has +enough information to allow memory-safe operations and disallow operations that +would create dangling pointers or otherwise violate memory safety. + +### Lifetime Annotations in Struct Definitions + +Up until now, we've only defined structs to hold owned types. It is possible +for structs to hold references, but we need to add a lifetime annotation on +every reference in the struct's definition. Listing 10-24 has a struct named +`ImportantExcerpt` that holds a string slice: + +Filename: src/main.rs + +``` +struct ImportantExcerpt<'a> { + part: &'a str, +} + +fn main() { + let novel = String::from("Call me Ishmael. Some years ago..."); + let first_sentence = novel.split('.') + .next() + .expect("Could not find a '.'"); + let i = ImportantExcerpt { part: first_sentence }; +} +``` + +Listing 10-24: A struct that holds a reference, so its definition needs a +lifetime annotation + +This struct has one field, `part`, that holds a string slice, which is a +reference. Just like with generic data types, we have to declare the name of +the generic lifetime parameter inside angle brackets after the name of the +struct so that we can use the lifetime parameter in the body of the struct +definition. + +The `main` function here creates an instance of the `ImportantExcerpt` struct +that holds a reference to the first sentence of the `String` owned by the +variable `novel`. + +### Lifetime Elision + +In this section, we've learned that every reference has a lifetime, and we need +to specify lifetime parameters for functions or structs that use references. +However, in Chapter 4 we had a function in the "String Slices" section, shown +again in Listing 10-25, that compiled without lifetime annotations: + +Filename: src/lib.rs + +``` +fn first_word(s: &str) -> &str { + let bytes = s.as_bytes(); + + for (i, &item) in bytes.iter().enumerate() { + if item == b' ' { + return &s[0..i]; + } + } + + &s[..] +} +``` + +Listing 10-25: A function we defined in Chapter 4 that compiled without +lifetime annotations, even though the parameter and return type are references + +The reason this function compiles without lifetime annotations is historical: +in early versions of pre-1.0 Rust, this indeed wouldn't have compiled. Every +reference needed an explicit lifetime. At that time, the function signature +would have been written like this: + +``` +fn first_word<'a>(s: &'a str) -> &'a str { +``` + +After writing a lot of Rust code, the Rust team found that Rust programmers +were typing the same lifetime annotations over and over in particular +situations. These situations were predictable and followed a few deterministic +patterns. The Rust team then programmed these patterns into the Rust compiler's +code so that the borrow checker can infer the lifetimes in these situations +without forcing the programmer to explicitly add the annotations. + +We mention this piece of Rust history because it's entirely possible that more +deterministic patterns will emerge and be added to the compiler. In the future, +even fewer lifetime annotations might be required. + +The patterns programmed into Rust's analysis of references are called the +*lifetime elision rules*. These aren't rules for programmers to follow; the +rules are a set of particular cases that the compiler will consider, and if +your code fits these cases, you don't need to write the lifetimes explicitly. + +The elision rules don't provide full inference: if Rust deterministically +applies the rules but there's still ambiguity as to what lifetimes the +references have, it won't guess what the lifetime of the remaining references +should be. In this case, the compiler will give you an error that can be +resolved by adding the lifetime annotations that correspond to your intentions +for how the references relate to each other. + +First, some definitions: Lifetimes on function or method parameters are called +*input lifetimes*, and lifetimes on return values are called *output lifetimes*. + +Now, on to the rules that the compiler uses to figure out what lifetimes +references have when there aren't explicit annotations. The first rule applies +to input lifetimes, and the second two rules apply to output lifetimes. If the +compiler gets to the end of the three rules and there are still references that +it can't figure out lifetimes for, the compiler will stop with an error. + +1. Each parameter that is a reference gets its own lifetime parameter. In other + words, a function with one parameter gets one lifetime parameter: `fn + foo<'a>(x: &'a i32)`, a function with two arguments gets two separate + lifetime parameters: `fn foo<'a, 'b>(x: &'a i32, y: &'b i32)`, and so on. + +2. If there is exactly one input lifetime parameter, that lifetime is assigned + to all output lifetime parameters: `fn foo<'a>(x: &'a i32) -> &'a i32`. + +3. If there are multiple input lifetime parameters, but one of them is `&self` + or `&mut self` because this is a method, then the lifetime of `self` is + assigned to all output lifetime parameters. This makes writing methods much + nicer. + +Let's pretend we're the compiler and apply these rules to figure out what the +lifetimes of the references in the signature of the `first_word` function in +Listing 10-25 are. The signatures starts without any lifetimes associated with +the references: + +``` +fn first_word(s: &str) -> &str { +``` + +Then we (as the compiler) apply the first rule, which says each parameter gets +its own lifetime. We're going to call it `'a` as usual, so now the signature is: + +``` +fn first_word<'a>(s: &'a str) -> &str { +``` + +On to the second rule, which applies because there is exactly one input +lifetime. The second rule says the lifetime of the one input parameter gets +assigned to the output lifetime, so now the signature is: + +``` +fn first_word<'a>(s: &'a str) -> &'a str { +``` + +Now all the references in this function signature have lifetimes, and the +compiler can continue its analysis without needing the programmer to annotate +the lifetimes in this function signature. + +Let's do another example, this time with the `longest` function that had no +lifetime parameters when we started working with in Listing 10-20: + +``` +fn longest(x: &str, y: &str) -> &str { +``` + +Pretending we're the compiler again, let's apply the first rule: each parameter +gets its own lifetime. This time we have two parameters, so we have two +lifetimes: + +``` +fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &str { +``` + +Looking at the second rule, it doesn't apply since there is more than one input +lifetime. Looking at the third rule, this also does not apply because this is a +function rather than a method, so none of the parameters are `self`. So we're +out of rules, but we haven't figured out what the return type's lifetime is. +This is why we got an error trying to compile the code from Listing 10-20: the +compiler worked through the lifetime elision rules it knows, but still can't +figure out all the lifetimes of the references in the signature. + +Because the third rule only really applies in method signatures, let's look at +lifetimes in that context now, and see why the third rule means we don't have +to annotate lifetimes in method signatures very often. + +### Lifetime Annotations in Method Definitions + + + + +When we implement methods on a struct with lifetimes, the syntax is again the +same as that of generic type parameters that we showed in Listing 10-10: the +place that lifetime parameters are declared and used depends on whether the +lifetime parameter is related to the struct fields or the method arguments and +return values. + +Lifetime names for struct fields always need to be declared after the `impl` +keyword and then used after the struct's name, since those lifetimes are part +of the struct's type. + +In method signatures inside the `impl` block, references might be tied to the +lifetime of references in the struct's fields, or they might be independent. In +addition, the lifetime elision rules often make it so that lifetime annotations +aren't necessary in method signatures. Let's look at some examples using the +struct named `ImportantExcerpt` that we defined in Listing 10-24. + +First, here's a method named `level`. The only parameter is a reference to +`self`, and the return value is just an `i32`, not a reference to anything: + +``` +impl<'a> ImportantExcerpt<'a> { + fn level(&self) -> i32 { + 3 + } +} +``` + +The lifetime parameter declaration after `impl` and use after the type name is +required, but we're not required to annotate the lifetime of the reference to +`self` because of the first elision rule. + +Here's an example where the third lifetime elision rule applies: + +``` +impl<'a> ImportantExcerpt<'a> { + fn announce_and_return_part(&self, announcement: &str) -> &str { + println!("Attention please: {}", announcement); + self.part + } +} +``` + +There are two input lifetimes, so Rust applies the first lifetime elision rule +and gives both `&self` and `announcement` their own lifetimes. Then, because +one of the parameters is `&self`, the return type gets the lifetime of `&self`, +and all lifetimes have been accounted for. + +### The Static Lifetime + +There is *one* special lifetime we need to discuss: `'static`. The `'static` +lifetime is the entire duration of the program. All string literals have the +`'static` lifetime, which we can choose to annotate as follows: + +``` +let s: &'static str = "I have a static lifetime."; +``` + +The text of this string is stored directly in the binary of your program and +the binary of your program is always available. Therefore, the lifetime of all +string literals is `'static`. + + + + +You may see suggestions to use the `'static` lifetime in error message help +text, but before specifying `'static` as the lifetime for a reference, think +about whether the reference you have is one that actually lives the entire +lifetime of your program or not (or even if you want it to live that long, if +it could). Most of the time, the problem in the code is an attempt to create a +dangling reference or a mismatch of the available lifetimes, and the solution +is fixing those problems, not specifying the `'static` lifetime. + +### Generic Type Parameters, Trait Bounds, and Lifetimes Together + +Let's briefly look at the syntax of specifying generic type parameters, trait +bounds, and lifetimes all in one function! + +``` +use std::fmt::Display; + +fn longest_with_an_announcement<'a, T>(x: &'a str, y: &'a str, ann: T) -> &'a str + where T: Display +{ + println!("Announcement! {}", ann); + if x.len() > y.len() { + x + } else { + y + } +} +``` + +This is the `longest` function from Listing 10-21 that returns the longest of +two string slices, but with an extra argument named `ann`. The type of `ann` is +the generic type `T`, which may be filled in by any type that implements the +`Display` trait as specified by the `where` clause. This extra argument will be +printed out before the function compares the lengths of the string slices, +which is why the `Display` trait bound is necessary. Because lifetimes are a +type of generic, the declarations of both the lifetime parameter `'a` and the +generic type parameter `T` go in the same list within the angle brackets after +the function name. + +## Summary + +We covered a lot in this chapter! Now that you know about generic type +parameters, traits and trait bounds, and generic lifetime parameters, you're +ready to write code that isn't duplicated but can be used in many different +situations. Generic type parameters mean the code can be applied to different +types. Traits and trait bounds ensure that even though the types are generic, +those types will have the behavior the code needs. Relationships between the +lifetimes of references specified by lifetime annotations ensure that this +flexible code won't have any dangling references. And all of this happens at +compile time so that run-time performance isn't affected! + +Believe it or not, there's even more to learn in these areas: Chapter 17 will +discuss trait objects, which are another way to use traits. Chapter 19 will be +covering more complex scenarios involving lifetime annotations. Chapter 20 will +get to some advanced type system features. Up next, though, let's talk about +how to write tests in Rust so that we can make sure our code using all these +features is working the way we want it to! diff --git a/src/doc/book/second-edition/nostarch/chapter11.md b/src/doc/book/second-edition/nostarch/chapter11.md new file mode 100644 index 0000000000..52c849367c --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter11.md @@ -0,0 +1,1500 @@ + +[TOC] + +# Testing + +> Program testing can be a very effective way to show the presence of bugs, but +> it is hopelessly inadequate for showing their absence. +> +> Edsger W. Dijkstra, "The Humble Programmer" (1972) + +Correctness in our programs means that our code does what we intend for it to +do. Rust is a programming language that cares a lot about correctness, but +correctness is a complex topic and isn't easy to prove. Rust's type system +shoulders a huge part of this burden, but the type system cannot catch every +kind of incorrectness. As such, Rust includes support for writing software +tests within the language itself. + +As an example, say we write a function called `add_two` that adds two to a +number passed to it. This function's signature accepts an integer as a +parameter and returns an integer as a result. When we implement and compile +that function, Rust will do all the type checking and borrow checking that +we've seen so far. Those checks will make sure that, for instance, we aren't +passing a `String` value or an invalid reference to this function. What Rust +*can't* check is that this function will do precisely what we intend: return +the parameter plus two, rather than, say, the parameter plus 10 or the +parameter minus 50! That's where tests come in. + +We can write tests that assert, for example, that when we pass `3` to the +`add_two` function, we get `5` back. We can run these tests whenever we make +changes to our code to make sure any existing correct behavior has not changed. + +Testing is a complex skill, and we cannot hope to cover everything about how to +write good tests in one chapter of a book, so here we'll just discuss the +mechanics of Rust's testing facilities. We'll talk about the annotations and +macros available to you when writing your tests, the default behavior and +options provided for running your tests, and how to organize tests into unit +tests and integration tests. + +## How to Write Tests + +Tests are Rust functions that verify non-test code is functioning in the +program in the expected manner. The bodies of test functions typically contain +some setup, running the code we want to test, then asserting that the results +are what we expect. Let's look at the features Rust provides specifically for +writing tests: the `test` attribute, a few macros, and the `should_panic` +attribute. + +### The Anatomy of a Test Function + +At its simplest, a test in Rust is a function that's annotated with the `test` +attribute. Attributes are metadata about pieces of Rust code: the `derive` +attribute that we used with structs in Chapter 5 is one example. To make a +function into a test function, we add `#[test]` on the line before `fn`. When +we run our tests with the `cargo test` command, Rust will build a test runner +binary that runs the functions annotated with the `test` attribute and reports +on whether each test function passes or fails. + + + + +We saw in Chapter 7 that when you make a new library project with Cargo, a test +module with a test function in it is automatically generated for us. This is to +help us get started writing our tests, since we don't have to go look up the +exact structure and syntax of test functions every time we start a new project. +We can add as many additional test functions and as many test modules as we +want, though! + +We're going to explore some aspects of how tests work by experimenting with the +template test generated for us, without actually testing any code. Then we'll +write some real-world tests that call some code that we've written and assert +that its behavior is correct. + +Let's create a new library project called `adder`: + +``` +$ cargo new adder + Created library `adder` project +$ cd adder +``` + +The contents of the `src/lib.rs` file in your adder library should be as +follows: + +Filename: src/lib.rs + +``` +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + } +} +``` + +Listing 11-1: The test module and function generated automatically for us by +`cargo new` + +For now, let's ignore the top two lines and focus on the function to see how it +works. Note the `#[test]` annotation before the `fn` line: this attribute +indicates this is a test function, so that the test runner knows to treat this +function as a test. We could also have non-test functions in the `tests` module +to help set up common scenarios or perform common operations, so we need to +indicate which functions are tests with the `#[test]` attribute. + +The function currently has no body, which means there is no code to fail the +test; an empty test is a passing test! Let's run it and see that this test +passes. + +The `cargo test` command runs all tests we have in our project, as shown in +Listing 11-2: + +``` +$ cargo test + Compiling adder v0.1.0 (file:///projects/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.22 secs + Running target/debug/deps/adder-ce99bcc2479f4607 + +running 1 test +test tests::it_works ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + + Doc-tests adder + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +``` + +Listing 11-2: The output from running the one automatically generated test + +Cargo compiled and ran our test. After the `Compiling`, `Finished`, and +`Running` lines, we see the line `running 1 test`. The next line shows the name +of the generated test function, called `it_works`, and the result of running +that test, `ok`. Then we see the overall summary of running the tests: `test +result: ok.` means all the tests passed. `1 passed; 0 failed` adds up the +number of tests that passed or failed. + +We don't have any tests we've marked as ignored, so the summary says `0 +ignored`. We're going to talk about ignoring tests in the next section on +different ways to run tests. The `0 measured` statistic is for benchmark tests +that measure performance. Benchmark tests are, as of this writing, only +available in nightly Rust. See Appendix D for more information about nightly +Rust. + +The next part of the test output that starts with `Doc-tests adder` is for the +results of any documentation tests. We don't have any documentation tests yet, +but Rust can compile any code examples that appear in our API documentation. +This feature helps us keep our docs and our code in sync! We'll be talking +about how to write documentation tests in the "Documentation Comments" section +of Chapter 14. We're going to ignore the `Doc-tests` output for now. + + + + +Let's change the name of our test and see how that changes the test output. +Give the `it_works` function a different name, such as `exploration`, like so: + +Filename: src/lib.rs + +``` +#[cfg(test)] +mod tests { + #[test] + fn exploration() { + } +} +``` + +And run `cargo test` again. In the output, we'll now see `exploration` instead +of `it_works`: + +``` +running 1 test +test tests::exploration ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured +``` + +Let's add another test, but this time we'll make a test that fails! Tests fail +when something in the test function panics. We talked about the simplest way to +cause a panic in Chapter 9: call the `panic!` macro! Type in the new test so +that your `src/lib.rs` now looks like Listing 11-3: + +Filename: src/lib.rs + +``` +#[cfg(test)] +mod tests { + #[test] + fn exploration() { + } + + #[test] + fn another() { + panic!("Make this test fail"); + } +} +``` + +Listing 11-3: Adding a second test; one that will fail since we call the +`panic!` macro + +And run the tests again with `cargo test`. The output should look like Listing +11-4, which shows that our `exploration` test passed and `another` failed: + +``` +running 2 tests +test tests::exploration ... ok +test tests::another ... FAILED + +failures: + +---- tests::another stdout ---- + thread 'tests::another' panicked at 'Make this test fail', src/lib.rs:9 +note: Run with `RUST_BACKTRACE=1` for a backtrace. + +failures: + tests::another + +test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured + +error: test failed +``` + +Listing 11-4: Test results when one test passes and one test fails + +Instead of `ok`, the line `test tests::another` says `FAILED`. We have two new +sections between the individual results and the summary: the first section +displays the detailed reason for the test failures. In this case, `another` +failed because it `panicked at 'Make this test fail'`, which happened on +*src/lib.rs* line 9. The next section lists just the names of all the failing +tests, which is useful when there are lots of tests and lots of detailed +failing test output. We can use the name of a failing test to run just that +test in order to more easily debug it; we'll talk more about ways to run tests +in the next section. + +Finally, we have the summary line: overall, our test result is `FAILED`. We had +1 test pass and 1 test fail. + +Now that we've seen what the test results look like in different scenarios, +let's look at some macros other than `panic!` that are useful in tests. + +### Checking Results with the `assert!` Macro + +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 `true`, +`assert!` does nothing and the test passes. If the value is `false`, `assert!` +calls the `panic!` macro, which causes the test to fail. This is one macro that +helps us check that our code is functioning in the way we intend. + + + + +Remember all the way back in Chapter 5, Listing 5-9, where we had a `Rectangle` +struct and a `can_hold` method, repeated here in Listing 11-5. Let's put this +code in *src/lib.rs* instead of *src/main.rs* and write some tests for it using +the `assert!` macro. + + + +Filename: src/lib.rs + +``` +#[derive(Debug)] +pub struct Rectangle { + length: u32, + width: u32, +} + +impl Rectangle { + pub fn can_hold(&self, other: &Rectangle) -> bool { + self.length > other.length && self.width > other.width + } +} +``` + +Listing 11-5: 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 +for the `assert!` macro. In Listing 11-6, let's write a test that exercises the +`can_hold` method by creating a `Rectangle` instance that has a length of 8 and +a width of 7, and asserting that it can hold another `Rectangle` instance that +has a length of 5 and a width of 1: + +Filename: src/lib.rs + +``` +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn larger_can_hold_smaller() { + let larger = Rectangle { length: 8, width: 7 }; + let smaller = Rectangle { length: 5, width: 1 }; + + assert!(larger.can_hold(&smaller)); + } +} +``` + +Listing 11-6: A test for `can_hold` that checks that a larger rectangle indeed +holds a smaller rectangle + +Note that we've added a new line inside the `tests` module: `use super::*;`. +The `tests` module is a regular module that follows the usual visibility rules +we covered in Chapter 7. Because we're in an inner module, we need to bring the +code under test in the outer module into the scope of the inner module. We've +chosen to use a glob here so that anything we define in the outer module is +available to this `tests` module. + +We've named our test `larger_can_hold_smaller`, and we've created the two +`Rectangle` instances that we need. Then we called the `assert!` macro and +passed it the result of calling `larger.can_hold(&smaller)`. This expression is +supposed to return `true`, so our test should pass. Let's find out! + +``` +running 1 test +test tests::larger_can_hold_smaller ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured +``` + +It does pass! Let's add another test, this time asserting that a smaller +rectangle cannot hold a larger rectangle: + +Filename: src/lib.rs + +``` +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn larger_can_hold_smaller() { + let larger = Rectangle { length: 8, width: 7 }; + let smaller = Rectangle { length: 5, width: 1 }; + + assert!(larger.can_hold(&smaller)); + } + + #[test] + fn smaller_can_hold_larger() { + let larger = Rectangle { length: 8, width: 7 }; + let smaller = Rectangle { length: 5, width: 1 }; + + assert!(!smaller.can_hold(&larger)); + } +} +``` + +Because the correct result of the `can_hold` function in this case is `false`, +we need to negate that result before we pass it to the `assert!` macro. This +way, our test will pass if `can_hold` returns `false`: + +``` +running 2 tests +test tests::smaller_can_hold_larger ... ok +test tests::larger_can_hold_smaller ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured +``` + +Two passing tests! Now let's see what happens to our test results if we +introduce a bug in our code. Let's change the implementation of the `can_hold` +method to have a less-than sign when it compares the lengths where it's +supposed to have a greater-than sign: + +``` +#[derive(Debug)] +pub struct Rectangle { + length: u32, + width: u32, +} + +impl Rectangle { + pub fn can_hold(&self, other: &Rectangle) -> bool { + self.length < other.length && self.width > other.width + } +} +``` + +Running the tests now produces: + +``` +running 2 tests +test tests::smaller_can_hold_larger ... ok +test tests::larger_can_hold_smaller ... FAILED + +failures: + +---- tests::larger_can_hold_smaller stdout ---- + thread 'tests::larger_can_hold_smaller' panicked at 'assertion failed: + larger.can_hold(&smaller)', src/lib.rs:22 +note: Run with `RUST_BACKTRACE=1` for a backtrace. + +failures: + tests::larger_can_hold_smaller + +test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured +``` + +Our tests caught the bug! Since `larger.length` is 8 and `smaller.length` is 5, +the comparison of the lengths in `can_hold` now returns `false` since 8 is not +less than 5. + +### Testing Equality with the `assert_eq!` and `assert_ne!` Macros + +A common way to test functionality is to take the result of the code under test +and the value we expect the code to return and check that they're equal. We +could do this using the `assert!` macro and passing it an expression using the +`==` operator. However, this is such a common test that the standard library +provides a pair of macros to perform this test more conveniently: `assert_eq!` +and `assert_ne!`. These macros compare two arguments for equality or +inequality, respectively. They'll also print out the two values if the +assertion fails, so that it's easier to see *why* the test failed, while the +`assert!` macro only tells us that it got a `false` value for the `==` +expression, not the values that lead to the `false` value. + +In Listing 11-7, let's write a function named `add_two` that adds two to its +parameter and returns the result. Then let's test this function using the +`assert_eq!` macro: + +Filename: src/lib.rs + +``` +pub fn add_two(a: i32) -> i32 { + a + 2 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_adds_two() { + assert_eq!(4, add_two(2)); + } +} +``` + +Listing 11-7: Testing the function `add_two` using the `assert_eq!` macro + +Let's check that it passes! + +``` +running 1 test +test tests::it_adds_two ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured +``` + +The first argument we gave to the `assert_eq!` macro, 4, is equal to the result +of calling `add_two(2)`. We see a line for this test that says `test +tests::it_adds_two ... ok`, and the `ok` text indicates that our test passed! + +Let's introduce a bug into our code to see what it looks like when a test that +uses `assert_eq!` fails. Change the implementation of the `add_two` function to +instead add 3: + +``` +pub fn add_two(a: i32) -> i32 { + a + 3 +} +``` + +And run the tests again: + +``` +running 1 test +test tests::it_adds_two ... FAILED + +failures: + +---- tests::it_adds_two stdout ---- + thread 'tests::it_adds_two' panicked at 'assertion failed: `(left == + right)` (left: `4`, right: `5`)', src/lib.rs:11 +note: Run with `RUST_BACKTRACE=1` for a backtrace. + +failures: + tests::it_adds_two + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured +``` + +Our test caught the bug! The `it_adds_two` test failed with the message `` +assertion failed: `(left == right)` (left: `4`, right: `5`) ``. This message is +useful and helps us get started debugging: it says the `left` argument to +`assert_eq!` was 4, but the `right` argument, where we had `add_two(2)`, was 5. + +Note that in some languages and test frameworks, the parameters to the +functions that assert two values are equal are called `expected` and `actual` +and the order in which we specify the arguments matters. However, in Rust, +they're called `left` and `right` instead, and the order in which we specify +the value we expect and the value that the code under test produces doesn't +matter. We could have written the assertion in this test as +`assert_eq!(add_two(2), 4)`, which would result in a failure message that says +`` assertion failed: `(left == right)` (left: `5`, right: `4`) ``. + +The `assert_ne!` macro will pass if the two values we give to it are not equal +and fail if they are equal. This macro is most useful for cases when we're not +sure exactly what a value *will* be, but we know what the value definitely +*won't* be, if our code is functioning as we intend. For example, if we have a +function that is guaranteed to change its input in some way, but the way in +which the input is changed depends on the day of the week that we run our +tests, the best thing to assert might be that the output of the function is not +equal to the input. + +Under the surface, the `assert_eq!` and `assert_ne!` macros use the operators +`==` and `!=`, respectively. When the assertions fail, these macros print their +arguments using debug formatting, which means the values being compared must +implement the `PartialEq` and `Debug` traits. All of the primitive types and +most of the standard library types implement these traits. For structs and +enums that you define, you'll need to implement `PartialEq` in order to be able +to assert that values of those types are equal or not equal. You'll need to +implement `Debug` in order to be able to print out the values in the case that +the assertion fails. Because both of these traits are derivable traits, as we +mentioned in Chapter 5, this is usually as straightforward as adding the +`#[derive(PartialEq, Debug)]` annotation to your struct or enum definition. See +Appendix C for more details about these and other derivable traits. + +### Custom Failure Messages + +We can also add a custom message to be printed with the failure message as +optional arguments to `assert!`, `assert_eq!`, and `assert_ne!`. Any arguments +specified after the one required argument to `assert!` or the two required +arguments to `assert_eq!` and `assert_ne!` are passed along to the `format!` +macro that we talked about in Chapter 8, so you can pass a format string that +contains `{}` placeholders and values to go in the placeholders. Custom +messages are useful in order to document what an assertion means, so that when +the test fails, we have a better idea of what the problem is with the code. + +For example, let's say we have a function that greets people by name, and we +want to test that the name we pass into the function appears in the output: + +Filename: src/lib.rs + +``` +pub fn greeting(name: &str) -> String { + format!("Hello {}!", name) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn greeting_contains_name() { + let result = greeting("Carol"); + assert!(result.contains("Carol")); + } +} +``` + +The requirements for this program haven't been agreed upon yet, and we're +pretty sure the `Hello` text at the beginning of the greeting will change. We +decided we don't want to have to update the test for the name when that +happens, so instead of checking for exact equality to the value returned from +the `greeting` function, we're just going to assert that the output contains +the text of the input parameter. + +Let's introduce a bug into this code to see what this test failure looks like, +by changing `greeting` to not include `name`: + +``` +pub fn greeting(name: &str) -> String { + String::from("Hello!") +} +``` + +Running this test produces: + +``` +running 1 test +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 +note: Run with `RUST_BACKTRACE=1` for a backtrace. + +failures: + tests::greeting_contains_name +``` + +This just tells us that the assertion failed and which line the assertion is +on. A more useful failure message in this case would print the value we did get +from the `greeting` function. Let's change the test function to have a custom +failure message made from a format string with a placeholder filled in with the +actual value we got from the `greeting` function: + +``` +#[test] +fn greeting_contains_name() { + let result = greeting("Carol"); + assert!( + result.contains("Carol"), + "Greeting did not contain name, value was `{}`", result + ); +} +``` + +Now if we run the test again, we'll get a much more informative error message: + +``` +---- tests::greeting_contains_name stdout ---- + thread 'tests::greeting_contains_name' panicked at 'Result did not contain + name, value was `Hello`', src/lib.rs:12 +note: Run with `RUST_BACKTRACE=1` for a backtrace. +``` + +We can see the value we actually got in the test output, which would help us +debug what happened instead of what we were expecting to happen. + +### Checking for Panics with `should_panic` + +In addition to checking that our code returns the correct values we expect, +it's also important to check that our code handles error conditions as we +expect. For example, consider the `Guess` type that we created in Chapter 9 in +Listing 9-8. Other code that uses `Guess` is depending on the guarantee that +`Guess` instances will only contain values between 1 and 100. We can write a +test that ensures that attempting to create a `Guess` instance with a value +outside that range panics. + +We can do this by adding another attribute, `should_panic`, to our test +function. This attribute makes a test pass if the code inside the function +panics, and the test will fail if the code inside the function does non panic. + +Listing 11-8 shows how we'd write a test that checks the error conditions of +`Guess::new` happen when we expect: + +Filename: src/lib.rs + +``` +struct Guess { + value: u32, +} + +impl Guess { + pub fn new(value: u32) -> Guess { + if value < 1 || value > 100 { + panic!("Guess value must be between 1 and 100, got {}.", value); + } + + Guess { + value: value, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn greater_than_100() { + Guess::new(200); + } +} +``` + +Listing 11-8: Testing that a condition will cause a `panic!` + +The `#[should_panic]` attribute goes after the `#[test]` attribute and before +the test function it applies to. Let's see what it looks like when this test +passes: + +``` +running 1 test +test tests::greater_than_100 ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured +``` + +Looks good! Now let's introduce a bug in our code, by removing the condition +that the `new` function will panic if the value is greater than 100: + +``` +impl Guess { + pub fn new(value: u32) -> Guess { + if value < 1 { + panic!("Guess value must be between 1 and 100, got {}.", value); + } + + Guess { + value: value, + } + } +} +``` + +If we run the test from Listing 11-8, it will fail: + +``` +running 1 test +test tests::greater_than_100 ... FAILED + +failures: + +failures: + tests::greater_than_100 + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured +``` + +We don't get a very helpful message in this case, but once we look at the test +function, we can see that it's annotated with `#[should_panic]`. The failure we +got means that the code in the function, `Guess::new(200)`, did not cause a +panic. + +`should_panic` tests can be imprecise, however, because they only tell us that +the code has caused some panic. A `should_panic` test would pass even if the +test panics for a different reason than the one we were expecting to happen. To +make `should_panic` tests more precise, we can add an optional `expected` +parameter to the `should_panic` attribute. The test harness will make sure that +the failure message contains the provided text. For example, consider the +modified code for `Guess` in Listing 11-9 where the `new` function panics with +different messages depending on whether the value was too small or too large: + +Filename: src/lib.rs + +``` +struct Guess { + value: u32, +} + +impl Guess { + pub fn new(value: u32) -> Guess { + if value < 1 { + panic!("Guess value must be greater than or equal to 1, got {}.", + value); + } else if value > 100 { + panic!("Guess value must be less than or equal to 100, got {}.", + value); + } + + Guess { + value: value, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic(expected = "Guess value must be less than or equal to 100")] + fn greater_than_100() { + Guess::new(200); + } +} +``` + +Listing 11-9: Testing that a condition will cause a `panic!` with a particular +panic message + +This test will pass, because the value we put in the `expected` parameter of +the `should_panic` attribute is a substring of the message that the +`Guess::new` function panics with. We could have specified the whole panic +message that we expect, which in this case would be `Guess value must be less +than or equal to 100, got 200.` It depends on how much of the panic message is +unique or dynamic and how precise you want your test to be. In this case, a +substring of the panic message is enough to ensure that the code in the +function that gets run is the `else if value > 100` case. + +To see what happens when a `should_panic` test with an `expected` message +fails, let's again introduce a bug into our code by swapping the bodies of the +`if value < 1` and the `else if value > 100` blocks: + +``` +if value < 1 { + panic!("Guess value must be less than or equal to 100, got {}.", value); +} else if value > 100 { + panic!("Guess value must be greater than or equal to 1, got {}.", value); +} +``` + +This time when we run the `should_panic` test, it will fail: + +``` +running 1 test +test tests::greater_than_100 ... FAILED + +failures: + +---- tests::greater_than_100 stdout ---- + thread 'tests::greater_than_100' panicked at 'Guess value must be greater + than or equal to 1, got 200.', src/lib.rs:10 +note: Run with `RUST_BACKTRACE=1` for a backtrace. +note: Panic did not include expected string 'Guess value must be less than or +equal to 100' + +failures: + tests::greater_than_100 + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured +``` + +The failure message indicates that this test did indeed panic as we expected, +but the panic message `did not include expected string 'Guess value must be +less than or equal to 100'`. We can see the panic message that we did get, +which in this case was `Guess value must be greater than or equal to 1, got +200.` We could then start figuring out where our bug was! + +Now that we've gone over ways to write tests, let's look at what is happening +when we run our tests and talk about the different options we can use with +`cargo test`. + +## Controlling How Tests are Run + +Just as `cargo run` compiles your code and then runs the resulting binary, +`cargo test` compiles your code in test mode and runs the resulting test +binary. There are options you can use to change the default behavior of `cargo +test`. For example, the default behavior of the binary produced by `cargo test` +is to run all the tests in parallel and capture output generated during test +runs, preventing it from being displayed to make it easier to read the output +related to the test results. You can change this default behavior by specifying +command line options. + +Some command line options can be passed to `cargo test`, and some need to be +passed instead to the resulting test binary. To separate these two types of +arguments, you list the arguments that go to `cargo test`, then the separator +`--`, and then the arguments that go to the test binary. Running `cargo test +--help` will tell you about the options that go with `cargo test`, and running +`cargo test -- --help` will tell you about the options that go after the +separator `--`. + +### Running Tests in Parallel or Consecutively + + + + +When multiple tests are run, by default they run in parallel using threads. +This means the tests will finish running faster, so that we can get faster +feedback on whether or not our code is working. Since the tests are running at +the same time, you should take care that your tests do not depend on each other +or on any shared state, including a shared environment such as the current +working directory or environment variables. + +For example, say each of your tests runs some code that creates a file on disk +named `test-output.txt` and writes some data to that file. Then each test reads +the data in that file and asserts that the file contains a particular value, +which is different in each test. Because the tests are all run at the same +time, one test might overrwrite the file between when another test writes and +reads the file. The second test will then fail, not because the code is +incorrect, but because the tests have interfered with each other while running +in parallel. One solution would be to make sure each test writes to a different +file; another solution is to run the tests one at a time. + +If you don't want to run the tests in parallel, or if you want more +fine-grained control over the number of threads used, you can send the +`--test-threads` flag and the number of threads you want to use to the test +binary. For example: + +``` +$ cargo test -- --test-threads=1 +``` + +We set the number of test threads to 1, telling the program not to use any +parallelism. This will take longer than running them in parallel, but the tests +won't be potentially interfering with each other if they share state. + +### Showing Function Output + +By default, if a test passes, Rust's test library captures anything printed to +standard output. For example, if we call `println!` in a test and the test +passes, we won't see the `println!` output in the terminal: we'll only see the +line that says the test passed. If a test fails, we'll see whatever was printed +to standard output with the rest of the failure message. + +For example, Listing 11-10 has a silly function that prints out the value of +its parameter and then returns 10. We then have a test that passes and a test +that fails: + +Filename: src/lib.rs + +``` +fn prints_and_returns_10(a: i32) -> i32 { + println!("I got the value {}", a); + 10 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn this_test_will_pass() { + let value = prints_and_returns_10(4); + assert_eq!(10, value); + } + + #[test] + fn this_test_will_fail() { + let value = prints_and_returns_10(8); + assert_eq!(5, value); + } +} +``` + +Listing 11-10: Tests for a function that calls `println!` + +The output we'll see when we run these tests with `cargo test` is: + +``` +running 2 tests +test tests::this_test_will_pass ... ok +test tests::this_test_will_fail ... FAILED + +failures: + +---- tests::this_test_will_fail stdout ---- + I got the value 8 +thread 'tests::this_test_will_fail' panicked at 'assertion failed: `(left == +right)` (left: `5`, right: `10`)', src/lib.rs:19 +note: Run with `RUST_BACKTRACE=1` for a backtrace. + +failures: + tests::this_test_will_fail + +test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured +``` + +Note that nowhere in this output do we see `I got the value 4`, which is what +gets printed when the test that passes runs. That output has been captured. The +output from the test that failed, `I got the value 8`, appears in the section +of the test summary output that also shows the cause of the test failure. + +If we want to be able to see printed values for passing tests as well, the +output capture behavior can be disabled by using the `--nocapture` flag: + +``` +$ cargo test -- --nocapture +``` + +Running the tests from Listing 11-10 again with the `--nocapture` flag now +shows: + +``` +running 2 tests +I got the value 4 +I got the value 8 +test tests::this_test_will_pass ... ok +thread 'tests::this_test_will_fail' panicked at 'assertion failed: `(left == +right)` (left: `5`, right: `10`)', src/lib.rs:19 +note: Run with `RUST_BACKTRACE=1` for a backtrace. +test tests::this_test_will_fail ... FAILED + +failures: + +failures: + tests::this_test_will_fail + +test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured +``` + +Note that the output for the tests and the test results is interleaved; this is +because the tests are running in parallel as we talked about in the previous +section. Try using both the `--test-threads=1` option and the `--nocapture` +function and see what the output looks like then! + +### Running a Subset of Tests by Name + +Sometimes, running a full test suite can take a long time. If you're working on +code in a particular area, you might want to run only the tests pertaining to +that code. You can choose which tests to run by passing `cargo test` the name +or names of the test/s you want to run as an argument. + +To demonstrate how to run a subset of tests, we'll create three tests for our +`add_two` function as shown in Listing 11-11 and choose which ones to run: + +Filename: src/lib.rs + +``` +pub fn add_two(a: i32) -> i32 { + a + 2 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn add_two_and_two() { + assert_eq!(4, add_two(2)); + } + + #[test] + fn add_three_and_two() { + assert_eq!(5, add_two(3)); + } + + #[test] + fn one_hundred() { + assert_eq!(102, add_two(100)); + } +} +``` + +Listing 11-11: Three tests with a variety of names + +If we run the tests without passing any arguments, as we've already seen, all +the tests will run in parallel: + +``` +running 3 tests +test tests::add_two_and_two ... ok +test tests::add_three_and_two ... ok +test tests::one_hundred ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured +``` + +#### Running Single Tests + +We can pass the name of any test function to `cargo test` to run only that test: + +``` +$ cargo test one_hundred + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running target/debug/deps/adder-06a75b4a1f2515e9 + +running 1 test +test tests::one_hundred ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured +``` + +We can't specify the names of multiple tests in this way, only the first value +given to `cargo test` will be used. + +#### Filtering to Run Multiple Tests + +However, we can specify part of a test name, and any test whose name matches +that value will get run. For example, since two of our tests' names contain +`add`, we can run those two by running `cargo test add`: + +``` +$ cargo test add + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running target/debug/deps/adder-06a75b4a1f2515e9 + +running 2 tests +test tests::add_two_and_two ... ok +test tests::add_three_and_two ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured +``` + +This ran all tests with `add` in the name. Also note that the module in which +tests appear becomes part of the test's name, so we can run all the tests in a +module by filtering on the module's name. + + + + +### Ignore Some Tests Unless Specifically Requested + +Sometimes a few specific tests can be very time-consuming to execute, so you +might want to exclude them during most runs of `cargo test`. Rather than +listing as arguments all tests you do want to run, we can instead annotate the +time consuming tests with the `ignore` attribute to exclude them: + +Filename: src/lib.rs + +``` +#[test] +fn it_works() { + assert!(true); +} + +#[test] +#[ignore] +fn expensive_test() { + // code that takes an hour to run +} +``` + +We add the `#[ignore]` line to the test we want to exlcude, after `#[test]`. +Now if we run our tests, we'll see `it_works` runs, but `expensive_test` does +not: + +``` +$ cargo test + Compiling adder v0.1.0 (file:///projects/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.24 secs + Running target/debug/deps/adder-ce99bcc2479f4607 + +running 2 tests +test expensive_test ... ignored +test it_works ... ok + +test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured + + Doc-tests adder + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +``` + +`expensive_test` is listed as `ignored`. If we want to run only the ignored +tests, we can ask for them to be run with `cargo test -- --ignored`: + + + + + + + +``` +$ cargo test -- --ignored + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running target/debug/deps/adder-ce99bcc2479f4607 + +running 1 test +test expensive_test ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured +``` + +By controlling which tests run, you can make sure your `cargo test` results +will be fast. When you're at a point that it makes sense to check the results +of the `ignored` tests and you have time to wait for the results, you can +choose to run `cargo test -- --ignored` instead. + +## Test Organization + +As mentioned at the start of the chapter, testing is a large discipline, and +different people use different terminology and organization. The Rust community +tends to think about tests in terms of two main categories: *unit tests* and +*integration tests*. Unit tests are smaller and more focused, testing one +module in isolation at a time, and can test private interfaces. Integration +tests are entirely external to your library, and use your code in the same way +any other external code would, using only the public interface and exercising +multiple modules per test. + +Both kinds of tests are important to ensure that the pieces of your library are +doing what you expect them to separately and together. + +### Unit Tests + +The purpose of unit tests is to test each unit of code in isolation from the +rest of the code, in order to be able to quickly pinpoint where code is and is +not working as expected. We put unit tests in the *src* directory, in each file +with the code that they're testing. The convention is that we create a module +named `tests` in each file to contain the test functions, and we annotate the +module with `cfg(test)`. + +#### The Tests Module and `#[cfg(test)]` + +The `#[cfg(test)]` annotation on the tests module tells Rust to compile and run +the test code only when we run `cargo test`, and not when we run `cargo build`. +This saves compile time when we only want to build the library, and saves space +in the resulting compiled artifact since the tests are not included. We'll see +that since integration tests go in a different directory, they don't need the +`#[cfg(test)]` annotation. Because unit tests go in the same files as the code, +though, we use `#[cfg(test)]`to specify that they should not be included in the +compiled result. + +Remember that when we generated the new `adder` project in the first section of +this chapter, Cargo generated this code for us: + +Filename: src/lib.rs + +``` +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + } +} +``` + +This is the automatically generated test module. The attribute `cfg` stands for +*configruation*, and tells Rust that the following item should only be included +given a certain configuration. In this case, the configuration is `test`, +provided by Rust for compiling and running tests. By using this attribute, +Cargo only compiles our test code if we actively run the tests with `cargo +test`. This includes any helper functions that might be within this module, in +addition to the functions annotated with `#[test]`. + +#### Testing Private Functions + +There's debate within the testing community about whether private functions +should be tested directly or not, and other languages make it difficult or +impossible to test private functions. Regardless of which testing ideology you +adhere to, Rust's privacy rules do allow you to test private functions. +Consider the code in Listing 11-12 with the private function `internal_adder`: + +Filename: src/lib.rs + +``` +pub fn add_two(a: i32) -> i32 { + internal_adder(a, 2) +} + +fn internal_adder(a: i32, b: i32) -> i32 { + a + b +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn internal() { + assert_eq!(4, internal_adder(2, 2)); + } +} +``` + +Listing 11-12: Testing a private function + + + + +Note that the `internal_adder` function is not marked as `pub`, but because +tests are just Rust code and the `tests` module is just another module, we can +import and call `internal_adder` in a test just fine. If you don't think +private functions should be tested, there's nothing in Rust that will compel +you to do so. + +### Integration Tests + +In Rust, integration tests are entirely external to your library. They use your +library in the same way any other code would, which means they can only call +functions that are part of your library's public API. Their purpose is to test +that many parts of your library work correctly together. Units of code that +work correctly by themselves could have problems when integrated, so test +coverage of the integrated code is important as well. To create integration +tests, you first need a *tests* directory. + +#### The *tests* Directory + +To write integration tests for our code, we need to make a *tests* directory at +the top level of our project directory, next to *src*. Cargo knows to look for +integration test files in this directory. We can then make as many test files +as we'd like in this directory, and Cargo will compile each of the files as an +individual crate. + +Let's give it a try! Keep the code from Listing 11-12 in *src/lib.rs*. Make a +*tests* directory, then make a new file named *tests/integration_test.rs*, and +enter the code in Listing 11-13. + +Filename: tests/integration_test.rs + +``` +extern crate adder; + +#[test] +fn it_adds_two() { + assert_eq!(4, adder::add_two(2)); +} +``` + +Listing 11-13: An integration test of a function in the `adder` crate + +We've added `extern crate adder` at the top, which we didn't need in the unit +tests. This is because each test in the `tests` directory is an entirely +separate crate, so we need to import our library into each of them. Integration +tests use the library like any other consumer of it would, by importing the +crate and using only the public API. + +We don't need to annotate any code in *tests/integration_test.rs* with +`#[cfg(test)]`. Cargo treats the `tests` directory specially and will only +compile files in this directory if we run `cargo test`. Let's try running +`cargo test` now: + +``` +cargo test + Compiling adder v0.1.0 (file:///projects/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.31 secs + Running target/debug/deps/adder-abcabcabc + +running 1 test +test tests::internal ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + + Running target/debug/deps/integration_test-ce99bcc2479f4607 + +running 1 test +test it_adds_two ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + + Doc-tests adder + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +``` + + + + +Now we have three sections of output: the unit tests, the integration test, and +the doc tests. The first section for the unit tests is the same as we have been +seeing: one line for each unit test (we have one named `internal` that we added +in Listing 11-12), then a summary line for the unit tests. + +The integration tests section starts with the line that says `Running +target/debug/deps/integration-test-ce99bcc2479f4607` (the hash at the end of +your output will be different). Then there's a line for each test function in +that integration test, and a summary line for the results of the integration +test just before the `Doc-tests adder` section starts. + +Note that adding more unit test functions in any *src* file will add more test +result lines to the unit tests section. Adding more test functions to the +integration test file we created will add more lines to the integration test +section. Each integration test file gets its own section, so if we add more +files in the *tests* directory, there will be more integration test sections. + +We can still run a particular integration test function by specifying the test +function's name as an argument to `cargo test`. To run all of the tests in a +particular integration test file, use the `--test` argument of `cargo test` +followed by the name of the file: + +``` +$ cargo test --test integration_test + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running target/debug/integration_test-952a27e0126bb565 + +running 1 test +test it_adds_two ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured +``` + +This tests only the file that we specified from the *tests* directory. + +#### Submodules in Integration Tests + +As you add more integration tests, you may want to make more than one file in +the *tests* directory to help organize them; for example, to group the test +functions by the functionality they're testing. As we mentioned, each file in +the *tests* directory is compiled as its own separate crate. + +Treating each integration test file as its own crate is useful to create +separate scopes that are more like the way end users will be using your crate. +However, this means files in the *tests* directory don't share the same +behavior as files in *src* do that we learned about in Chapter 7 regarding how +to separate code into modules and files. + +The different behavior of files in the *tests* directory is usually most +noticeable if you have a set of helper functions that would be useful in +multiple integration test files, and you try to follow the steps from Chapter 7 +to extract them into a common module. For example, if we create +*tests/common.rs* and place this function named `setup` in it, where we could +put some code that we want to be able to call from multiple test functions in +multiple test files: + +Filename: tests/common.rs + +``` +pub fn setup() { + // setup code specific to your library's tests would go here +} +``` + +If we run the tests again, we'll see a new section in the test output for the +*common.rs* file, even though this file doesn't contain any test functions, nor +are we calling the `setup` function from anywhere: + +``` +running 1 test +test tests::internal ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + + Running target/debug/deps/common-b8b07b6f1be2db70 + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured + + Running target/debug/deps/integration_test-d993c68b431d39df + +running 1 test +test it_adds_two ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + + Doc-tests adder + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +``` + + + +Having `common` show up in the test results with `running 0 tests` displayed +for it is not what we wanted; we just wanted to be able to share some code with +the other integration test files. + +In order to not have `common` show up in the test output, we need to use the +other method of extracting code into a file that we learned about in Chapter 7: +instead of creating *tests/common.rs*, we'll create *tests/common/mod.rs*. When +we move the `setup` function code into *tests/common/mod.rs* and get rid of the +*tests/common.rs* file, the section in the test output will no longer show up. +Files in subdirectories of the *tests* directory do not get compiled as +separate crates or have sections in the test output. + +Once we have *tests/common/mod.rs*, we can use it from any of the integration +test files as a module. Here's an example of calling the `setup` function from +the `it_adds_two` test in *tests/integration_test.rs*: + +Filename: tests/integration_test.rs + +``` +extern crate adder; + +mod common; + +#[test] +fn it_adds_two() { + common::setup(); + assert_eq!(4, adder::add_two(2)); +} +``` + +Note the `mod common;` declaration is the same as the module declarations we +did in Chapter 7. Then in the test function, we can call the `common::setup()` +function. + +#### Integration Tests for Binary Crates + +If our project is a binary crate that only contains a *src/main.rs* and does +not have a *src/lib.rs*, we aren't able to create integration tests in the +*tests* directory and use `extern crate` to import functions defined in +*src/main.rs*. Only library crates expose functions that other crates are able +to call and use; binary crates are meant to be run on their own. + +This is one of the reasons Rust projects that provide a binary have a +straightforward *src/main.rs* that calls logic that lives in *src/lib.rs*. With +that structure, integration tests *can* test the library crate by using `extern +crate` to cover the important functionality. If the important functionality +works, the small amount of code in *src/main.rs* will work as well, and that +small amount of code does not need to be tested. + +## Summary + +Rust's testing features provide a way to specify how code should function to +ensure it continues to work as we expect even as we make changes. Unit tests +exercise different parts of a library separately and can test private +implementation details. Integration tests cover the use of many parts of the +library working together, and they use the library's public API to test the +code in the same way external code will use it. Even though Rust's type system +and ownership rules help prevent some kinds of bugs, tests are still important +to help reduce logic bugs having to do with how your code is expected to behave. + +Let's put together the knowledge from this chapter and other previous chapters +and work on a project in the next chapter! diff --git a/src/doc/book/second-edition/nostarch/chapter12.md b/src/doc/book/second-edition/nostarch/chapter12.md new file mode 100644 index 0000000000..ec789020ea --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter12.md @@ -0,0 +1,1979 @@ + +[TOC] + +# An I/O Project Building a Small Grep + + + + + +This chapter is both a recap of the many skills you've learned so far and an +exploration of a few more standard library features. We're going to build a +command-line tool that interacts with file and command line input/output to +practice some of the Rust you now have under your belt. + +Rust's speed, safety, 'single binary' output, and cross-platform support make +it a good language for creating command line tools, so for our project we'll +make our own version of the classic command line tool `grep`. Grep is an +acronym for "Globally search a Regular Expression and Print." In the simplest +use case, `grep` searches a specified file for a specified string using the +following steps: + +- Take as arguments a filename and a string. +- Read the file. +- Find lines in the file that contain the string argument. +- Print out those lines. + +We'll also show how to use environment variables and print to standard error +instead of standard out; these techniques are commonly used in command line +tools. + +One Rust community member, Andrew Gallant, has already created a +fully-featured, very fast version of `grep`, called `ripgrep`. By comparison, +our version of `grep` will be fairly simple, this chapter will give you some of +the background knowledge to help you understand a real-world project like +`ripgrep`. + +This project will bring together a number of concepts you've learned so far: + +- Organizing code (using what we learned in modules, Chapter 7) +- Using vectors and strings (collections, Chapter 8) +- Handling errors (Chapter 9) +- Using traits and lifetimes where appropriate (Chapter 10) +- Writing tests (Chapter 11) + +We'll also briefly introduce closures, iterators, and trait objects, which +Chapters 13 and 17 will cover in detail. + +Let's create a new project with, as always, `cargo new`. We're calling our +project `greprs` to distinguish from the `grep` tool that you may already have +on your system: + +``` +$ cargo new --bin greprs + Created binary (application) `greprs` project +$ cd greprs +``` + +## Accepting Command Line Arguments + +Our first task is to make `greprs` able to accept its two command line +arguments: the filename and a string to search for. That is, we want to be able +to run our program with `cargo run`, a string to search for, and a path to a +file to search in, like so: + +``` +$ cargo run searchstring example-filename.txt +``` + +Right now, the program generated by `cargo new` ignores any arguments we give +it. There are some existing libraries on crates.io that can help us accept +command line arguments, but since we're learning, let's implement this +ourselves. + + + + +### Reading the Argument Values + +In order to be able to get the values of command line arguments passed to our +program, we'll need to call a function provided in Rust's standard library: +`std::env::args`. This function returns an *iterator* of the command line +arguments that were given to our program. We haven't discussed iterators yet, +and we'll cover them fully in Chapter 13, but for our purposes now we only need +to know two things about iterators: + +1. Iterators produce a series of values. +2. We can call the `collect` function on an iterator to turn it into a vector + containing all of the elements the iterator produces. + +Let's give it a try: use the code in Listing 12-1 to read any command line +arguments passed to our `greprs` program and collect them into a vector. + + + + +Filename: src/main.rs + +``` +use std::env; + +fn main() { + let args: Vec = env::args().collect(); + println!("{:?}", args); +} +``` + +Listing 12-1: Collect the command line arguments into a vector and print them +out + + + +First, we bring the `std::env` module into scope with a `use` statement so that +we can use its `args` function. Notice the `std::env::args` function is nested +in two levels of modules. As we talked about in Chapter 7, in cases where the +desired function is nested in more than one module, it's conventional to bring +the parent module into scope, rather than the function itself. This lets us +easily use other functions from `std::env`. It's also less ambiguous than +adding `use std::env::args;` then calling the function with just `args`; that +might look like a function that's defined in the current module. + + + + + +> Note: `std::env::args` will panic if any argument contains invalid Unicode. +> If you need to accept arguments containing invalid Unicode, use +> `std::env::args_os` instead. That function returns `OsString` values instead +> of `String` values. We've chosen to use `std::env::args` here for simplicity +> because `OsString` values differ per-platform and are more complex to work +> with than `String` values. + + + + + + +On the first line of `main`, we call `env::args`, and immediately use `collect` +to turn the iterator into a vector containing all of the iterator's values. The +`collect` function can be used to create many kinds of collections, so we +explicitly annotate the type of `args` to specify that we want a vector of +strings. Though we very rarely need to annotate types in Rust, `collect` is one +function you do often need to annotate because Rust isn't able to infer what +kind of collection you want. + +Finally, we print out the vector with the debug formatter, `:?`. Let's try +running our code with no arguments, and then with two arguments: + +``` +$ cargo run +["target/debug/greprs"] + +$ cargo run needle haystack +...snip... +["target/debug/greprs", "needle", "haystack"] +``` + + + + +You may notice that the first value in the vector is "target/debug/greprs", +which is the name of our binary. The reasons for this are out of the scope of +this chapter, but we'll need to remember this as we save the two arguments we +need. + +### Saving the Argument Values in Variables + +Printing out the value of the vector of arguments just illustrated that we're +able to access the values specified as command line arguments from our program. +That's not what we actually want to do, though, we want to save the values of +the two arguments in variables so that we can use the values in our program. +Let's do that as shown in Listing 12-2: + + + + +Filename: src/main.rs + +``` +use std::env; + +fn main() { + let args: Vec = env::args().collect(); + + let query = &args[1]; + let filename = &args[2]; + + println!("Searching for {}", query); + println!("In file {}", filename); +} +``` + +Listing 12-2: Create variables to hold the query argument and filename argument + + + +As we saw when we printed out the vector, the program's name takes up the first +value in the vector at `args[0]`, so we're starting at index `1`. The first +argument `greprs` takes is the string we're searching for, so we put a +reference to the first argument in the variable `query`. The second argument +will be the filename, so we put a reference to the second argument in the +variable `filename`. + +We're temporarily printing out the values of these variables, again to prove to +ourselves that our code is working as we intend. Let's try running this program +again with the arguments `test` and `sample.txt`: + +``` +$ cargo run test sample.txt + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running `target/debug/greprs test sample.txt` +Searching for test +In file sample.txt +``` + +Great, it's working! We're saving the values of the arguments that we need into +the right variables. Later we'll add some error handling to deal with +situations such as when the user provides no arguments, but for now we'll +ignore that and work on adding file reading capabilities instead. + +## Reading a File + +Next, we're going to read the file that we specify in the filename command line +argument. First, we need a sample file to test it with---the best kind of file +to use to make sure that `greprs` is working is one with a small amount of text +over multiple lines with some repeated words. Listing 12-3 has an Emily +Dickinson poem that will work well! Create a file called `poem.txt` at the root +level of your project, and enter the poem "I'm nobody! Who are you?": + +Filename: poem.txt + +``` +I'm nobody! Who are you? +Are you nobody, too? +Then there's a pair of us — don't tell! +They'd banish us, you know. + +How dreary to be somebody! +How public, like a frog +To tell your name the livelong day +To an admiring bog! +``` + +Listing 12-3: The poem "I'm nobody! Who are you?" by Emily Dickinson that will +make a good test case + + + + + +With that in place, edit *src/main.rs* and add code to open the file as shown +in Listing 12-4: + +Filename: src/main.rs + +``` +use std::env; +use std::fs::File; +use std::io::prelude::*; + +fn main() { + let args: Vec = env::args().collect(); + + let query = &args[1]; + let filename = &args[2]; + + println!("Searching for {}", query); + println!("In file {}", filename); + + let mut f = File::open(filename).expect("file not found"); + + let mut contents = String::new(); + f.read_to_string(&mut contents).expect("something went wrong reading the file"); + + println!("With text:\n{}", contents); +} +``` + +Listing 12-4: Reading the contents of the file specified by the second argument + + + +First, we add some more `use` statements to bring in relevant parts of the +standard library: we need `std::fs::File` for dealing with files, and +`std::io::prelude::*` contains various traits that are useful when doing I/O, +including file I/O. In the same way that Rust has a general prelude that brings +certain things into scope automatically, the `std::io` module has its own +prelude of common things you'll need when working with I/O. Unlike the default +prelude, we must explicitly `use` the prelude in `std::io`. + +In `main`, we've added three things: first, we get a mutable handle to the file +by calling the `File::open` function and passing it the value of the `filename` +variable. Second, we create a variable called `contents` and set it to a +mutable, empty `String`. This will hold the content of the file after we read +it in. Third, we call `read_to_string` on our file handle and pass a mutable +reference to `contents` as an argument. + +After those lines, we've again added temporary `println!` that prints out the +value in `contents` after we've read the file so we can check that our program +is working so far. + +Let's try running this code with any string as the first command line argument +(since we haven't implemented the searching part yet) and our *poem.txt* file +as the second argument: + +``` +$ cargo run the poem.txt + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running `target/debug/greprs the poem.txt` +Searching for the +In file poem.txt +With text: +I'm nobody! Who are you? +Are you nobody, too? +Then there's a pair of us — don't tell! +They'd banish us, you know. + +How dreary to be somebody! +How public, like a frog +To tell your name the livelong day +To an admiring bog! +``` + +Great! Our code read in and printed out the content of the file. We've got a +few flaws though: the `main` function has multiple responsibilities, and we're +not handling errors as well as we could be. While our program is still small, +these flaws aren't a big problem, but as our program grows, it will be harder +to fix them cleanly. It's good practice to begin refactoring early on when +developing a program, as it's much easier to refactor smaller amounts of code, +so we'll do that now. + +## Refactoring to Improve Modularity and Error Handling + +There are four problems that we'd like to fix to improve our program, and they +have to do with the way the program is structured and how it's handling +potential errors. + +First, our `main` function now performs two tasks: it parses arguments and +opens up files. For such a small function, this isn't a huge problem. However, +if we keep growing our program inside of `main`, the number of separate tasks +the `main` function handles will grow. As a function gains responsibilities, it +gets harder to reason about, harder to test, and harder to change without +breaking one of its parts. It's better to separate out functionality so that +each function is responsible for one task. + +This also ties into our second problem: while `query` and `filename` are +configuration variables to our program, variables like `f` and `contents` are +used to perform our program's logic. The longer `main` gets, the more variables +we're going to need to bring into scope; the more variables we have in scope, +the harder it is to keep track of the purpose of each. It's better to group the +configuration variables into one structure to make their purpose clear. + +The third problem is that we've used `expect` to print out an error message if +opening the file fails, but the error message only says `file not found`. There +are a number of ways that opening a file can fail besides a missing file: for +example, the file might exist, but we might not have permission to open it. +Right now, if we're in that situation, we'd print the `file not found` error +message that would give the user the wrong advice! + +Fourth, we use `expect` repeatedly to deal with different errors, and if the +user runs our programs without specifying enough arguments, they'll get an +"index out of bounds" error from Rust that doesn't clearly explain the problem. +It would be better if all our error handling code was in one place so that +future maintainers only have one place to consult in the code if the error +handling logic needs to change. Having all the error handling code in one place +will also help us to ensure that we're printing messages that will be +meaningful to our end users. + +Let's address these problems by refactoring our project. + +### Separation of Concerns for Binary Projects + +The organizational problem of having the `main` function responsible for +multiple tasks is common to many binary projects, so the Rust community has +developed a kind of guideline process for splitting up the separate concerns of +a binary program when `main` starts getting large. The process has the +following steps: + +1. Split your program into both a *main.rs* and a *lib.rs* and move your + program's logic into *lib.rs*. +2. While your command line parsing logic is small, it can remain in *main.rs*. +3. When the command line parsing logic starts getting complicated, extract it + from *main.rs* into *lib.rs* as well. +4. The responsibilities that remain in the `main` function after this process + should be: + * Calling the command line parsing logic with the argument values + * Setting up any other configuration + * Calling a `run` function in *lib.rs* + * If `run` returns an error, handling that error + +This pattern is all about separating concerns: *main.rs* handles running the +program, and *lib.rs* handles all of the logic of the task at hand. Because we +can't test the `main` function directly, this structure lets us test all of our +program's logic by moving it into functions in *lib.rs*. The only code that +remains in *main.rs* will be small enough to verify its correctness by reading +it. Let's re-work our program by following this process. + + + + +### Extracting the Argument Parser + +First, we'll extract the functionality for parsing arguments. Listing 12-5 +shows the new start of `main` that calls a new function `parse_config`, which +we're still going to define in *src/main.rs* for the moment: + +Filename: src/main.rs + +``` +fn main() { + let args: Vec = env::args().collect(); + + let (query, filename) = parse_config(&args); + + // ...snip... +} + +fn parse_config(args: &[String]) -> (&str, &str) { + let query = &args[1]; + let filename = &args[2]; + + (query, filename) +} +``` + +Listing 12-5: Extract a `parse_config` function from `main` + + + +We're still collecting the command line arguments into a vector, but instead of +assigning the argument value at index 1 to the variable `query` and the +argument value at index 2 to the variable `filename` within the `main` +function, we pass the whole vector to the `parse_config` function. The +`parse_config` function then holds the logic that knows which argument goes in +which variable, and passes the values back to `main`. We still create the +`query` and `filename` variables in `main`, but `main` no longer has the +responsibility of knowing how the command line arguments and variables +correspond. + +This may seem like overkill for our small program, but we're refactoring in +small, incremental steps. After making this change, run the program again to +verify that the argument parsing still works. It's good to check your progress +often, as that will help you identify the cause of problems when they occur. + +#### Grouping Configuration Values + +We can take another small step to improve this function further. At the moment, +we're returning a tuple, but then we immediately break that tuple up into +individual parts again. This is a sign that perhaps we don't have the right +abstraction yet. + +Another indicator that there's room for improvement is the `config` part of +`parse_config`, which implies that the two values we return are related and are +both part of one configuration value. We're not currently conveying this +meaning in the structure of the data other than grouping the two values into a +tuple: we could put the two values into one struct and give each of the struct +fields a meaningful name. This will make it easier for future maintainers of +this code to understand how the different values relate to each other and what +their purpose is. + + + +> Note: some people call this anti-pattern of using primitive values when a +> complex type would be more appropriate *primitive obsession*. + + + + +Listing 12-6 shows the addition of a struct named `Config` defined to have +fields named `query` and `filename`. We've also changed the `parse_config` +function to return an instance of the `Config` struct, and updated `main` to +use the struct fields rather than having separate variables: + +Filename: src/main.rs + +``` +fn main() { + let args: Vec = env::args().collect(); + + let config = parse_config(&args); + + println!("Searching for {}", config.query); + println!("In file {}", config.filename); + + let mut f = File::open(config.filename).expect("file not found"); + + // ...snip... +} + +struct Config { + query: String, + filename: String, +} + +fn parse_config(args: &[String]) -> Config { + let query = args[1].clone(); + let filename = args[2].clone(); + + Config { + query: query, + filename: filename, + } +} +``` + +Listing 12-6: Refactoring `parse_config` to return an instance of a `Config` +struct + + + +The signature of `parse_config` now indicates that it returns a `Config` value. +In the body of `parse_config`, where we used to return string slices that +reference `String` values in `args`, we've now chosen to define `Config` to +contain owned `String` values. The `args` variable in `main` is the owner of +the argument values and is only letting the `parse_config` function borrow +them, though, which means we'd violate Rust's borrowing rules if `Config` tried +to take ownership of the values in `args`. + +There are a number of different ways we could manage the `String` data, and the +easiest, though somewhat inefficient, route is to call the `clone` method on +the values. This will make a full copy of the data for the `Config` instance to +own, which does take more time and memory than storing a reference to the +string data. However, cloning the data also makes our code very straightforward +since we don't have to manage the lifetimes of the references, so in this +circumstance giving up a little performance to gain simplicity is a worthwhile +trade-off. + + + + + +> #### The Tradeoffs of Using `clone` +> +> There's a tendency amongst many Rustaceans to avoid using `clone` to fix +> ownership problems because of its runtime cost. In Chapter 13 on iterators, +> you'll learn how to use more efficient methods in this kind of situation, but +> for now, it's okay to copy a few strings to keep making progress since we'll +> only make these copies once, and our filename and query string are both very +> small. It's better to have a working program that's a bit inefficient than +> try to hyper-optimize code on your first pass. As you get more experienced +> with Rust, it'll be easier to go straight to the desirable method, but for +> now it's perfectly acceptable to call `clone`. + + + +We've updated `main` so that it places the instance of `Config` that +`parse_config` returns into a variable named `config`, and updated the code +that previously used the separate `query` and `filename` variables so that is +now uses the fields on the `Config` struct instead. + +Our code now more clearly conveys our intent that `query` and `filename` are +related and their purpose is to configure how the program will work. Any code +that uses these values knows to find them in the `config` instance in the +fields named for their purpose. + +#### Creating a Constructor for `Config` + + + + +So far, we've extracted the logic responsible for parsing the command line +arguments from `main` into the `parse_config` function, which helped us to see +that the `query` and `filename` values were related and that relationship +should be conveyed in our code. We then added a `Config` struct to name the +related purpose of `query` and `filename`, and to be able to return the values' +names as struct field names from the `parse_config` function. + +So now that the purpose of the `parse_config` function is to create a `Config` +instance, we can change `parse_config` from being a plain function into a +function named `new` that is associated with the `Config` struct. Making this +change will make our code more idiomatic: we can create instances of types in +the standard library like `String` by calling `String::new`, and by changing +`parse_config` to be a `new` function associated with `Config`, we'll be able +to create instances of `Config` by calling `Config::new`. Listing 12-7 shows +the changes we'll need to make: + +Filename: src/main.rs + +``` +fn main() { + let args: Vec = env::args().collect(); + + let config = Config::new(&args); + + // ...snip... +} + +// ...snip... + +impl Config { + fn new(args: &[String]) -> Config { + let query = args[1].clone(); + let filename = args[2].clone(); + + Config { + query: query, + filename: filename, + } + } +} +``` + +Listing 12-7: Changing `parse_config` into `Config::new` + + + +We've updated `main` where we were calling `parse_config` to instead call +`Config::new`. We've changed the name of `parse_config` to `new` and moved it +within an `impl` block, which makes the `new` function associated with +`Config`. Try compiling this again to make sure it works. + +### Fixing the Error Handling + +Now we'll work on fixing our error handling. Recall that we mentioned +attempting to access the values in the `args` vector at index 1 or index 2 will +cause the program to panic if the vector contains fewer than 3 items. Try +running the program without any arguments; it will look like this: + +``` +$ cargo run + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running `target/debug/greprs` +thread 'main' panicked at 'index out of bounds: the len is 1 +but the index is 1', /stable-dist-rustc/build/src/libcollections/vec.rs:1307 +note: Run with `RUST_BACKTRACE=1` for a backtrace. +``` + +`index out of bounds: the len is 1 but the index is 1` is an error message that +is intended for programmers, and won't really help our end users understand +what happened and what they should do instead. Let's fix that now. + +#### Improving the Error Message + +In Listing 12-8, we're adding a check in the `new` function to check that the +slice is long enough before accessing index 1 and 2. If the slice isn't long +enough, we panic with a better error message than the `index out of bounds` +message: + +Filename: src/main.rs + +``` +// ...snip... +fn new(args: &[String]) -> Config { + if args.len() < 3 { + panic!("not enough arguments"); + } + // ...snip... +``` + +Listing 12-8: Adding a check for the number of arguments + + + +This is similar to the `Guess::new` function we wrote in Listing 9-8, where we +called `panic!` if the `value` argument was out of the range of valid values. +Instead of checking for a range of values, we're checking that the length of +`args` is at least 3, and the rest of the function can operate under the +assumption that this condition has been met. If `args` has fewer than 3 items, +this condition will be true, and we call the `panic!` macro to end the program +immediately. + +With these extra few lines of code in `new`, let's try running our program +without any arguments again and see what the error looks like now: + +``` +$ cargo run + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running `target/debug/greprs` +thread 'main' panicked at 'not enough arguments', src/main.rs:29 +note: Run with `RUST_BACKTRACE=1` for a backtrace. +``` + +This output is better, we now have a reasonable error message. However, we also +have a bunch of extra information we don't want to give to our users. So +perhaps using the technique we used in Listing 9-8 isn't the best to use here; +a call to `panic!` is more appropriate for a programming problem rather than a +usage problem anyway, as we discussed in Chapter 9. Instead, we can use the +other technique we learned about in that chapter: returning a `Result` that can +indicate either success or an error. + + + + +#### Returning a `Result` from `new` Instead of Calling `panic!` + +We can choose to instead return a `Result` value that will contain a `Config` +instance in the successful case, and will describe the problem in the error +case. When `Config::new` is communicating to `main`, we can use Rust's way of +signaling that there was a problem using the `Result` type. Then we can change +`main` to convert an `Err` variant into a nicer error for our users, without +the surrounding text about `thread 'main'` and `RUST_BACKTRACE` that a call to +`panic!` causes. + +Listing 12-9 shows the changes to the return value of `Config::new` and the +body of the function needed to return a `Result`: + +Filename: src/main.rs + +``` +impl Config { + fn new(args: &[String]) -> Result { + if args.len() < 3 { + return Err("not enough arguments"); + } + + let query = args[1].clone(); + let filename = args[2].clone(); + + Ok(Config { + query: query, + filename: filename, + }) + } +} +``` + +Listing 12-9: Return a `Result` from `Config::new` + + + + + + +Our `new` function now returns a `Result`, with a `Config` instance in the +success case and a `&'static str` in the error case. Recall from "The Static +Lifetime" section in Chapter 10 that `&'static str` is the type of string +literals, which is our error message type for now. + +We've made two changes in the body of the `new` function: instead of calling +`panic!` when the user doesn't pass enough arguments, we now return an `Err` +value, and we've wrapped the `Config` return value in an `Ok`. These changes +make the function conform to its new type signature. + +By having `Config::new` return an `Err` value, it allows the `main` function to +handle the `Result` value returned from the `new` function and exit the process +more cleanly in the error case. + +#### Calling `Config::new` and Handling Errors + +In order to handle the error case and print a user-friendly message, we need to +update `main` to handle the `Result` that `Config::new` is now returning as +shown in Listing 12-10. We're also going to implement by hand something that +`panic!` handled for us: exiting the command line tool with an error code of 1. +A nonzero exit status is a convention to signal to the process that called our +program that our program ended with an error state. + +Filename: src/main.rs + +``` +use std::process; + +fn main() { + let args: Vec = env::args().collect(); + + let config = Config::new(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {}", err); + process::exit(1); + }); + + // ...snip... +``` + +Listing 12-10: Exiting with an error code if creating a new `Config` fails + + + + + + + +In this listing, we're using a method we haven't covered before: +`unwrap_or_else`, which is defined on `Result` by the standard library. +Using `unwrap_or_else` allows us to define some custom, non-`panic!` error +handling. If the `Result` is an `Ok` value, this method's behavior is similar +to `unwrap`: it returns the inner value `Ok` is wrapping. However, if the value +is an `Err` value, this method calls the code in the *closure*, which is an +anonymous function we define and pass as an argument to `unwrap_or_else`. We'll +be covering closures in more detail in Chapter 13. What you need to know for +now is that `unwrap_or_else` will pass the inner value of the `Err`, which in +this case is the static string `not enough arguments` that we added in Listing +12-9, to our closure in the argument `err` that appears between the vertical +pipes. The code in the closure can then use the `err` value when it runs. + + + + +We've added a new `use` line to import `process` from the standard library. The +code in the closure that will get run in the error case is only two lines: we +print out the `err` value, then call `std::process::exit` (we've added a new +`use` line at the top to import `process` from the standard library). +`process::exit` will stop the program immediately and return the number that +was passed as the exit status code. This is similar to the `panic!`-based +handling we used in Listing 12-8, with the exception that we no longer get all +the extra output. Let's try it: + +``` +$ cargo run + Compiling greprs v0.1.0 (file:///projects/greprs) + Finished debug [unoptimized + debuginfo] target(s) in 0.48 secs + Running `target/debug/greprs` +Problem parsing arguments: not enough arguments +``` + +Great! This output is much friendlier for our users. + +### Extracting a `run` Function + +Now we're done refactoring our configuration parsing; let's turn to our +program's logic. As we laid out in the process we discussed in the "Separation +of Concerns for Binary Projects" section, we're going to extract a function +named `run` that will hold all of the logic currently in the `main` function +that isn't setting up configuration or handling errors. Once we're done, `main` +will be concise and easy to verify by inspection, and we'll be able to write +tests for all of the other logic. + + + + +Listing 12-11 shows the extracted `run` function. For now, we're making only +the small, incremental improvement of extracting the function and still +defining the function in *src/main.rs*: + +Filename: src/main.rs + +``` +fn main() { + // ...snip... + + println!("Searching for {}", config.query); + println!("In file {}", config.filename); + + run(config); +} + +fn run(config: Config) { + let mut f = File::open(config.filename).expect("file not found"); + + let mut contents = String::new(); + f.read_to_string(&mut contents).expect("something went wrong reading the file"); + + println!("With text:\n{}", contents); +} + +// ...snip... +``` + +Listing 12-11: Extracting a `run` function containing the rest of the program +logic + + + +The `run` function now contains all the remaining logic from `main` starting +from reading the file. The `run` function takes the `Config` instance as an +argument. + +#### Returning Errors from the `run` Function + +With the remaining program logic separated into the `run` function rather than +being in `main`, we can improve the error handling like we did with +`Config::new` in Listing 12-9. Instead of allowing the program to panic by +calling `expect`, the `run` function will return a `Result` when +something goes wrong. This will let us further consolidate the logic around +handling errors in a user-friendly way into `main`. Listing 12-12 shows the +changes to the signature and body of `run`: + +Filename: src/main.rs + +``` +use std::error::Error; + +// ...snip... + +fn run(config: Config) -> Result<(), Box> { + let mut f = File::open(config.filename)?; + + let mut contents = String::new(); + f.read_to_string(&mut contents)?; + + println!("With text:\n{}", contents); + + Ok(()) +} +``` + +Listing 12-12: Changing the `run` function to return `Result` + + + +We've made three big changes here. First, we're changing the return type of the +`run` function to `Result<(), Box>`. This function previously returned +the unit type, `()`, and we keep that as the value returned in the `Ok` case. + + + + +For our error type, we're using the *trait object* `Box` (and we've +brought `std::error::Error` into scope with a `use` statement at the top). +We'll be covering trait objects in Chapter 17. For now, just know that +`Box` means the function will return a type that implements the `Error` +trait, but we don't have to specify what particular type the return value will +be. This gives us flexibility to return error values that may be of different +types in different error cases. + +The second change we're making is removing the calls to `expect` in favor of +`?`, like we talked about in Chapter 9. Rather than `panic!` on an error, this +will return the error value from the current function for the caller to handle. + +Thirdly, this function now returns an `Ok` value in the success case. We've +declared the `run` function's success type as `()` in the signature, which +means we need to wrap the unit type value in the `Ok` value. This `Ok(())` +syntax may look a bit strange at first, but using `()` like this is the +idiomatic way to indicate that we're calling `run` for its side effects only; +it doesn't return a value we need. + +When you run this, it will compile, but with a warning: + +``` +warning: unused result which must be used, #[warn(unused_must_use)] on by default + --> src/main.rs:39:5 + | +39 | run(config); + | ^^^^^^^^^^^^ +``` + +Rust is telling us that our code ignores the `Result` value, which might be +indicating that there was an error. We're not checking to see if there was an +error or not, though, and the compiler is reminding us that we probably meant +to have some error handling code here! Let's rectify that now. + +#### Handling Errors Returned from `run` in `main` + +We'll check for errors and handle them nicely using a similar technique to the +way we handled errors with `Config::new` in Listing 12-10, but with a slight +difference: + +Filename: src/main.rs + +``` +fn main() { + // ...snip... + + println!("Searching for {}", config.query); + println!("In file {}", config.filename); + + if let Err(e) = run(config) { + println!("Application error: {}", e); + + process::exit(1); + } +} +``` + + + +We use `if let` to check whether `run` returns an `Err` value, rather than +`unwrap_or_else`, and call `process::exit(1)` if it does. `run` doesn't return +a value that we want to `unwrap` like `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 as it would only be `()`. + +The bodies of the `if let` and the `unwrap_or_else` functions are the same in +both cases though: we print out the error and exit. + +### Split Code into a Library Crate + +This is looking pretty good so far! Now we're going to split the *src/main.rs* +file up and put some code into *src/lib.rs* so that we can test it and have a +small `main` function. + +Let's move the following pieces of code from *src/main.rs* to a new file, +*src/lib.rs*: + +- The `run` function definition +- The relevant `use` statements +- The definition of `Config` +- The `Config::new` function definition + +The contents of *src/lib.rs* should now look like Listing 12-13: + +Filename: src/lib.rs + +``` +use std::error::Error; +use std::fs::File; +use std::io::prelude::*; + +pub struct Config { + pub query: String, + pub filename: String, +} + +impl Config { + pub fn new(args: &[String]) -> Result { + if args.len() < 3 { + return Err("not enough arguments"); + } + + let query = args[1].clone(); + let filename = args[2].clone(); + + Ok(Config { + query: query, + filename: filename, + }) + } +} + +pub fn run(config: Config) -> Result<(), Box>{ + let mut f = File::open(config.filename)?; + + let mut contents = String::new(); + f.read_to_string(&mut contents)?; + + println!("With text:\n{}", contents); + + Ok(()) +} +``` + +Listing 12-13: Moving `Config` and `run` into *src/lib.rs* + + + +We've made liberal use of `pub` here: on `Config`, its fields and its `new` +method, and on the `run` function. We now have a library crate that has a +public API that we can test. + +#### Calling the Library Crate from the Binary Crate + +Now we need to bring the code we moved to *src/lib.rs* into the scope of the +binary crate in *src/main.rs* by using `extern crate greprs`. Then we'll add a +`use greprs::Config` line to bring the `Config` type into scope, and prefix the +`run` function with our crate name as shown in Listing 12-14: + +Filename: src/main.rs + +``` +extern crate greprs; + +use std::env; +use std::process; + +use greprs::Config; + +fn main() { + let args: Vec = env::args().collect(); + + let config = Config::new(&args).unwrap_or_else(|err| { + println!("Problem parsing arguments: {}", err); + process::exit(1); + }); + + println!("Searching for {}", config.query); + println!("In file {}", config.filename); + + if let Err(e) = greprs::run(config) { + println!("Application error: {}", e); + + process::exit(1); + } +} +``` + +Listing 12-14: Bringing the `greprs` crate into the scope of *src/main.rs* + + + +With that, all the functionality should be connected and should work. Give it a +`cargo run` and make sure everything is wired up correctly. + + + + +Whew! That was a lot of work, but we've set ourselves up for success in the +future. Now it's much easier to handle errors, and we've made our code more +modular. Almost all of our work will be done in *src/lib.rs* from here on out. + +Let's take advantage of this newfound modularity by doing something that would +have been hard with our old code, but is easy with our new code: write some +tests! + +## Testing the Library's Functionality + +Now that we've extracted the logic into *src/lib.rs* and left all the argument +parsing and error handling in *src/main.rs*, it's much easier for us to write +tests for the core functionality of our code. We can call our functions +directly with various arguments and check return values without having to call +our binary from the command line. + +In this section, we're going to follow the Test Driven Development (TDD) +process. This is a software development technique that follows this set of +steps: + +1. Write a test that fails, and run it to make sure it fails for the reason + you 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. +4. Repeat! + +This is just one of many ways to write software, but TDD can help drive the +design of code. Writing the test before writing the code that makes the test +pass helps to maintain high test coverage throughout the process. + +We're going to test drive the implementation of the part of our `greprs` +program that will actually do the searching for the query string in the file +contents and produce a list of lines that match the query. We're going to add +this functionality in a function called `search`. + +### Writing a Failing Test + +First, since we don't really need them any more, let's remove the `println!` +statements from both *src/lib.rs* and *src/main.rs*. Then we'll add a `test` +module with a test function, like we did in Chapter 11. The test function +specifies the behavior we'd like 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: + +Filename: src/lib.rs + +``` +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn one_result() { + let query = "duct"; + let contents = "\ +Rust: +safe, fast, productive. +Pick three."; + + assert_eq!( + vec!["safe, fast, productive."], + search(query, contents) + ); + } +} +``` + +Listing 12-15: Creating a failing test for the `search` function we wish we had + +We've chosen to use "duct" as the string we're looking for in this test. The +text we're searching in is three lines, only one of which contains "duct". We +assert that the value returned from the `search` function contains only the one +line we expect. + +We aren't able to run this test and watch it fail though, since this test +doesn't even compile yet! We're going to add just enough code to get it to +compile: a definition of the `search` function that always returns an empty +vector, as shown in Listing 12-16. Once we have this, the test should compile +and fail because an empty vector doesn't match a vector containing the one +line `"safe, fast, productive."`. + +Filename: src/lib.rs + +``` +fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { + vec![] +} +``` + +Listing 12-16: Defining just enough of the `search` function that our test will +compile + + + +Notice that we need an explicit lifetime `'a` defined in the signature of +`search` and used with the `contents` argument and the return value. Remember +from Chapter 10 that the lifetime parameters specify which argument lifetime is +connected to the lifetime of the return value. In this case, we're indicating +that the returned vector should contain string slices that reference slices of +the argument `contents` (rather than the argument `query`). + +In other words, we're telling Rust that the data returned by the `search` +function will live as long as the data passed into the `search` function in the +`contents` argument. This is important! The data referenced *by* a slice needs +to be valid in order for the reference to be valid; if the compiler assumed we +were making string slices of `query` rather than `contents`, it would do its +safety checking incorrectly. + +If we tried to compile this function without lifetimes, we would get this error: + +``` +error[E0106]: missing lifetime specifier + --> src/lib.rs:5:47 + | +5 | fn search(query: &str, contents: &str) -> Vec<&str> { + | ^ expected lifetime parameter + | + = help: this function's return type contains a borrowed value, but the + signature does not say whether it is borrowed from `query` or `contents` +``` + +Rust can't possibly know which of the two arguments we need, so we need to tell +it. Because `contents` is the argument that contains all of our text and we +want to return the parts of that text that match, we know `contents` is the +argument that should be connected to the return value using the lifetime syntax. + +Other programming languages don't require you to connect arguments to return +values in the signature, so this may still feel strange, but will get easier +over time. You may want to compare this example with the Lifetime Syntax +section in Chapter 10. + +Now let's try running our test: + +``` +$ cargo test +...warnings... + Finished debug [unoptimized + debuginfo] target(s) in 0.43 secs + Running target/debug/deps/greprs-abcabcabc + +running 1 test +test test::one_result ... FAILED + +failures: + +---- test::one_result stdout ---- + thread 'test::one_result' panicked at 'assertion failed: `(left == right)` +(left: `["safe, fast, productive."]`, right: `[]`)', src/lib.rs:16 +note: Run with `RUST_BACKTRACE=1` for a backtrace. + + +failures: + test::one_result + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured + +error: test failed +``` + +Great, our test fails, exactly as we expected. Let's get the test to pass! + +### Writing Code that Gets the Test to Pass + +Currently, our test is failing because we always return an empty vector. To fix +that and implement `search`, our program needs to follow these steps: + +1. Iterate through each line of the contents. +2. Check if the line contains our query string. + * If it does, add it to the list of values we're returning. + * If it doesn't, do nothing. +3. Return the list of results that match. + +Let's take each step at a time, starting with iterating through lines. + +#### Iterating Through Lines with the `lines` method + +Rust has a helpful method to handle line-by-line iteration of strings, +conveniently named `lines`, that works as shown in Listing 12-17: + +Filename: src/lib.rs + +``` +fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { + for line in contents.lines() { + // do something with line + } +} +``` + +Listing 12-17: Iterating through each line in `contents` + + + +The `lines` method returns an iterator. We'll be talking about iterators in +depth in Chapter 13, but we've already seen this way of using an iterator in +Listing 3-6, where we used a `for` loop with an iterator to run some code on +each item in a collection. + + + + +#### Searching Each Line for the Query + +Next, we'll add functionality to check if the current line contains the query +string. Luckily, strings have another helpful method named `contains` that does +this for us! Add the `contains` method to the `search` function as shown in +Listing 12-18: + +Filename: src/lib.rs + +``` +fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { + for line in contents.lines() { + if line.contains(query) { + // do something with line + } + } +} +``` + +Listing 12-18: Adding functionality to see if the line contains the string in +`query` + + + +#### Storing Matching Lines + +Finally, we need a way to store the lines that contain our query string. For +that, we can make a mutable vector before the `for` loop and call the `push` +method to store a `line` in the vector. After the `for` loop, we return the +vector, as shown in Listing 12-19: + +Filename: src/lib.rs + +``` +fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { + let mut results = Vec::new(); + + for line in contents.lines() { + if line.contains(query) { + results.push(line); + } + } + + results +} +``` + +Listing 12-19: Storing the lines that match so that we can return them + + + +Now the `search` function should be returning only the lines that contain +`query`, and our test should pass. Let's run the tests: + +``` +$ cargo test +running 1 test +test test::one_result ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + + Running target/debug/greprs-2f55ee8cd1721808 + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured + + Doc-tests greprs + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +``` + +Our test passed, great, it works! + +Now that our test is passing, we could consider opportunities for refactoring +the implementation of the `search` function while keeping the tests passing in +order to maintain the same functionality while we do so. This code isn't bad, +but it isn't taking advantage of some useful features of iterators. We'll be +coming back to this example in Chapter 13 where we'll explore iterators in +detail and see how to improve it. + + + + +#### Using the `search` Function in the `run` Function + +Now that we have the `search` function working and tested, we need to actually +call `search` from our `run` function. We need to pass the `config.query` value +and the `contents` that `run` read from the file to the `search` function. Then +`run` will print out each line returned from `search`: + +Filename: src/lib.rs + +``` +pub fn run(config: Config) -> Result<(), Box> { + let mut f = File::open(config.filename)?; + + let mut contents = String::new(); + f.read_to_string(&mut contents)?; + + for line in search(&config.query, &contents) { + println!("{}", line); + } + + Ok(()) +} +``` + + + +We're again using a `for` loop to get each line returned from `search`, and +the code that we run for each line prints it out. + +Now our whole program should be working! Let's try it out, first with a word +that should return exactly one line from the Emily Dickinson poem, "frog": + +``` +$ cargo run frog poem.txt + Compiling greprs v0.1.0 (file:///projects/greprs) + Finished debug [unoptimized + debuginfo] target(s) in 0.38 secs + Running `target/debug/greprs frog poem.txt` +How public, like a frog +``` + +Cool! Next, how about a word that will match multiple lines, like "the": + +``` +$ cargo run the poem.txt + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running `target/debug/greprs the poem.txt` +Then there's a pair of us — don't tell! +To tell your name the livelong day +``` + +And finally, let's make sure that we don't get any lines when we search for a +word that isn't anywhere in the poem, like "monomorphization": + +``` +$ cargo run monomorphization poem.txt + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running `target/debug/greprs monomorphization poem.txt` +``` + +Excellent! We've built our own version of a classic tool, and learned a lot +about how to structure applications. We've also learned a bit about file input +and output, lifetimes, testing, and command line parsing. + +Feel free to move on to Chapter 13 if you'd like at this point. To round out +this project chapter, though, we're going to briefly demonstrate how to work +with environment variables and printing to standard error, both of which are +useful when writing command line programs. + +## Working with Environment Variables + +We're going to improve our tool with an extra feature: an option for case +insensitive searching turned on via an environment variable. We could make this +a command line option and require that users enter it each time they want it to +apply, but instead we're going to use an environment variable. This allows our +users to set the environment variable once and have all their searches be case +insensitive in that terminal session. + +### Writing a Failing Test for the Case-Insensitive `search` Function + +First, let's add a new function that we will call when the environment variable +is on. + + + + +We're going to continue following the TDD process that we started doing in the +last section, and the first step is again to write a failing test. We'll add a +new test for the new case insensitive search function, and rename our old test +from `one_result` to `case_sensitive` to be clearer about the differences +between the two tests, as shown in Listing 12-20: + +Filename: src/lib.rs + +``` +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn case_sensitive() { + let query = "duct"; + let contents = "\ +Rust: +safe, fast, productive. +Pick three. +Duct tape."; + + assert_eq!( + vec!["safe, fast, productive."], + search(query, contents) + ); + } + + #[test] + fn case_insensitive() { + let query = "rUsT"; + let contents = "\ +Rust: +safe, fast, productive. +Pick three. +Trust me."; + + assert_eq!( + vec!["Rust:", "Trust me."], + search_case_insensitive(query, contents) + ); + } +} +``` + + + +Listing 12-20: Adding a new failing test for the case insensitive function +we're about to add + +Note that we've edited the old test's `query` and `contents` too: we changed +the query to "duct", which will match the line with the word "productive". +We've added a new line with the text "Duct tape", with a capital D, that +shouldn't match the query "duct" when we're searching for the query in a case +sensitive manner. We've changed this test to ensure that we don't accidentally +break the case sensitive search functionality that we've already implemented; +this test should pass now and should continue to pass as we work on the case +insensitive search. + +The new test for the case insensitive search uses "rUsT" with some capital +letters as its query. The expected return value from the +`search_case_insensitive` function we're going to add is that the query "rust" +will match both the line containing "Rust:" with a capital R and also the line +"Trust me." that contains "rust" with a lowercase r. This test will fail to +compile right now since we haven't yet defined the `search_case_insensitive` +function; feel free to add a skeleton implementation that always returns an +empty array in the same way that we did for the `search` function in Listing +12-16 in order to see the test compile and fail. + +### Implementing the `search_case_insensitive` Function + +The `search_case_insensitive` function, shown in Listing 12-21, will be almost +the same as the `search` function. The difference is that we'll lowercase the +`query` function and each `line` so that whatever the case of the input +arguments, they will be the same case when we check whether the line contains +the query. + +Filename: src/lib.rs + +``` +fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { + let query = query.to_lowercase(); + let mut results = Vec::new(); + + for line in contents.lines() { + if line.to_lowercase().contains(&query) { + results.push(line); + } + } + + results +} +``` + +Listing 12-21: Defining the `search_case_insensitive` function to lowercase +both the query and the line before comparing them + + + + + + +First, we lowercase the `query` string, and store it in a shadowed variable +with the same name. Calling `to_lowercase` on the query is necessary so that no +matter if the user's query is "rust", "RUST", "Rust", or "rUsT", we'll treat +the query as if it was "rust" and be insensitive to the case. + +Note that `query` is now a `String` rather than a string slice, because calling +`to_lowercase` is creating new data, not referencing existing data. If the +query is "rUsT", that string slice does not contain a lowercase u or t for us +to use, so we have to allocate a new `String` containing "rust". Because +`query` is now a `String`, when we pass `query` as an argument to the +`contains` method, we need to add an ampersand since the signature of +`contains` is defined to take a string slice. + +Next, we add a call to `to_lowercase` on each `line` before we check if it +contains `query`. This will turn "Rust:" into "rust:" and "Trust me." into +"trust me." Now that we've converted both `line` and `query` to all lowercase, +we'll find matches no matter what case the text in the file has or the user +entered in the query. + +Let's see if this implementation passes the tests: + +``` + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running target/debug/deps/greprs-e58e9b12d35dc861 + +running 2 tests +test test::case_insensitive ... ok +test test::case_sensitive ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured + + Running target/debug/greprs-8a7faa2662b5030a + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured + + Doc-tests greprs + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +``` + +Great! Now, let's actually call the new `search_case_insensitive` function from +the `run` function. First, we're going to add a configuration option for +switching between case sensitive and case insensitive search to the `Config` +struct: + +Filename: src/lib.rs + +``` +pub struct Config { + pub query: String, + pub filename: String, + pub case_sensitive: bool, +} +``` + + + +We add the `case_sensitive` field that holds a boolean. Then we need our `run` +function to check the `case_sensitive` field's value and use that to decide +whether to call the `search` function or the `search_case_insensitive` function +as shown in Listing 12-22: + +Filename: src/lib.rs + +``` +pub fn run(config: Config) -> Result<(), Box>{ + let mut f = File::open(config.filename)?; + + let mut contents = String::new(); + f.read_to_string(&mut contents)?; + + let results = if config.case_sensitive { + search(&config.query, &contents) + } else { + search_case_insensitive(&config.query, &contents) + }; + + for line in results { + println!("{}", line); + } + + Ok(()) +} +``` + +Listing 12-22: Calling either `search` or `search_case_insensitive` based on +the value in `config.case_sensitive` + + + +Finally, we need to actually check for the environment variable. The functions +for working with environment variables are in the `env` module in the standard +library, so we want to bring that module into scope with a `use std::env;` +line at the top of *src/lib.rs*. Then we're going to use the `var` method +from the `env` module in `Config::new` to check for an environment variable +named `CASE_INSENSITIVE`, as shown in Listing 12-23: + +Filename: src/lib.rs + +``` +use std::env; + +// ...snip... + +impl Config { + pub fn new(args: &[String]) -> Result { + if args.len() < 3 { + return Err("not enough arguments"); + } + + let query = args[1].clone(); + let filename = args[2].clone(); + + let case_sensitive = env::var("CASE_INSENSITIVE").is_err(); + + Ok(Config { + query: query, + filename: filename, + case_sensitive: case_sensitive, + }) + } +} +``` + +Listing 12-23: Checking for an environment variable named `CASE_INSENSITIVE` + + + +Here, we create a new variable `case_sensitive`. In order to set its value, we +call the `env::var` function and pass it the name of the environment variable +we're looking for, `CASE_INSENSITIVE`. `env::var` returns a `Result` that will +be the `Ok` variant containing the value if the environment variable is set, +and will be the `Err` variant if the environment variable is not set. We're +using the `is_err` method on the `Result` to check to see if it's an error (and +therefore unset), which means we *should* do a case sensitive search. If the +`CASE_INSENSITIVE` environment variable is set to anything, `is_err` will +return false and we will do a case insensitive search. We don't care about the +value that the environment variable is set to, just whether it's set or unset, +so we're checking `is_err` rather than `unwrap`, `expect`, or any of the other +methods we've seen on `Result`. We pass the value in the `case_sensitive` +variable to the `Config` instance so that the `run` function can read that +value and decide whether to call `search` or `search_case_insensitive` as we +implemented in Listing 12-22. + +Let's give it a try! First, we'll run our program without the environment +variable set and with the query "to", which should match any line that contains +the word "to" in all lowercase: + +``` +$ cargo run to poem.txt + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running `target/debug/greprs to poem.txt` +Are you nobody, too? +How dreary to be somebody! +``` + +Looks like that still works! Now, let's run the program with `CASE_INSENSITIVE` +set to 1 but with the same query "to", and we should get lines that contain +"to" that might have capital letters: + +``` +$ CASE_INSENSITIVE=1 cargo run to poem.txt + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running `target/debug/greprs to poem.txt` +Are you nobody, too? +How dreary to be somebody! +To tell your name the livelong day +To an admiring bog! +``` + +Excellent, we also got lines containing "To"! Our `greprs` program can now do +case insensitive searching, controlled by an environment variable. Now you know +how to manage options set using either command line arguments or environment +variables! + +Some programs allow both arguments *and* environment variables for the same +configuration. In those cases, the programs decide that one or the other takes +precedence. For another exercise on your own, try controlling case +insensitivity through a command line argument as well as through the +environment variable, and decide which should take precedence the program is +run with contradictory values. + +The `std::env` module contains many more useful features for dealing with +environment variables; check out its documentation to see what's available. + +## Write to `stderr` Instead of `stdout` + +Right now, we're writing all of our output to the terminal with `println!`. +Most terminals provide two kinds of output: "standard out" for general +information, and "standard error" for error messages. This distinction is the +behavior that's expected of command line programs: it enables users to choose +to direct a program's successful output to a file but still print error +messages to the screen, for example. `println!` is only capable of printing to +standard out, though, so we have to use something else in order to print to +standard error. + +We can verify that, the way we've written `greprs` so far, everything is being +written to standard out, including error messages that should be written to +standard error instead. We'll do that by intentionally causing an error, the +one that happens when we run the program without any arguments. We're going to +redirect standard output to a file, but not standard error. The way command +line programs are expected to work is that, because the output is an error +message, it should be shown on the screen rather than being redirected to the +file. Let's see that our program is not currently meeting this expectation by +using `>` and specifying a filename, *output.txt*, that we want to redirect +standard out to: + +``` +$ cargo run > output.txt +``` + + + + +The `>` syntax tells the shell to write the contents of standard out to +*output.txt* instead of the screen. We didn't see the error message we were +expecting printed on the screen, so that means it must have ended up in the +file. Let's see what *output.txt* contains: + +``` +Application error: No search string or filename found +``` + + + + +Yup, there's our error message, which means it's being printed to standard out. +This isn't what's expected from command line programs. It's much more useful +for error messages like this to be printed to standard error, and only have +data printed to standard out from a successful run end up in the file when we +redirect standard out in this way. Let's change how error messages are printed +as shown in Listing 12-23. Because of the refactoring we did earlier in this +chapter, all of the code that prints error messages is in one place, in `main`: + +Filename: src/main.rs + +``` +extern crate greprs; + +use std::env; +use std::process; +use std::io::prelude::*; + +use greprs::Config; + +fn main() { + let args: Vec = env::args().collect(); + let mut stderr = std::io::stderr(); + + let config = Config::new(&args).unwrap_or_else(|err| { + writeln!( + &mut stderr, + "Problem parsing arguments: {}", + err + ).expect("Could not write to stderr"); + process::exit(1); + }); + + if let Err(e) = greprs::run(config) { + writeln!( + &mut stderr, + "Application error: {}", + e + ).expect("Could not write to stderr"); + + process::exit(1); + } +} +``` + +Listing 12-23: Writing error messages to `stderr` instead of `stdout` using +`writeln!` + + + +Rust does not have a convenient function like `println!` for writing to +standard error. Instead, we use the `writeln!` macro, which is like `println!` +but takes an extra argument. The first thing we pass to it is what to write to. +We can acquire a handle to standard error through the `std::io::stderr` +function. We give a mutable reference to `stderr` to `writeln!`; we need it to +be mutable so we can write to it! The second and third arguments to `writeln!` +are like the first and second arguments to `println!`: a format string and any +variables we're interpolating. + +Let's try running the program again in the same way, without any arguments and +redirecting `stdout` with `>`: + +``` +$ cargo run > output.txt +Application error: No search string or filename found +``` + +Now we see our error on the screen, and `output.txt` contains nothing, which is +the behavior that's expected of command line programs. + +If we run the program again with arguments that don't cause an error, but still +redirecting standard out to a file: + +``` +$ cargo run to poem.txt > output.txt +``` + +We won't see any output to our terminal, and `output.txt` will contain our +results: + +Filename: output.txt + +``` +Are you nobody, too? +How dreary to be somebody! +``` + +This demonstrates that we're now using standard out for successful output and +standard error for error output as appropriate. + +## Summary + +In this chapter, we've recapped on some of the major concepts so far and +covered how to do common I/O operations in a Rust context. By using command +line arguments, files, environment variables, and the `writeln!` macro with +`stderr`, you're now prepared to write command line applications. By using the +concepts from previous chapters, your code will be well-organized, be able to +store data effectively in the appropriate data structures, handle errors +nicely, and be well tested. + +Next, let's explore some functional-language influenced Rust features: closures +and iterators. diff --git a/src/doc/book/second-edition/nostarch/chapter13.md b/src/doc/book/second-edition/nostarch/chapter13.md new file mode 100644 index 0000000000..c7d647fa9d --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter13.md @@ -0,0 +1,799 @@ + +[TOC] + +# Functional Language features in Rust - Iterators and Closures + +Rust's design has taken inspiration from a lot of previous work. One of Rust's +influences is functional programming, where functions are values that can be +used as arguments or return values to other functions, assigned to variables, +and so forth. We're going to sidestep the issue of what, exactly, functional +programming is or is not, and instead show off some features of Rust that +are similar to features in many languages referred to as functional. + +More specifically, we're going to cover: + +* *Closures*, a function-like construct you can store in a variable. +* *Iterators*, a way of processing series of elements. +* How to use these features to improve upon the project from the last chapter. +* The performance of these features. Spoiler alert: they're faster than you + might think! + +This is not a complete list of Rust's influence from the functional style: +pattern matching, enums, and many other features are too. But mastering +closures and iterators are an important part of writing idiomatic, fast Rust +code. + +## Closures + +Rust gives you the ability to define *closures*, which are similar to +functions. Instead of starting with a technical definition, let's see what +closures look like, syntactically, and then we'll return to defining what they +are. Listing 13-1 shows a small closure whose definition is assigned to the +variable `add_one`, which we can then use to call the closure: + +
+Filename: src/main.rs + +```rust +fn main() { + let add_one = |x| x + 1; + + let five = add_one(4); + + assert_eq!(5, five); +} +``` + +
+ +Listing 13-1: A closure that takes one parameter and adds one to it, assigned to +the variable `add_one` + +
+
+ +The closure definition, on the first line, shows that the closure takes one +parameter named `x`. Parameters to closures go in between vertical pipes (`|`). + +This is a minimal closure with only one expression as its body. Listing 13-2 has +a closure with a bit more complexity: + +
+Filename: src/main.rs + +```rust +fn main() { + let calculate = |a, b| { + let mut result = a * 2; + + result += b; + + result + }; + + assert_eq!(7, calculate(2, 3)); // 2 * 2 + 3 == 7 + assert_eq!(13, calculate(4, 5)); // 4 * 2 + 5 == 13 +} +``` + +
+ +Listing 13-2: A closure with two parameters and multiple expressions in its body + +
+
+ +We can use curly brackets to define a closure body with more than one +expression. + +You'll notice a few things about closures that are different from functions +defined with the `fn` keyword. The first difference is that we did not need to +annotate the types of the parameters the closure takes or the value it returns. +We can choose to add type annotations if we want; Listing 13-3 shows the +closure from Listing 13-1 with annotations for the parameter's and return +value's types: + +
+Filename: src/main.rs + +```rust +fn main() { + let add_one = |x: i32| -> i32 { x + 1 }; + + assert_eq!(2, add_one(1)); +} +``` + +
+ +Listing 13-3: A closure definition with optional parameter and return value +type annotations + +
+
+ +The syntax of closures and functions looks more similar with type annotations. +Let's compare the different ways we can specify closures with the syntax for +defining a function more directly. We've added some spaces here to line up the +relevant parts: + +```rust,ignore +fn add_one_v1 (x: i32) -> i32 { x + 1 } // a function +let add_one_v2 = |x: i32| -> i32 { x + 1 }; // the full syntax for a closure +let add_one_v3 = |x| { x + 1 }; // a closure eliding types +let add_one_v4 = |x| x + 1 ; // without braces +``` + +The reason type annotations are not required for defining a closure but are +required for defining a function is that functions are part of an explicit +interface exposed to your users, so defining this interface rigidly is +important for ensuring that everyone agrees on what types of values a function +uses and returns. Closures aren't used in an exposed interface like this, +though: they're stored in bindings and called directly. Being forced to +annotate the types would be a significant ergonomic loss for little advantage. + +Closure definitions do have one type inferred for each of their parameters and +for their return value. For instance, if we call the closure without type +annotations from Listing 13-1 using an `i8`, we'll get an error if we then try +to call the same closure with an `i32`: + +Filename: src/main.rs + +```rust,ignore +let add_one = |x| x + 1; + +let five = add_one(4i8); +assert_eq!(5i8, five); + +let three = add_one(2i32); +``` + +The compiler gives us this error: + +```text +error[E0308]: mismatched types + --> + | +7 | let three = add_one(2i32); + | ^^^^ expected i8, found i32 +``` + +Since closures' types can be inferred reliably since they're called directly, +it would be tedious if we were required to annotate their types. + +Another reason to have a different syntax from functions for closures is that +they have different behavior than functions: closures possess an *environment*. + +### Closures Can Reference Their Environment + +We've learned that functions can only use variables that are in scope, either +by being `const` or being declared as parameters. Closures can do more: they're +allowed to access variables from their enclosing scope. Listing 13-4 has an +example of a closure in the variable `equal_to_x` that uses the variable `x` +from the closure's surrounding environment: + +
+Filename: src/main.rs + +```rust +fn main() { + let x = 4; + + let equal_to_x = |z| z == x; + + let y = 4; + + assert!(equal_to_x(y)); +} +``` + +
+ +Listing 13-4: Example of a closure that refers to a variable in its enclosing +scope + +
+
+ +Here, even though `x` is not one of the parameters of `equal_to_x`, the +`equal_to_x` closure is allowed to use `x`, since `x` is a variable defined in +the scope that `equal_to_x` is defined. We aren't allowed to do the same thing +that Listing 13-4 does with functions; let's see what happens if we try: + +Filename: src/main.rs + +```rust,ignore +fn main() { + let x = 4; + + fn equal_to_x(z: i32) -> bool { z == x } + + let y = 4; + + assert!(equal_to_x(y)); +} +``` + +We get an error: + +```text +error[E0434]: can't capture dynamic environment in a fn item; use the || { ... } +closure form instead + --> + | +4 | fn equal_to_x(z: i32) -> bool { z == x } + | ^ +``` + +The compiler even reminds us that this only works with closures! + +Creating closures that capture values from their environment is mostly used in +the context of starting new threads. We'll show some more examples and explain +more detail about this feature of closures in Chapter 16 when we talk about +concurrency. + +### Closures as Function Parameters Using the `Fn` Traits + +While we can bind closures to variables, that's not the most useful thing we +can do with them. We can also define functions that have closures as parameters +by using the `Fn` traits. Here's an example of a function named `call_with_one` +whose signature has a closure as a parameter: + +```rust +fn call_with_one(some_closure: F) -> i32 + where F: Fn(i32) -> i32 { + + some_closure(1) +} + +let answer = call_with_one(|x| x + 2); + +assert_eq!(3, answer); +``` + +We pass the closure `|x| x + 2`, to `call_with_one`, and `call_with_one` calls +that closure with `1` as an argument. The return value of the call to +`some_closure` is then returned from `call_with_one`. + +The signature of `call_with_one` is using the `where` syntax discussed in the +Traits section of Chapter 10. The `some_closure` parameter has the generic type +`F`, which in the `where` clause is defined as having the trait bounds +`Fn(i32) -> i32`. The `Fn` trait represents a closure, and we can add types to +the `Fn` trait to represent a specific type of closure. In this case, our +closure has a parameter of type `i32` and returns an `i32`, so the generic bound +we specify is `Fn(i32) -> i32`. + +Specifying a function signature that contains a closure requires the use of +generics and trait bounds. Each closure has a unique type, so we can't write +the type of a closure directly, we have to use generics. + +`Fn` isn't the only trait bound available for specifying closures, however. +There are three: `Fn`, `FnMut`, and `FnOnce`. This continues the patterns of +threes we've seen elsewhere in Rust: borrowing, borrowing mutably, and +ownership. Using `Fn` specifies that the closure used may only borrow values in +its environment. To specify a closure that mutates the environment, use +`FnMut`, and if the closure takes ownership of the environment, `FnOnce`. Most +of the time, you can start with `Fn`, and the compiler will tell you if you +need `FnMut` or `FnOnce` based on what happens when the function calls the +closure. + +To illustrate a situation where it's useful for a function to have a parameter +that's a closure, let's move on to our next topic: iterators. + +## Iterators + +Iterators are a pattern in Rust that allows you to do some processing on a +sequence of items. For example, the code in Listing 13-5 adds one to each +number in a vector: + +
+ +```rust +let v1 = vec![1, 2, 3]; + +let v2: Vec = v1.iter().map(|x| x + 1).collect(); + +assert_eq!(v2, [2, 3, 4]); +``` + +
+ +Listing 13-5: Using an iterator, `map`, and `collect` to add one to each number +in a vector + +
+
+ + + +The `iter` method on vectors allows us to produce an *iterator* from the +vector. Next, the `map` method called on the iterator allows us to process each +element: in this case, we've passed a closure to `map` that specifies for every +element `x`, add one to it. `map` is one of the most basic ways of interacting +with an iterator, as processing each element in turn is very useful! Finally, +the `collect` method consumes the iterator and puts the iterator's elements +into a new data structure. In this case, since we've said that `v2` has the +type `Vec`, `collect` will create a new vector out of the `i32` values. + +Methods on iterators like `map` are sometimes called *iterator adaptors* +because they take one iterator and produce a new iterator. That is, `map` +builds on top of our previous iterator and produces another iterator by calling +the closure it's passed to create the new sequence of values. + +So, to recap, this line of code does the following: + +1. Creates an iterator from the vector. +2. Uses the `map` adaptor with a closure argument to add one to each element. +3. Uses the `collect` adaptor to consume the iterator and make a new vector. + +That's how we end up with `[2, 3, 4]`. As you can see, closures are a very +important part of using iterators: they provide a way of customizing the +behavior of an iterator adaptor like `map`. + +### Iterators are Lazy + +In the previous section, you may have noticed a subtle difference in wording: +we said that `map` *adapts* an iterator, but `collect` *consumes* one. That was +intentional. By themselves, iterators won't do anything; they're lazy. That is, +if we write code like Listing 13-5 except we don't call `collect`: + +```rust +let v1: Vec = vec![1, 2, 3]; + +v1.iter().map(|x| x + 1); // without collect +``` + +It will compile, but it will give us a warning: + +```text +warning: unused result which must be used: iterator adaptors are lazy and do +nothing unless consumed, #[warn(unused_must_use)] on by default + --> src/main.rs:4:1 + | +4 | v1.iter().map(|x| x + 1); // without collect + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +``` + +We get this warning because iterator adaptors won't start actually doing the +processing on their own. They need some other method that causes the iterator +chain to evaluate. We call those *consuming adaptors*, and `collect` is one of +them. + +So how do we tell which iterator methods consume the iterator or not? And what +adaptors are available? For that, let's look at the `Iterator` trait. + +### The `Iterator` trait + +Iterators all implement a trait named `Iterator` that is defined in the standard +library. The definition of the trait looks like this: + +```rust +trait Iterator { + type Item; + + fn next(&mut self) -> Option; +} +``` + +There's some new syntax that we haven't covered here yet: `type Item` and +`Self::Item` are defining an *associated type* with this trait, and we'll talk +about associated types in depth in Chapter XX. For now, all you need to know is +that this code says the `Iterator` trait requires that you also define an +`Item` type, and this `Item` type is used in the return type of the `next` +method. In other words, the `Item` type will be the type of element that's +returned from the iterator. + +Let's make an iterator named `Counter` that will count from `1` to `5`, using +the `Iterator` trait. First, we need to create a struct that holds the current +state of the iterator, which is one field named `count` that will hold a `u32`. +We'll also define a `new` method, which isn't strictly necessary. We want our +`Counter` to go from one to five, though, so we're always going to have it +holding a zero to start: + +```rust +struct Counter { + count: u32, +} + +impl Counter { + fn new() -> Counter { + Counter { count: 0 } + } +} +``` + +Next, we're going to implement the `Iterator` trait for our `Counter` type by +defining the body of the `next` method. The way we want our iterator to work +is to add one to the state (which is why we initialized `count` to 0, since we +want our iterator to return one first). If `count` is still less than six, we'll +return the current value, but if `count` is six or higher, our iterator will +return `None`, as shown in Listing 13-6: + +
+ +```rust +impl Iterator for Counter { + // Our iterator will produce u32s + type Item = u32; + + fn next(&mut self) -> Option { + // increment our count. This is why we started at zero. + self.count += 1; + + // check to see if we've finished counting or not. + if self.count < 6 { + Some(self.count) + } else { + None + } + } +} +``` + +
+ +Listing 13-6: Implementing the `Iterator` trait on our `Counter` struct + +
+
+ + + +The `type Item = u32` line is saying that the associated `Item` type will be +a `u32` for our iterator. Again, don't worry about associated types yet, because +we'll be covering them in Chapter XX. + +The `next` method is the main interface into an iterator, and it returns an +`Option`. If the option is `Some(value)`, we have gotten another value from the +iterator. If it's `None`, iteration is finished. Inside of the `next` method, +we do whatever kind of calculation our iterator needs to do. In this case, we +add one, then check to see if we're still below six. If we are, we can return +`Some(self.count)` to produce the next value. If we're at six or more, +iteration is over, so we return `None`. + +The iterator trait specifies that when an iterator returns `None`, that +indicates iteration is finished. The trait does not mandate anything about the +behavior an iterator must have if the `next` method is called again after +having returned one `None` value. In this case, every time we call `next` after +getting the first `None` value will still return `None`, but the internal +`count` field will continue to be incremented by one each time. If we call +`next` as many times as the maximum value a `u32` value can hold, `count` will +overflow (which will `panic!` in debug mode and wrap in release mode). Other +iterator implementations choose to start iterating again. If you need to be +sure to have an iterator that will always return `None` on subsequent calls to +the `next` method after the first `None` value is returned, you can use the +`fuse` method to create an iterator with that characteristic out of any other +iterator. + +Once we've implemented the `Iterator` trait, we have an iterator! We can use +the iterator functionality that our `Counter` struct now has by calling the +`next` method on it repeatedly: + +```rust,ignore +let mut counter = Counter::new(); + +let x = counter.next(); +println!("{:?}", x); + +let x = counter.next(); +println!("{:?}", x); + +let x = counter.next(); +println!("{:?}", x); + +let x = counter.next(); +println!("{:?}", x); + +let x = counter.next(); +println!("{:?}", x); + +let x = counter.next(); +println!("{:?}", x); +``` + +This will print `Some(1)` through `Some(5)` and then `None`, each on their own +line. + +### All Sorts of `Iterator` Adaptors + +In Listing 13-5, we had iterators and we called methods like `map` and +`collect` on them. In Listing 13-6, however, we only implemented the `next` +method on our `Counter`. How do we get methods like `map` and `collect` on our +`Counter`? + +Well, when we told you about the definition of `Iterator`, we committed a small +lie of omission. The `Iterator` trait has a number of other useful methods +defined on it that come with default implementations that call the `next` +method. Since `next` is the only method of the `Iterator` trait that does not +have a default implementation, once you've done that, you get all of the other +`Iterator` adaptors for free. There are a lot of them! + +For example, if for some reason we wanted to take the first five values that +an instance of `Counter` produces, pair those values with values produced by +another `Counter` instance after skipping the first value that instance +produces, multiply each pair together, keep only those results that are +divisible by three, and add all the resulting values together, we could do: + +```rust,ignore +let sum: u32 = Counter::new().take(5) + .zip(Counter::new().skip(1)) + .map(|(a, b)| a * b) + .filter(|x| x % 3 == 0) + .sum(); +assert_eq!(48, sum); +``` + +All of these method calls are possible because we implemented the `Iterator` +trait by specifying how the `next` method works. Use the standard library +documentation to find more useful methods that will come in handy when you're +working with iterators. + +## Improving our I/O Project + +In our I/O project implementing `grep` in the last chapter, there are some +places where the code could be made clearer and more concise using iterators. +Let's take a look at how iterators can improve our implementation of the +`Config::new` function and the `grep` function. + +### Removing a `clone` by Using an Iterator + +Back in listing 12-8, we had this code that took a slice of `String` values and +created an instance of the `Config` struct by checking for the right number of +arguments, indexing into the slice, and cloning the values so that the `Config` +struct could own those values: + +```rust,ignore +impl Config { + fn new(args: &[String]) -> Result { + if args.len() < 3 { + return Err("not enough arguments"); + } + + let search = args[1].clone(); + let filename = args[2].clone(); + + Ok(Config { + search: search, + filename: filename, + }) + } +} +``` + +At the time, we said not to worry about the `clone` calls here, and that we +could remove them in the future. Well, that time is now! So, why do we need +`clone` here? The issue is that we have a slice with `String` elements in the +parameter `args`, and the `new` function does not own `args`. In order to be +able to return ownership of a `Config` instance, we need to clone the values +that we put in the `search` and `filename` fields of `Config`, so that the +`Config` instance can own its values. + +Now that we know more about iterators, we can change the `new` function to +instead take ownership of an iterator as its argument. We'll use the iterator +functionality instead of having to check the length of the slice and index into +specific locations. Since we've taken ownership of the iterator, and we won't be +using indexing operations that borrow anymore, we can move the `String` values +from the iterator into `Config` instead of calling `clone` and making a new +allocation. + +First, let's take `main` as it was in Listing 12-6, and change it to pass the +return value of `env::args` to `Config::new`, instead of calling `collect` and +passing a slice: + +```rust,ignore +fn main() { + let config = Config::new(env::args()); + // ...snip... +``` + + + +If we look in the standard library documentation for the `env::args` function, +we'll see that its return type is `std::env::Args`. So next we'll update the +signature of the `Config::new` function so that the parameter `args` has the +type `std::env::Args` instead of `&[String]`: + + +```rust,ignore +impl Config { + fn new(args: std::env::Args) -> Result { + // ...snip... +``` + + + +Next, we'll fix the body of `Config::new`. As we can also see in the standard +library documentation, `std::env::Args` implements the `Iterator` trait, so we +know we can call the `next` method on it! Here's the new code: + +```rust +impl Config { + fn new(mut args: std::env::Args) -> Result { + args.next(); + + let search = match args.next() { + Some(arg) => arg, + None => return Err("Didn't get a search string"), + }; + + let filename = match args.next() { + Some(arg) => arg, + None => return Err("Didn't get a file name"), + }; + + Ok(Config { + search: search, + filename: filename, + }) + } +} +``` + + + +Remember that the first value in the return value of `env::args` is the name of +the program. We want to ignore that, so first we'll call `next` and not do +anything with the return value. The second time we call `next` should be the +value we want to put in the `search` field of `Config`. We use a `match` to +extract the value if `next` returns a `Some`, and we return early with an `Err` +value if there weren't enough arguments (which would cause this call to `next` +to return `None`). + +We do the same thing for the `filename` value. It's slightly unfortunate that +the `match` expressions for `search` and `filename` are so similar. It would be +nice if we could use `?` on the `Option` returned from `next`, but `?` only +works with `Result` values currently. Even if we could use `?` on `Option` like +we can on `Result`, the value we would get would be borrowed, and we want to +move the `String` from the iterator into `Config`. + +### Making Code Clearer with Iterator Adaptors + +The other bit of code where we could take advantage of iterators was in the +`grep` function as implemented in Listing 12-15: + + + +```rust +fn grep<'a>(search: &str, contents: &'a str) -> Vec<&'a str> { + let mut results = Vec::new(); + + for line in contents.lines() { + if line.contains(search) { + results.push(line); + } + } + + results +} +``` + +We can write this code in a much shorter way, and avoiding having to have a +mutable intermediate `results` vector, by using iterator adaptor methods like +this instead: + +```rust +fn grep<'a>(search: &str, contents: &'a str) -> Vec<&'a str> { + contents.lines() + .filter(|line| line.contains(search)) + .collect() +} +``` + +Here, we use the `filter` adaptor to only keep the lines that +`line.contains(search)` returns true for. We then collect them up into another +vector with `collect`. Much simpler! + +We can use the same technique in the `grep_case_insensitive` function that we +defined in Listing 12-16 as follows: + + + +```rust +fn grep_case_insensitive<'a>(search: &str, contents: &'a str) -> Vec<&'a str> { + contents.lines() + .filter(|line| { + line.to_lowercase().contains(&search) + }).collect() +} +``` + +Not too bad! So which style should you choose? Most Rust programmers prefer to +use the iterator style. It's a bit tougher to understand at first, but once you +gain an intuition for what the various iterator adaptors do, this is much +easier to understand. Instead of fiddling with the various bits of looping +and building a new vector, the code focuses on the high-level objective of the +loop, abstracting some of the commonplace code so that it's easier to see the +concepts that are unique to this usage of the code, like the condition on which +the code is filtering each element in the iterator. + +But are they truly equivalent? Surely the more low-level loop will be faster. +Let's talk about performance. + +## Performance + +Which version of our `grep` functions is faster: the version with an explicit +`for` loop or the version with iterators? We ran a benchmark by loading the +entire contents of "The Adventures of Sherlock Holmes" by Sir Arthur Conan +Doyle into a `String` and looking for the word "the" in the contents. Here were +the results of the benchmark on the version of grep using the `for` loop and the +version using iterators: + +```text +test bench_grep_for ... bench: 19,620,300 ns/iter (+/- 915,700) +test bench_grep_iter ... bench: 19,234,900 ns/iter (+/- 657,200) +``` + +The iterator version ended up slightly faster! We're not going to go through +the benchmark code here, as the point is not to prove that they're exactly +equivalent, but to get a general sense of how these two implementations +compare. For a *real* benchmark, you'd want to check various texts of various +sizes, different words, words of different lengths, and all kinds of other +variations. The point is this: iterators, while a high-level abstraction, get +compiled down to roughly the same code as if you'd written the lower-level code +yourself. Iterators are one of Rust's *zero-cost abstractions*, by which we mean +using the abstraction imposes no additional runtime overhead in the same way +that Bjarne Stroustrup, the original designer and implementer of C++, defines +*zero-overhead*: + +> In general, C++ implementations obey the zero-overhead principle: What you +> don’t use, you don’t pay for. And further: What you do use, you couldn’t hand +> code any better. +> +> - Bjarne Stroustrup "Foundations of C++" + +As another example, here is some code taken from an audio decoder. This code +uses an iterator chain to do some math on three variables in scope: a `buffer` +slice of data, an array of 12 `coefficients`, and an amount by which to shift +data in `qlp_shift`. We've declared the variables within this example but not +given them any values; while this code doesn't have much meaning outside of its +context, it's still a concise, real-world example of how Rust translates +high-level ideas to low-level code: + +```rust,ignore +let buffer: &mut [i32]; +let coefficients: [i64; 12]; +let qlp_shift: i16; + +for i in 12..buffer.len() { + let prediction = coefficients.iter() + .zip(&buffer[i - 12..i]) + .map(|(&c, &s)| c * s as i64) + .sum::() >> qlp_shift; + let delta = buffer[i]; + buffer[i] = prediction as i32 + delta; +} +``` + +In order to calculate the value of `prediction`, this code iterates through +each of the 12 values in `coefficients`, uses the `zip` method to pair the +coefficient values with the previous 12 values in `buffer`. Then for each pair, +multiply the values together, sum all the results, and shift the bits in the +sum `qlp_shift` bits to the right + +Calculations in applications like audio decoders often prioritize performance +most highly. Here, we're creating an iterator, using two adaptors, then +consuming the value. What assembly code would this Rust code compile to? Well, +as of this writing, it compiles down to the same assembly you'd write by hand. +There's no loop at all corresponding to the iteration over the values in +`coefficients`: Rust knows that there are twelve iterations, so it "unrolls" +the loop. All of the coefficients get stored in registers (which means +accessing the values is very fast). There are no bounds checks on the array +access. It's extremely efficient. + +Now that you know this, go use iterators and closures without fear! They make +code feel higher-level, but don't impose a runtime performance penalty for +doing so. + +## Summary + +Closures and iterators are Rust features inspired by functional programming +language ideas. They contribute to Rust's ability to clearly express high-level +ideas. The implementations of closures and iterators, as well as other zero-cost +abstractions in Rust, are such that runtime performance is not affected. + +Now that we've improved the expressiveness of our I/O project, let's look at +some more features of `cargo` that would help us get ready to share the project +with the world. diff --git a/src/doc/book/second-edition/nostarch/chapter14.md b/src/doc/book/second-edition/nostarch/chapter14.md new file mode 100644 index 0000000000..2ce61b041a --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter14.md @@ -0,0 +1,727 @@ + +[TOC] + +# More about Cargo and Crates.io + +We've used some features of Cargo in this book so far, but only the most basic +ones. We've used Cargo to build, run, and test our code, but it can do a lot +more. Let's go over some of its other features now. Cargo can do even more than +what we will cover in this chapter; for a full explanation, see its +documentation. + +We're going to cover: + +* Customizing your build through release profiles +* Publishing libraries on crates.io +* Organizing larger projects with workspaces +* Installing binaries from crates.io +* Extending Cargo with your own custom commands + +## Release profiles + +Cargo supports a notion of *release profiles*. These profiles control various +options for compiling your code and let you configure each profile +independently of the others. You've seen a hint of this feature in the output +of your builds: + +```text +$ cargo build + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs +$ cargo build --release + Finished release [optimized] target(s) in 0.0 secs +``` + +The "debug" and "release" notifications here indicate that the compiler is +using different profiles. Cargo supports four profiles: + +* `dev`: used for `cargo build` +* `release` used for `cargo build --release` +* `test` used for `cargo test` +* `doc` used for `cargo doc` + +We can customize our `Cargo.toml` file with `[profile.*]` sections to tweak +various compiler options for these profiles. For example, here's one of the +default options for the `dev` and `release` profiles: + +```toml +[profile.dev] +opt-level = 0 + +[profile.release] +opt-level = 3 +``` + +The `opt-level` setting controls how many optimizations Rust will apply to your +code. The setting goes from zero to three. Applying more optimizations takes +more time. When you're compiling very often in development, you'd usually want +compiling to be fast at the expense of the resulting code running slower. When +you're ready to release, it's better to spend more time compiling the one time +that you build your code to trade off for code that will run faster every time +you use that compiled code. + +We could override these defaults by changing them in `Cargo.toml`. For example, +if we wanted to use optimization level 1 in development: + +```toml +[profile.dev] +opt-level = 1 +``` + +This overrides the default setting of `0`, and now our development builds will +use more optimizations. Not as much as a release build, but a little bit more. + +For the full list of settings and the defaults for each profile, see Cargo's +documentation. at *http://doc.crates.io/* + +## Publishing a Crate to Crates.io + +We've added crates from crates.io as dependencies of our project. We can choose +to share our code for other people to use as well. Crates.io distributes the +source code of your packages, so it is primarily used to distribute code that's +open source. + +Rust and Cargo have some features that can 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. + +### Documentation Comments + +In Chapter 3, we saw comments in Rust that start with `//`. Rust also has a +second kind of comment: the *documentation comment*. While comments can be +useful if someone is reading your code, you can generate HTML documentation +that displays the contents of documentation comments for public API items meant +for someone who's interested in knowing how to *use* your crate, as opposed to +how your crate is *implemented*. Note that documentation is only generated for +library crates, since binary crates don't have a public API that people need to +know how to use. + +Documentation comments use `///` instead of `//` and support Markdown notation +inside. They go just before the item they are documenting. Here's documentation +comments for an `add_one` function: + +
+ +Filename: src/lib.rs + +````rust +/// Adds one to the number given. +/// +/// # Examples +/// +/// ``` +/// let five = 5; +/// +/// assert_eq!(6, add_one(5)); +/// # fn add_one(x: i32) -> i32 { +/// # x + 1 +/// # } +/// ``` +pub fn add_one(x: i32) -> i32 { + x + 1 +} +```` + +
+ +Listing 14-1: A documentation comment for a function + +
+
+ +`cargo doc` runs a tool distributed with Rust, `rustdoc`, to generate HTML +documentation from these comments. To try this out locally, you can run `cargo +doc --open`, which will build the documentation for your current crate (as well +as all of your crate's dependencies) and open it in a web browser. Navigate to +the `add_one` function and you'll see how the text in the documentation +comments gets rendered. + +Adding examples in code blocks in your documentation comments is a way to +clearly demonstrate how to use your library. There's an additional bonus reason +to do this: `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 in Listing 14-1; you'll see a section in the test +results like this: + +```test + Doc-tests add-one + +running 1 test +test add_one_0 ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured +``` + +Try changing the function or the example to see that `cargo test` will catch +that the example no longer works! + +There's another style of doc comment, `//!`, to comment containing items (e.g. +crates, modules or functions), instead of the items following it. These are +typically used inside the crate root (lib.rs) or a module's root (mod.rs) to +document the crate or the module as a whole, respectively. Here's the +documentation within the `libstd` module that contains the entire standard +library: + +``` +//! # The Rust Standard Library +//! +//! The Rust Standard Library provides the essential runtime +//! functionality for building portable Rust software. +``` + +### 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. When publishing a crate for people +unfamiliar with the implementation to use, it's worth taking time to consider +if the structure of your crate that's useful for you as you're developing is +what would be useful for people depending on your crate. If the structure isn't +convenient to use from another library, you don't have to rearrange your +internal organization: you can choose to re-export items to make a different +public structure with `pub use`. + +For example, say that we made a library named `art` consisting of a `kinds` +module containing an enum named `Color` and a `utils` module containing a +function named `mix` as shown in Listing 14-2: + +
+Filename: src/lib.rs + +```rust +//! # Art +//! +//! A library for modeling artistic concepts. + +pub mod kinds { + /// The primary colors according to the RYB color model. + pub enum PrimaryColor { + Red, + Yellow, + Blue, + } + + /// The secondary colors according to the RYB color model. + pub enum SecondaryColor { + Orange, + Green, + Purple, + } +} + +pub mod utils { + use kinds::*; + + /// Combines two primary colors in equal amounts to create + /// a secondary color. + pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor { + // ...snip... + } +} +``` + +
+ +Listing 14-2: An `art` library with items organized into `kinds` and `utils` +modules + +
+
+ +In order to use this library, another crate would have `use` statements as in +Listing 14-3: + +
+Filename: src/main.rs + +```rust,ignore +extern crate art; + +use art::kinds::PrimaryColor; +use art::utils::mix; + +fn main() { + let red = PrimaryColor::Red; + let yellow = PrimaryColor::Yellow; + mix(red, yellow); +} +``` + +
+ +Listing 14-3: A program using the `art` crate's items with its internal +structure exported + +
+
+ +Users of this crate shouldn't need to know that `PrimaryColor` and +`SecondaryColor` are in the `kinds` module, and `mix` is in the `utils` module; +that structure might be useful for internal organization but doesn't have much +meaning from the outside looking in. + +To change this, we can add the following `pub use` statements to the code from +Listing 14-2 to re-export the types at the top level, as shown in Listing 14-4: + +
+Filename: src/lib.rs + +```rust +//! # Art +//! +//! A library for modeling artistic concepts. + +pub use kinds::PrimaryColor; +pub use kinds::SecondaryColor; +pub use utils::mix; + +pub mod kinds { + // ...snip... +``` + +
+ +Listing 14-4: Adding `pub use` statements to re-export items + +
+
+ + + +Re-exports are listed and linked on the front page of the crate's API +documentation. Users of the `art` crate can still see and choose to use the +internal structure as in Listing 14-3, or they can use the more convenient +structure from Listing 14-4, as shown in Listing 14-5: + +
+Filename: src/main.rs + +```rust,ignore +extern crate art; + +use art::PrimaryColor; +use art::mix; + +fn main() { + // ...snip... +} +``` + +
+ +Listing 14-5: Using the re-exported items from the `art` crate + +
+
+ + + +Creating a useful public API structure is more of an art than a science. +Choosing `pub use` gives you flexibility in how you expose your crate's +internal structure to 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. + +### Before Your First Publish + +Before being able to publish any crates, you'll need to create an account on +crates.io at *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. A GitHub account is a requirement for now, 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* page and run the `cargo login` +command with the API key as the page specifies, which will look something like +this: + + +```text +$ cargo login abcdefghijklmnopqrstuvwxyz012345 +``` + +This command will inform Cargo of your API token and store it locally in +*~/.cargo/config*. Note that this token is a **secret** and should not be +shared with anyone else. If it gets shared with anyone for any reason, you +should regenerate it immediately. + +### Before Publishing a New Crate + +First, your crate will need a unique name. While you're working on a crate +locally, you may name a crate whatever you'd like, but crate names on +crates.io at *https://crates.io* are allocated on a first-come-first- serve basis. Once a crate name +is taken, it cannot be used for another crate, so check on the site that the +name you'd like is available. + +If you try to publish a crate as generated by `cargo new`, you'll get a warning +and then an error: + +```text +$ cargo publish + Updating registry `https://github.com/rust-lang/crates.io-index` +warning: manifest has no description, license, license-file, documentation, +homepage or repository. +...snip... +error: api errors: missing or empty metadata fields: description, license. +Please see http://doc.crates.io/manifest.html#package-metadata for how to +upload metadata +``` + +We can include more information about our package in *Cargo.toml*. Some of +these fields are optional, but a description and a license are required in +order to publish so that people will know what your crate does and under what +terms they may use it. + +The description appears with your crate in search results and on your crate's +page. Descriptions are usually a sentence or two. The `license` field takes a +license identifier value, and the possible values have been specified by the +Linux Foundation's Software Package Data Exchange (SPDX) at *http://spdx.org/licenses/*. If you would +like to use a license that doesn't appear there, instead of the `license` key, +you can use `license-file` to specify the name of a file in your project that +contains the text of the license you want to use. + +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`, which +demonstrates that you can specify multiple license identifiers separated by a +slash. So the *Cargo.toml* for a project that is ready to publish might look +like this: + + +```toml +[package] +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" + +[dependencies] +``` + +Be sure to check out the documentation on crates.io at *http://doc.crates.io/manifest.html#package-metadata* that +describes other metadata you can specify to ensure your crate can be discovered +and used more easily! + + +### Publishing to Crates.io + +Now that we've created an account, saved our API token, chosen a name for our +crate, and specified the required metadata, we're ready to publish! Publishing +a crate is when a specific version is uploaded to be hosted on crates.io. + +Take care when publishing a crate, because a publish is **permanent**. The +version can never be overwritten, and the code cannot be deleted. However, +there is no limit to the number of versions which can be published. + +Let's run the `cargo publish` command, which should succeed this time since +we've now specified the required metadata: + +```text +$ cargo publish + Updating registry `https://github.com/rust-lang/crates.io-index` +Packaging guessing_game v0.1.0 (file:///projects/guessing_game) +Verifying guessing_game v0.1.0 (file:///projects/guessing_game) +Compiling guessing_game v0.1.0 +(file:///projects/guessing_game/target/package/guessing_game-0.1.0) + Finished debug [unoptimized + debuginfo] target(s) in 0.19 secs +Uploading guessing_game v0.1.0 (file:///projects/guessing_game) +``` + +Congratulations! You've now shared your code with the Rust community, and +anyone can easily add your crate as a dependency to 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, +change the `version` value specified in your *Cargo.toml*. 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` + +Occasions may arise where you publish a version of a crate that actually ends +up being broken for one reason or another, such as a syntax error or forgetting +to include a file. For situations such as this, Cargo supports *yanking* a +version of a crate. + +Marking a version of a crate as yanked means that no projects will be able to +start depending on that version, but all existing projects that depend on that +version will continue to be allowed to download and depend on that version. One +of the major goals of crates.io is to act as a permanent archive of code so +that builds of all projects will continue to work, and allowing deletion of a +version would go against this goal. Essentially, a yank means that all projects +with a *Cargo.lock* will not break, while any future *Cargo.lock* files +generated will not use the yanked version. + +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 +reset those secrets immediately. + +To yank a version of a crate, run `cargo yank` and specify which version you +want to yank: + +```text +$ 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: + +```text +$ cargo yank --vers 1.0.1 --undo +``` + +## Cargo Workspaces + +In Chapter 12, we built a package that included both a binary crate and a +library crate. But what if the library crate continues to get bigger and we +want to split our package up further into multiple library crates? As packages +grow, separating out major components can be quite useful. In this situation, +Cargo has a feature called *workspaces* that can help us 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 where the code +will be trivial so that we can concentrate on the structure of a workspace. +We'll have a binary that uses two libraries: one that will provide an `add_one` +method and a second that will provide an `add_two` method. Let's start by +creating a new crate for the binary: + +```text +$ cargo new --bin adder + Created binary (application) `adder` project +$ cd adder +``` + +We need to modify the binary package's *Cargo.toml* to tell Cargo the `adder` +package is a workspace. Add this at the bottom of the file: + +```toml +[workspace] +``` + +Like many Cargo features, workspaces support convention over configuration: we +don't need to say anything more than this as long as we follow the convention. +The convention is that any crates that we depend on as sub-directories will be +part of the workspace. Let's add a path dependency to the `adder` crate by +changing the `[dependencies]` section of *Cargo.toml* to look like this: + +```toml +[dependencies] +add-one = { path = "add-one" } +``` + +If we add dependencies that don't have a `path` specified, those will be normal +dependencies that aren't in this workspace. + +Next, generate the `add-one` crate within the `adder` directory: + +```text +$ cargo new add-one + Created library `add-one` project +``` + +Your `adder` directory should now have these directories and files: + +```text +├── Cargo.toml +├── add-one +│   ├── Cargo.toml +│   └── src +│   └── lib.rs +└── src + └── main.rs +``` + +In *add-one/src/lib.rs*, let's add an implementation of an `add_one` function: + +Filename: add-one/src/lib.rs + +```rust +pub fn add_one(x: i32) -> i32 { + x + 1 +} +``` + +Open up *src/main.rs* for `adder` and add an `extern crate` line to bring the +new `add-one` library crate into scope, and change the `main` function to use +the `add_one` function: + +```rust,ignore +extern crate add_one; + +fn main() { + let num = 10; + println!("Hello, world! {} plus one is {}!", num, add_one::add_one(num)); +} +``` + +Let's build it! + +```text +$ cargo build + Compiling add-one v0.1.0 (file:///projects/adder/add-one) + Compiling adder v0.1.0 (file:///projects/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.68 secs +``` + +Note that running `cargo build` in the *adder* directory built both that crate +and the `add-one` crate in *adder/add-one*, but created only one *Cargo.lock* +and one *target* directory, both in the *adder* directory. See if you can add +an `add-two` crate in the same way. + +Let's now say that we'd like to use the `rand` crate in our `add-one` crate. +As usual, we'll add it to the `[dependencies]` section in the `Cargo.toml` for +that crate: + +Filename: add-one/Cargo.toml + +```toml +[dependencies] + +rand = "0.3.14" +``` + +And if we add `extern crate rand;` to *add-one/src/lib.rs* then run `cargo +build`, it will succeed: + +```text +$ cargo build + Updating registry `https://github.com/rust-lang/crates.io-index` + 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) + Finished debug [unoptimized + debuginfo] target(s) in 10.18 secs +``` + +The top level *Cargo.lock* now contains information about the dependency +`add-one` has 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: + +```text +$ cargo build + Compiling adder v0.1.0 (file:///projects/adder) +error[E0463]: can't find crate for `rand` + --> src/main.rs:1:1 + | +1 | extern crate rand; + | ^^^^^^^^^^^^^^^^^^^ can't find crate +``` + +To fix this, edit *Cargo.toml* for the top level and indicate that `rand` is a +dependency for the `adder` crate. + +For another enhancement, let's add a test of the `add_one::add_one` function +within that crate: + +Filename: add-one/src/lib.rs + +```rust +pub fn add_one(x: i32) -> i32 { + x + 1 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + assert_eq!(3, add_one(2)); + } +} +``` + +Now run `cargo test` in the top-level *adder* directory: + +```text +$ cargo test + Compiling adder v0.1.0 (file:///projects/adder) + Finished debug [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 the tests for the top level +crate. To run tests for the other crates, we need to use the `-p` argument to +indicate we want to run tests for a particular package: + +```text +$ cargo test -p add-one + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running target/debug/deps/add_one-abcabcabc + +running 1 test +test tests::it_works ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured + + Doc-tests add-one + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured +``` + +Similarly, if you choose to publish the workspace to crates.io, each crate in +the workspace will get published separately. + +As your project grows, consider 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. + +## 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 which have binary targets can be installed, and all +binaries are installed 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`. Add that directory to your `$PATH` to be able to +run programs you've gotten through `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: + +```text +$ cargo install ripgrep +Updating registry `https://github.com/rust-lang/crates.io-index` + Downloading ripgrep v0.3.2 + ...snip... + Compiling ripgrep v0.3.2 + Finished release [optimized + debuginfo] target(s) in 97.91 secs + Installing ~/.cargo/bin/rg +``` + +The last line of the output shows the location and the name of the installed +binary, which in the case of `ripgrep` is named `rg`. As long as the +installation directory is in our `$PATH` as mentioned above, we can then run +`rg --help` and start using a faster, rustier tool for searching files! + +## Extending Cargo with Custom Commands + +Cargo is designed to be extensible 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`. It's +convenient to `cargo install` extensions to Cargo then be able to run them just +like the built-in Cargo tools! + +## 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 different timeline than 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! diff --git a/src/doc/book/second-edition/nostarch/chapter15.md b/src/doc/book/second-edition/nostarch/chapter15.md new file mode 100644 index 0000000000..759ad3ebb8 --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter15.md @@ -0,0 +1,1384 @@ + +[TOC] + +# Smart Pointers + +*Pointer* is a generic programming term for something that refers to a location +that stores some other data. We learned about Rust's references in Chapter 4; +they're a plain sort of pointer indicated by the `&` symbol and borrow the +value that they point to. *Smart pointers* are data structures that act like a +pointer, but also have additional metadata and capabilities, such as reference +counting. The smart pointer pattern originated in C++. In Rust, an additional +difference between plain 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. + +We've actually already encountered a few smart pointers in this book, even +though we didn't call them that by name at the time. For example, in a certain +sense, `String` and `Vec` from Chapter 8 are both smart pointers. They own +some memory and allow you to manipulate it, and have metadata (like their +capacity) and extra capabilities or guarantees (`String` data will always be +valid UTF-8). The characteristics that distinguish a smart pointer from an +ordinary struct are that smart pointers implement the `Deref` and `Drop` +traits, and in this chapter we'll be discussing both of those traits and 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 and you may write some yourself. The ones we +cover here are the most common ones from the standard library: + +* `Box`, for allocating values on the heap +* `Rc`, a reference counted type so data can have multiple owners +* `RefCell`, which isn't a smart pointer itself, but manages access to the + smart pointers `Ref` and `RefMut` to enforce the borrowing rules at runtime + instead of compile time + +Along the way, we'll also cover: + +* The *interior mutability* pattern where an immutable type exposes an API for + mutating an interior value, and the borrowing rules apply at runtime instead + of compile time +* Reference cycles, how they can leak memory, and how to prevent them + +Let's dive in! + +## `Box` Points to Data on the Heap and Has a Known Size + +The most straightforward smart pointer is a *box*, whose type is written +`Box`. Boxes allow you to put a single value on the heap (we talked about +the stack vs. the heap in Chapter 4). Listing 15-1 shows how to use a box to +store an `i32` on the heap: + +Filename: src/main.rs + +``` +fn main() { + let b = Box::new(5); + println!("b = {}", b); +} +``` + +Listing 15-1: Storing an `i32` value on the heap using a box + +This 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). + +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. A time when boxes are +useful is when you want to ensure that your type has a known size. For +example, consider Listing 15-2, which contains an enum definition for a *cons +list*, a type of data structure that comes from functional programming. + +A cons list is a list where each item contains a value and the next item until +the end of the list, which is signified by a value called `Nil`. Note that we +aren't introducing the idea of "nil" or "null" that we discussed in Chapter 6, +this is just a regular enum variant name we're using because it's the canonical +name to use when describing the cons list data structure. Cons lists aren't +used very often in Rust, `Vec` is a better choice most of the time, but +implementing this data structure is useful as an example. + +Here's our first try at defining a cons list as an enum; note that this won't +compile quite yet: + +Filename: src/main.rs + +``` +enum List { + Cons(i32, List), + Nil, +} +``` + +Listing 15-2: The first attempt of defining an enum to represent a cons list +data structure of `i32` values + +We're choosing to implement a cons list that only holds `i32` values, but we +could have chosen to implement it using generics as we discussed in Chapter 10 +to define a cons list concept independent of the type of value stored in the +cons list. + +Using a cons list to store the list `1, 2, 3` would look like this: + +``` +use List::{Cons, Nil}; + +fn main() { + let list = Cons(1, Cons(2, Cons(3, Nil))); +} +``` + +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 +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-3: + +``` +error[E0072]: recursive type `List` has infinite size + --> + | +1 | enum List { + | _^ starting here... +2 | | Cons(i32, List), +3 | | Nil, +4 | | } + | |_^ ...ending here: recursive type has infinite size + | + = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to + make `List` representable +``` + +Listing 15-3: The error we get when attempting to define a recursive enum + +The error says this type 'has infinite size'. Why is that? It's because we've +defined `List` to have a variant that is recursive: it holds another value of +itself. 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 type. +Recall the `Message` enum we defined in Listing 6-2 when we discussed enum +definitions in Chapter 6: + +``` +enum Message { + Quit, + Move { x: i32, y: i32 }, + Write(String), + ChangeColor(i32, i32, i32), +} +``` + +When Rust needs to know how much space to allocate for a `Message` value, it +can go through each of the variants and see that `Message::Quit` does not need +any space, `Message::Move` needs enough space to store two `i32` values, and so +forth. Therefore, 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 the Rust compiler looks at a recursive type +like `List` in Listing 15-2. The compiler tries to figure out how much memory +is needed to store value of `List`, and starts by looking at the `Cons` +variant. The `Cons` variant holds a value of type `i32` and a value of type +`List`, so `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 a `List` needs, it looks at +its 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-4. + +An infinite Cons list + +Figure 15-4: An infinite `List` consisting of infinite `Cons` variants + +Rust can't figure out how much space to allocate for recursively defined types, +so the compiler gives the error in Listing 15-3. The error did include this +helpful suggestion: + +``` += help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to + make `List` representable +``` + +Because a `Box` is a pointer, we always know how much space it needs: a +pointer takes up a `usize` amount of space. The value of the `usize` will be +the address of the heap data. The heap data can be any size, but the address to +the start of that heap data will always fit in a `usize`. So if we change our +definition from Listing 15-2 to look like the definition here in Listing 15-5, +and change `main` to use `Box::new` for the values inside the `Cons` variants +like so: + +Filename: src/main.rs + +``` +enum List { + Cons(i32, Box), + Nil, +} + +use List::{Cons, Nil}; + +fn main() { + let list = Cons(1, + Box::new(Cons(2, + Box::new(Cons(3, + Box::new(Nil)))))); +} +``` + +Listing 15-5: Definition of `List` that uses `Box` in order to have a +known size + +The compiler will be able to figure out the size it needs to store a `List` +value. Rust will look at `List`, and again start by looking at the `Cons` +variant. The `Cons` variant will need the size of `i32` plus the space to store +a `usize`, since a box always has the size of a `usize`, no matter what it's +pointing to. Then Rust looks at the `Nil` variant, which does not store a +value, so `Nil` doesn't need any space. We've broken the infinite, recursive +chain by adding in a box. Figure 15-6 shows what the `Cons` variant looks like +now: + +A finite Cons list + +Figure 15-6: A `List` that is not infinitely sized since `Cons` holds a `Box` + +This is the main area where boxes are useful: breaking up an infinite data +structure so that the compiler can know what size it is. We'll look at another +case where Rust has data of unknown size in Chapter 17 when we discuss trait +objects. + +Even though you won't be using boxes very often, they are a good way to +understand the smart pointer pattern. Two of the aspects of `Box` that are +commonly used with smart pointers are its implementations of the `Deref` trait +and the `Drop` trait. Let's investigate how these traits work and how smart +pointers use them. + +## The `Deref` Trait Allows Access to the Data Through a Reference + +The first important smart pointer-related trait is `Deref`, which allows us to +override `*`, the dereference operator (as opposed to the multiplication +operator or the glob operator). Overriding `*` for smart pointers makes +accessing the data behind the smart pointer convenient, and we'll talk about +what we mean by convenient when we get to deref coercions later in this section. + +We briefly mentioned the dereference operator in Chapter 8, in the hash map +section titled "Update a Value Based on the Old Value". We had a mutable +reference, and we wanted to change the value that the reference was pointing +to. In order to do that, first we had to dereference the reference. Here's +another example using references to `i32` values: + +``` +let mut x = 5; +{ + let y = &mut x; + + *y += 1 +} + +assert_eq!(6, x); +``` + +We use `*y` to access the data that the mutable reference in `y` refers to, +rather than the mutable reference itself. We can then modify that data, in this +case by adding 1. + +With references that aren't smart pointers, there's only one value that the +reference is pointing to, so the dereference operation is straightforward. +Smart pointers can also store metadata about the pointer or the data. When +dereferencing a smart pointer, we only want the data, not the metadata, since +dereferencing a regular reference only gives us data and not metadata. We want +to be able to use smart pointers in the same places that we can use regular +references. To enable that, we can override the behavior of the `*` operator by +implementing the `Deref` trait. + +Listing 15-7 has an example of overriding `*` using `Deref` on a struct we've +defined to hold mp3 data and metadata. `Mp3` is, in a sense, a smart pointer: +it owns the `Vec` data containing the audio. In addition, it holds some +optional metadata, in this case the artist and title of the song in the audio +data. We want to be able to conveniently access the audio data, not the +metadata, so we implement the `Deref` trait to return the audio data. +Implementing the `Deref` trait requires implementing one method named `deref` +that borrows `self` and returns the inner data: + +Filename: src/main.rs + +``` +use std::ops::Deref; + +struct Mp3 { + audio: Vec, + artist: Option, + title: Option, +} + +impl Deref for Mp3 { + type Target = Vec; + + fn deref(&self) -> &Vec { + &self.audio + } +} + +fn main() { + let my_favorite_song = Mp3 { + // we would read the actual audio data from an mp3 file + audio: vec![1, 2, 3], + artist: Some(String::from("Nirvana")), + title: Some(String::from("Smells Like Teen Spirit")), + }; + + assert_eq!(vec![1, 2, 3], *my_favorite_song); +} +``` + +Listing 15-7: An implementation of the `Deref` trait on a struct that holds mp3 +file data and metadata + +Most of this should look familiar: a struct, a trait implementation, and a +main function that creates an instance of the struct. There is one part we +haven't explained thoroughly yet: similarly to Chapter 13 when we looked at the +Iterator trait with the `type Item`, the `type Target = T;` syntax is defining +an associated type, which is covered in more detail in Chapter 19. Don't worry +about that part of the example too much; it is a slightly different way of +declaring a generic parameter. + +In the `assert_eq!`, we're verifying that `vec![1, 2, 3]` is the result we get +when dereferencing the `Mp3` instance with `*my_favorite_song`, which is what +happens since we implemented the `deref` method to return the audio data. If +we hadn't implemented the `Deref` trait for `Mp3`, Rust wouldn't compile the +code `*my_favorite_song`: we'd get an error saying type `Mp3` cannot be +dereferenced. + +The reason this code works is that what the `*` operator is doing behind +the scenes when we call `*my_favorite_song` is: + +``` +*(my_favorite_song.deref()) +``` + +This calls the `deref` method on `my_favorite_song`, which borrows +`my_favorite_song` and returns a reference to `my_favorite_song.audio`, since +that's what we defined `deref` to do in Listing 15-5. `*` on references is +defined to just follow the reference and return the data, so the expansion of +`*` doesn't recurse for the outer `*`. So we end up with data of type +`Vec`, which matches the `vec![1, 2, 3]` in the `assert_eq!` in Listing +15-5. + +The reason that the return type of the `deref` method is still a reference and +why it's necessary to dereference the result of the method is that if the +`deref` method returned just the value, using `*` would always take ownership. + +### Implicit Deref Coercions with Functions and Methods + +Rust tends to favor explicitness over implicitness, but one case where this +does not hold true is *deref coercions* of arguments to functions and methods. +A deref coercion will automatically convert a reference to a pointer or a smart +pointer into a reference to that pointer's contents. A deref coercion happens +when a value is passed to a function or method, and only happens if it's needed +to get the type of the value passed in to match the type of the parameter +defined in the signature. Deref coercion was added to Rust to make calling +functions and methods not need as many explicit references and dereferences +with `&` and `*`. + +Using our `Mp3` struct from Listing 15-5, here's the signature of a function to +compress mp3 audio data that takes a slice of `u8`: + +``` +fn compress_mp3(audio: &[u8]) -> Vec { + // the actual implementation would go here +} +``` + +If Rust didn't have deref coercion, in order to call this function with the +audio data in `my_favorite_song`, we'd have to write: + +``` +compress_mp3(my_favorite_song.audio.as_slice()) +``` + +That is, we'd have to explicitly say that we want the data in the `audio` field +of `my_favorite_song` and that we want a slice referring to the whole +`Vec`. If there were a lot of places where we'd want process the `audio` +data in a similar manner, `.audio.as_slice()` would be wordy and repetitive. + +However, because of deref coercion and our implementation of the `Deref` trait +on `Mp3`, we can call this function with the data in `my_favorite_song` by +using this code: + +``` +let result = compress_mp3(&my_favorite_song); +``` + +Just an `&` and the instance, nice! We can treat our smart pointer as if it was +a regular reference. Deref coercion means that Rust can use its knowledge of +our `Deref` implementation, namely: Rust knows that `Mp3` implements the +`Deref` trait and returns `&Vec` from the `deref` method. Rust also knows +the standard library implements the `Deref` trait on `Vec` to return `&[T]` +from the `deref` method (and we can find that out too by looking at the API +documentation for `Vec`). So, at compile time, Rust will see that it can use +`Deref::deref` twice to turn `&Mp3` into `&Vec` and then into `&[T]` to +match the signature of `compress_mp3`. That means we get to do less typing! +Rust will analyze types through `Deref::deref` as many times as it needs to in +order to get a reference to match the parameter's type, when the `Deref` trait +is defined for the types involved. The indirection is resolved at compile time, +so there is no run-time penalty for taking advantage of deref coercion. + +There's also a `DerefMut` trait for overriding `*` on `&mut T` for use in +assignment in the same fashion that we use `Deref` to override `*` on `&T`s. + +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`. + +The first two are the same, except for mutability: if you have a `&T`, and +`T` implements `Deref` to some type `U`, you can get a `&U` transparently. Same +for mutable references. The last one is more tricky: if you have a mutable +reference, it will also coerce to an immutable one. The other case is _not_ +possible though: immutable references will never coerce to mutable ones. + +The reason that the `Deref` trait is important to the smart pointer pattern is +that smart pointers can then be treated like regular references and used in +places that expect regular references. We don't have to redefine methods and +functions to take smart pointers explicitly, for example. + +## The `Drop` Trait Runs Code on Cleanup + +The other trait that's important to the smart pointer pattern is the `Drop` +trait. `Drop` lets us run some code when a value is about to go out of scope. +Smart pointers perform important cleanup when being dropped, like deallocating +memory or decrementing a reference count. More generally, data types can manage +resources beyond memory, like files or network connections, and use `Drop` to +release those resources when our code is done with them. We're discussing +`Drop` in the context of smart pointers, though, because the functionality of +the `Drop` trait is almost always used when implementing smart pointers. + +In some other languages, we have to remember to call code to free the memory or +resource every time we finish using an instance of a smart pointer. If we +forget, the system our code is running on might get overloaded and crash. In +Rust, we can specify that some code should be run when a value goes out of +scope, and the compiler will insert this code automatically. That means we don't +need to remember to put this code everywhere we're done with an instance of +these types, but we still won't leak resources! + +The way we specify code should be run when a value goes out of scope is by +implementing the `Drop` trait. The `Drop` trait requires us to implement one +method named `drop` that takes a mutable reference to `self`. + +Listing 15-8 shows a `CustomSmartPointer` struct that doesn't actually do +anything, but we're printing out `CustomSmartPointer created.` right after we +create an instance of the struct and `Dropping CustomSmartPointer!` when the +instance goes out of scope so that we can see when each piece of code gets run. +Instead of a `println!` statement, you'd fill in `drop` with whatever cleanup +code your smart pointer needs to run: + +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."); + println!("Wait for it..."); +} +``` + +Listing 15-8: A `CustomSmartPointer` struct that implements the `Drop` trait, +where we could put code that would clean up after the `CustomSmartPointer`. + +The `Drop` trait is in the prelude, so we don't need to import it. The `drop` +method implementation calls the `println!`; this is where you'd put the actual +code needed to close the socket. In `main`, we create a new instance of +`CustomSmartPointer` then print out `CustomSmartPointer created.` to be able to +see that our code got to that point at runtime. At the end of `main`, our +instance of `CustomSmartPointer` will go out of scope. Note that we didn't call +the `drop` method explicitly. + +When we run this program, we'll see: + +``` +CustomSmartPointer created. +Wait for it... +Dropping CustomSmartPointer! +``` + +printed to the screen, which shows that Rust automatically called `drop` for us +when our instance went out of scope. + +We can use the `std::mem::drop` function to drop a value earlier than when it +goes out of scope. This isn't usually necessary; the whole point of the `Drop` +trait is that it's taken care of automatically for us. We'll see an example of +a case when we'll need to drop a value earlier than when it goes out of scope +in Chapter 16 when we're talking about concurrency. For now, let's just see +that it's possible, and `std::mem::drop` is in the prelude so we can just call +`drop` as shown in Listing 15-9: + +Filename: src/main.rs + +``` +fn main() { + let c = CustomSmartPointer { data: String::from("some data") }; + println!("CustomSmartPointer created."); + drop(c); + println!("Wait for it..."); +} +``` + +Listing 15-9: Calling `std::mem::drop` to explicitly drop a value before it +goes out of scope + +Running this code will print the following, showing that the destructor code is +called since `Dropping CustomSmartPointer!` is printed between +`CustomSmartPointer created.` and `Wait for it...`: + +``` +CustomSmartPointer created. +Dropping CustomSmartPointer! +Wait for it... +``` + +Note that we aren't allowed to call the `drop` method that we defined directly: +if we replaced `drop(c)` in Listing 15-9 with `c.drop()`, we'll get a compiler +error that says `explicit destructor calls not allowed`. We're not allowed to +call `Drop::drop` directly because when Rust inserts its call to `Drop::drop` +automatically when the value goes out of scope, then the value would get +dropped twice. Dropping a value twice could cause an error or corrupt memory, +so Rust doesn't let us. Instead, we can use `std::mem::drop`, whose definition +is: + +``` +pub mod std { + pub mod mem { + pub fn drop(x: T) { } + } +} +``` + +This function is generic over any type `T`, so we can pass any value to it. The +function doesn't actually have anything in its body, so it doesn't use its +parameter. The reason this empty function is useful is that `drop` takes +ownership of its parameter, which means the value in `x` gets dropped at the +end of this function when `x` goes out of scope. + +Code specified in a `Drop` trait implementation can be used for many reasons to +make cleanup convenient and safe: we could use it to create our own memory +allocator, for instance! By using the `Drop` trait and Rust's ownership system, +we don't have to remember to clean up after ourselves since Rust takes care of +it automatically. We'll get compiler errors if we write code that would clean +up a value that's still in use, since the ownership system that makes sure +references are always valid will also make sure that `drop` only gets called +one time 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 +library that add different kinds of useful functionality. + +## `Rc`, the Reference Counted Smart Pointer + +In the majority of cases, ownership is very clear: you know exactly which +variable owns a given value. However, this isn't always the case; sometimes, +you may actually need multiple owners. For this, 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, we know we can clean up the value without any references becoming +invalid. + +To think about this in terms of a real-world scenario, it's like a TV in a +family room. When one person comes in the room to watch TV, they turn it on. +Others can also come in the room and watch the TV. When the last person leaves +the room, they'll turn the TV off since it's no longer being used. If someone +turns off the TV while others are still watching it, though, the people +watching the TV would get mad! + +`Rc` is for use 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 +of our program using this data will finish using it last. If we knew which part +would finish last, we could make that part the owner of the data and the normal +ownership rules enforced at compile time would kick in. + +Note that `Rc` is only for use in single-threaded scenarios; the next +chapter on concurrency will cover how to do reference counting in +multithreaded programs. If you try to use `Rc` with multiple threads, +you'll get a compile-time error. + +### Using `Rc` to Share Data + +Let's return to our cons list example from Listing 15-5. In Listing 15-11, we're +going to try to use `List` as we defined it using `Box`. First we'll create +one list instance that contains 5 and then 10. Next, we want to create two more +lists: one that starts with 3 and continues on to our first list containing 5 +and 10, then another list that starts with 4 and *also* continues on to our +first list containing 5 and 10. In other words, we want two lists that both +share ownership of the third list, which conceptually will be something like +Figure 15-10: + +Two lists that share ownership of a third list + +Figure 15-10: Two lists, `b` and `c`, sharing ownership of a third list, `a` + +Trying to implement this using our definition of `List` with `Box` won't +work, as shown in Listing 15-11: + +Filename: src/main.rs + +``` +enum List { + Cons(i32, Box), + Nil, +} + +use List::{Cons, Nil}; + +fn main() { + let a = Cons(5, + Box::new(Cons(10, + Box::new(Nil)))); + let b = Cons(3, Box::new(a)); + let c = Cons(4, Box::new(a)); +} +``` + +Listing 15-11: Having two lists using `Box` that try to share ownership of a +third list won't work + +If we compile this, we get this error: + +``` +error[E0382]: use of moved value: `a` + --> src/main.rs:13:30 + | +12 | let b = Cons(3, Box::new(a)); + | - value moved here +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 +``` + +The `Cons` variants own the data they hold, so when we create the `b` list it +moves `a` to be owned by `b`. Then when we try to use `a` again when creating +`c`, we're not allowed to since `a` has been moved. + +We could change the definition of `Cons` to hold references instead, but then +we'd have to specify lifetime parameters and we'd have to construct elements of +a list such that every element lives at least as long as the list itself. +Otherwise, the borrow checker won't even let us compile the code. + +Instead, we can change our definition of `List` to use `Rc` instead of +`Box` as shown here in Listing 15-12: + +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))))); + let b = Cons(3, a.clone()); + let c = Cons(4, a.clone()); +} +``` + +Listing 15-12: A definition of `List` that uses `Rc` + +Note that we need to add a `use` statement for `Rc` 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 `clone` method on `a`. + +### Cloning an `Rc` Increases the Reference Count + +We've seen the `clone` method previously, where we used it for making a +complete copy of some data. With `Rc`, though, it doesn't make a full copy. +`Rc` holds a *reference count*, that is, a count of how many clones exist. +Let's change `main` as shown in Listing 15-13 to have an inner scope around +where we create `c`, and to print out the results of the `Rc::strong_count` +associated function at various points. `Rc::strong_count` returns the reference +count of the `Rc` value we pass to it, and we'll talk about why this function +is named `strong_count` in the section later in this chapter about preventing +reference cycles. + +Filename: src/main.rs + +``` +fn main() { + let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil))))); + println!("rc = {}", Rc::strong_count(&a)); + let b = Cons(3, a.clone()); + println!("rc after creating b = {}", Rc::strong_count(&a)); + { + let c = Cons(4, a.clone()); + println!("rc after creating c = {}", Rc::strong_count(&a)); + } + println!("rc after c goes out of scope = {}", Rc::strong_count(&a)); +} +``` + +Listing 15-13: Printing out the reference count + +This will print out: + +``` +rc = 1 +rc after creating b = 2 +rc after creating c = 3 +rc after c goes out of scope = 2 +``` + +We're able to see that `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 is decreased by one, which happens in the implementation of the `Drop` +trait for `Rc`. 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 of references to the list +containing 5 and 10 is then 0, and the list is dropped. This strategy lets us +have multiple owners, as the count will ensure that the value remains valid as +long as any of the owners still exist. + +In the beginning of this section, we said that `Rc` only allows you to share +data for multiple parts of your program to read through immutable references to +the `T` value the `Rc` contains. If `Rc` let us have a mutable reference, +we'd run into the problem that the borrowing rules disallow that we discussed +in Chapter 4: two mutable borrows to the same place can cause data races and +inconsistencies. But mutating 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. + +## `RefCell` and the Interior Mutability Pattern + +*Interior mutability* is a design pattern in Rust for allowing you to mutate +data even though there are immutable references to that data, which would +normally be disallowed by the borrowing rules. The interior mutability pattern +involves using `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. The interior mutability pattern is used when you 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 +interior mutability pattern. + +### `RefCell` has Interior Mutability + +Unlike `Rc`, the `RefCell` type represents single ownership over the data +that it holds. So, what makes `RefCell` different than a type like `Box`? +Let's recall the borrowing rules we 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. + +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!`. + +Static analysis, like the Rust compiler performs, is inherently conservative. +There are properties of code that are impossible to detect by analyzing the +code: the most famous is the Halting Problem, which is out of scope of this +book but an interesting topic to research if you're interested. + +Because some analysis is impossible, the Rust compiler does not try to even +guess if it can't be sure, so it's conservative and sometimes rejects correct +programs that would not actually violate Rust's guarantees. Put another way, if +Rust accepts an incorrect program, people would not be able to trust in the +guarantees Rust makes. If Rust rejects a correct program, the programmer will +be inconvenienced, but nothing catastrophic can occur. `RefCell` is useful +when you know that the borrowing rules are respected, but the compiler can't +understand that that's true. + +Similarly to `Rc`, `RefCell` is only for use in single-threaded +scenarios. We'll talk about how to get the functionality of `RefCell` in a +multithreaded program in the next chapter on concurrency. For now, all you +need to know is that if you try to use `RefCell` in a multithreaded +context, you'll get a compile time error. + +With references, we use the `&` and `&mut` syntax to create references and +mutable references, respectively. But with `RefCell`, we use the `borrow` +and `borrow_mut` methods, which are part of the safe API that `RefCell` has. +`borrow` returns the smart pointer type `Ref`, and `borrow_mut` returns the +smart pointer type `RefMut`. These two types implement `Deref` so that we can +treat them as if they're regular references. `Ref` and `RefMut` track the +borrows dynamically, and their implementation of `Drop` releases the borrow +dynamically. + +Listing 15-14 shows what it looks like to use `RefCell` with functions that +borrow their parameters immutably and mutably. Note that the `data` variable is +declared as immutable with `let data` rather than `let mut data`, yet +`a_fn_that_mutably_borrows` is allowed to borrow the data mutably and make +changes to the data! + +Filename: src/main.rs + +``` +use std::cell::RefCell; + +fn a_fn_that_immutably_borrows(a: &i32) { + println!("a is {}", a); +} + +fn a_fn_that_mutably_borrows(b: &mut i32) { + *b += 1; +} + +fn demo(r: &RefCell) { + a_fn_that_immutably_borrows(&r.borrow()); + a_fn_that_mutably_borrows(&mut r.borrow_mut()); + a_fn_that_immutably_borrows(&r.borrow()); +} + +fn main() { + let data = RefCell::new(5); + demo(&data); +} +``` + +Listing 15-14: Using `RefCell`, `borrow`, and `borrow_mut` + +This example prints: + +``` +a is 5 +a is 6 +``` + +In `main`, we've created a new `RefCell` containing the value 5, and stored +in the variable `data`, declared without the `mut` keyword. We then call the +`demo` function with an immutable reference to `data`: as far as `main` is +concerned, `data` is immutable! + +In the `demo` function, we get an immutable reference to the value inside the +`RefCell` by calling the `borrow` method, and we call +`a_fn_that_immutably_borrows` with that immutable reference. More +interestingly, we can get a *mutable* reference to the value inside the +`RefCell` with the `borrow_mut` method, and the function +`a_fn_that_mutably_borrows` is allowed to change the value. We can see that the +next time we call `a_fn_that_immutably_borrows` that prints out the value, it's +6 instead of 5. + +### Borrowing Rules are Checked at Runtime on `RefCell` + +Recall from Chapter 4 that because of the borrowing rules, this code using +regular references that tries to create two mutable borrows in the same scope +won't compile: + +``` +let mut s = String::from("hello"); + +let r1 = &mut s; +let r2 = &mut s; +``` + +We'll get this compiler error: + +``` +error[E0499]: cannot borrow `s` as mutable more than once at a time + --> + | +5 | let r1 = &mut s; + | - first mutable borrow occurs here +6 | let r2 = &mut s; + | ^ second mutable borrow occurs here +7 | } + | - first borrow ends here +``` + +In contrast, using `RefCell` and calling `borrow_mut` twice in the same +scope *will* compile, but it'll panic at runtime instead. This code: + +``` +use std::cell::RefCell; + +fn main() { + let s = RefCell::new(String::from("hello")); + + let r1 = s.borrow_mut(); + let r2 = s.borrow_mut(); +} +``` + +compiles but panics with the following error when we `cargo run`: + +``` + Finished dev [unoptimized + debuginfo] target(s) in 0.83 secs + Running `target/debug/refcell` +thread 'main' panicked at 'already borrowed: BorrowMutError', +/stable-dist-rustc/build/src/libcore/result.rs:868 +note: Run with `RUST_BACKTRACE=1` for a backtrace. +``` + +This runtime `BorrowMutError` is similar to the compiler error: it says we've +already borrowed `s` mutably once, so we're not allowed to borrow it again. We +aren't getting around the borrowing rules, we're just choosing to have Rust +enforce them at runtime instead of compile time. You could choose to use +`RefCell` everywhere all the time, but in addition to having to type +`RefCell` a lot, you'd find out about possible problems later (possibly in +production rather than during development). Also, checking the borrowing rules +while your program is running has a performance penalty. + +### Multiple Owners of Mutable Data by Combining `Rc` and `RefCell` + +So why would we choose to make the tradeoffs that using `RefCell` involves? +Well, remember when we said that `Rc` only lets you have an immutable +reference to `T`? Given that `RefCell` is immutable, but has interior +mutability, we can combine `Rc` and `RefCell` to get a type that's both +reference counted and mutable. Listing 15-15 shows an example of how to do +that, again going back to our cons list from Listing 15-5. In this example, +instead of storing `i32` values in the cons list, we'll be storing +`Rc>` values. We want to store that type so that we can have an +owner of the value that's not part of the list (the multiple owners +functionality that `Rc` provides), and so we can mutate the inner `i32` +value (the interior mutability functionality that `RefCell` provides): + +Filename: src/main.rs + +``` +#[derive(Debug)] +enum List { + Cons(Rc>, Rc), + Nil, +} + +use List::{Cons, Nil}; +use std::rc::Rc; +use std::cell::RefCell; + +fn main() { + let value = Rc::new(RefCell::new(5)); + + let a = Cons(value.clone(), Rc::new(Nil)); + let shared_list = Rc::new(a); + + let b = Cons(Rc::new(RefCell::new(6)), shared_list.clone()); + let c = Cons(Rc::new(RefCell::new(10)), shared_list.clone()); + + *value.borrow_mut() += 10; + + println!("shared_list after = {:?}", shared_list); + println!("b after = {:?}", b); + println!("c after = {:?}", c); +} +``` + +Listing 15-15: Using `Rc>` to create a `List` that we can mutate + +We're creating a value, which is an instance of `Rc>. We're +storing it in a variable named `value` because we want to be able to access it +directly later. Then we create a `List` in `a` that has a `Cons` variant that +holds `value`, and `value` needs to be cloned since we want `value` to also +have ownership in addition to `a`. Then we wrap `a` in an `Rc` so that we +can create lists `b` and `c` that start differently but both refer to `a`, +similarly to what we did in Listing 15-12. + +Once we have the lists in `shared_list`, `b`, and `c` created, then we add 10 +to the 5 in `value` by dereferencing the `Rc` and calling `borrow_mut` on +the `RefCell`. + +When we print out `shared_list`, `b`, and `c`, we can see that they all have +the modified value of 15: + +``` +shared_list after = Cons(RefCell { value: 15 }, Nil) +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 can have an outwardly immutable +`List`, but we can use the methods on `RefCell` that provide access to its +interior mutability to be able to modify our data when we need to. The runtime +checks of the borrowing rules that `RefCell` does protect us from data +races, and we've decided that we want to trade a bit of speed for the +flexibility in our data structures. + +`RefCell` is not the only standard library type that provides interior +mutability. `Cell` is similar but instead of giving references to the inner +value like `RefCell` does, the value is copied in and out of the `Cell`. +`Mutex` offers interior mutability that is 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. + +## Creating Reference Cycles and Leaking Memory is Safe + +Rust makes a number of guarantees that we've talked about, for example that +we'll never have a null value, and data races will be disallowed at compile +time. Rust's memory safety guarantees make it more difficult to create memory +that never gets cleaned up, which is known as a *memory leak*. Rust does not +make memory leaks *impossible*, however, preventing memory leaks is *not* one +of Rust's guarantees. In other words, memory leaks are memory safe. + +By using `Rc` and `RefCell`, it is possible to create cycles of +references where items refer to each other in a cycle. This is bad because the +reference count of each item in the cycle will never reach 0, and the values +will never be dropped. Let's take a look at how that might happen and how to +prevent it. + +In Listing 15-16, we're going to use another variation of the `List` definition +from Listing 15-5. We're going back to storing an `i32` value as the first +element in the `Cons` variant. The second element in the `Cons` variant is now +`RefCell>`: instead of being able to modify the `i32` value this time, +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: + +Filename: src/main.rs + +``` +#[derive(Debug)] +enum List { + Cons(i32, RefCell>), + Nil, +} + +impl List { + fn tail(&self) -> Option<&RefCell>> { + match *self { + Cons(_, ref item) => Some(item), + Nil => None, + } + } +} +``` + +Listing 15-16: A cons list definition that holds a `RefCell` so that we can +modify what a `Cons` variant is referring to + +Next, in Listing 15-17, we're going to create a `List` value in the variable +`a` that initially is a list of `5, Nil`. Then we'll create a `List` value in +the variable `b` that is a list of the value 10 and then points to the list in +`a`. Finally, we'll modify `a` so that it points to `b` instead of `Nil`, which +will then create a cycle: + +Filename: src/main.rs + +``` +use List::{Cons, Nil}; +use std::rc::Rc; +use std::cell::RefCell; + +fn main() { + + let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil)))); + + println!("a initial rc count = {}", Rc::strong_count(&a)); + println!("a next item = {:?}", a.tail()); + + let b = Rc::new(Cons(10, RefCell::new(a.clone()))); + + println!("a rc count after b creation = {}", Rc::strong_count(&a)); + println!("b initial rc count = {}", Rc::strong_count(&b)); + println!("b next item = {:?}", b.tail()); + + if let Some(ref link) = a.tail() { + *link.borrow_mut() = b.clone(); + } + + println!("b rc count after changing a = {}", Rc::strong_count(&b)); + println!("a rc count after changing a = {}", Rc::strong_count(&a)); + + // Uncomment the next line to see that we have a cycle; it will + // overflow the stack + // println!("a next item = {:?}", a.tail()); +} +``` + +Listing 15-17: Creating a reference cycle of two `List` values pointing to +each other + +We use 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've created a reference cycle that looks like Figure 15-18: + +Reference cycle of lists + +Figure 15-18: A reference cycle of lists `a` and `b` pointing to each other + +If you uncomment the last `println!`, Rust will try and print this cycle out +with `a` pointing to `b` pointing to `a` and so forth until it overflows the +stack. + +Looking at the results of the `println!` calls before the last one, we'll see +that the reference count of both `a` and `b` are 2 after we change `a` to point +to `b`. At the end of `main`, Rust will try and drop `b` first, which will +decrease the count of the `Rc` by one. However, because `a` is still +referencing that `Rc`, its count is 1 rather than 0, so the memory the `Rc` has +on the heap won't be dropped. It'll just sit there with a count of one, +forever. In this specific case, the program ends right away, so it's not a +problem, but in a more complex program that allocates lots of memory in a cycle +and holds onto it for a long time, this would be a problem. The program would +be using more memory than it needs to be, and might overwhelm the system and +cause it to run out of memory available to use. + +Now, as you can see, creating reference cycles is difficult and inconvenient in +Rust. But it's not impossible: preventing memory leaks in the form of reference +cycles is not one of the guarantees Rust makes. 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'll have to ensure +that you don't create cycles. In the example in Listing 15-14, the solution +would probably be to not write code that could create cycles like this, since +we do want `Cons` variants to own the list they point to. + +With data structures like graphs, it's sometimes necessary to have references +that create cycles in order to have parent nodes point to their children and +children nodes point back in the opposite direction to their parents, for +example. If one of the directions is expressing ownership and the other isn't, +one way of being able to model the relationship of the data without creating +reference cycles and memory leaks is using `Weak`. Let's explore that next! + +### Prevent Reference Cycles: Turn an `Rc` into a `Weak` + +The Rust standard library provides `Weak`, a smart pointer type for use in +situations that have cycles of references but only one direction expresses +ownership. We've been showing how cloning an `Rc` increases the +`strong_count` of references; `Weak` is a way to reference an `Rc` that +does not increment the `strong_count`: instead it increments the `weak_count` +of references to an `Rc`. When an `Rc` goes out of scope, the inner value will +get dropped if the `strong_count` is 0, even if the `weak_count` is not 0. To +be able to get the value from a `Weak`, we first have to upgrade it to an +`Option>` by using the `upgrade` method. The result of upgrading a +`Weak` will be `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 +know Rust will make sure we handle both the `Some` case and the `None` case and +we won't be trying to use an invalid pointer. + +Instead of the list in Listing 15-17 where each item knows only about the +next item, let's say we want a tree where the items know about their children +items *and* their parent items. + +Let's start just with a struct named `Node` that holds its own `i32` value as +well as references to its children `Node` values: + +Filename: src/main.rs + +``` +use std::rc::Rc; +use std::cell::RefCell; + +#[derive(Debug)] +struct Node { + value: i32, + children: RefCell>>, +} +``` + +We want to be able to have a `Node` own its children, and we also want to be +able to have variables own each node so we can access them directly. That's why +the items in the `Vec` are `Rc` values. We want to be able to modify what +nodes are another node's children, so that's why we have a `RefCell` in +`children` around the `Vec`. In Listing 15-19, let's create one instance of +`Node` 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: + +Filename: src/main.rs + +``` +fn main() { + let leaf = Rc::new(Node { + value: 3, + children: RefCell::new(vec![]), + }); + + let branch = Rc::new(Node { + value: 5, + children: RefCell::new(vec![leaf.clone()]), + }); +} +``` + +Listing 15-19: Creating a `leaf` node and a `branch` node where `branch` has +`leaf` as one of its children but `leaf` has no reference to `branch` + +The `Node` in `leaf` now has two owners: `leaf` and `branch`, since we clone +the `Rc` in `leaf` and store that in `branch`. The `Node` in `branch` knows +it's related to `leaf` since `branch` has a reference to `leaf` in +`branch.children`. However, `leaf` doesn't know that it's related to `branch`, +and we'd like `leaf` to know that `branch` is its parent. + +To do that, we're going to add a `parent` field to our `Node` struct +definition, but what should the type of `parent` be? We know it can't contain +an `Rc`, since `leaf.parent` would point to `branch` and `branch.children` +contains a pointer to `leaf`, which makes a reference cycle. Neither `leaf` nor +`branch` would get dropped since they would always refer to each other and +their reference counts would never be zero. + +So instead of `Rc`, we're going to make the type of `parent` use `Weak`, +specifically a `RefCell>`: + +Filename: src/main.rs + +``` +use std::rc::{Rc, Weak}; +use std::cell::RefCell; + +#[derive(Debug)] +struct Node { + value: i32, + parent: RefCell>, + children: RefCell>>, +} +``` + +This way, a node will be able to refer to its parent node if it has one, +but it does not own its parent. A parent node will be dropped even if +it has child nodes referring to it, as long as it doesn't have a parent +node as well. Now let's update `main` to look like Listing 15-20: + +Filename: src/main.rs + +``` +fn main() { + let leaf = Rc::new(Node { + value: 3, + parent: RefCell::new(Weak::new()), + children: RefCell::new(vec![]), + }); + + println!("leaf parent = {:?}", leaf.parent.borrow().upgrade()); + + let branch = Rc::new(Node { + value: 5, + parent: RefCell::new(Weak::new()), + children: RefCell::new(vec![leaf.clone()]), + }); + + *leaf.parent.borrow_mut() = Rc::downgrade(&branch); + + println!("leaf parent = {:?}", leaf.parent.borrow().upgrade()); +} +``` + +Listing 15-20: A `leaf` node and a `branch` node where `leaf` has a `Weak` +reference to its parent, `branch` + +Creating the `leaf` node looks similar; since it starts out without a parent, +we create a new `Weak` reference instance. When we try to get a reference to +the parent of `leaf` by using the `upgrade` method, we'll get a `None` value, +as shown by the first `println!` that outputs: + +``` +leaf parent = None +``` + +Similarly, `branch` will also have a new `Weak` reference, since `branch` does +not have a parent node. We still make `leaf` be one of the children of +`branch`. Once we have a new `Node` instance in `branch`, we can modify `leaf` +to have a `Weak` reference to `branch` for 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`. Also notice we don't get a cycle printed out that +eventually ends in a stack overflow like we did in Listing 15-14: the `Weak` +references are just printed as `(Weak)`: + +``` +leaf parent = Some(Node { value: 5, parent: RefCell { value: (Weak) }, +children: RefCell { value: [Node { value: 3, parent: RefCell { value: (Weak) }, +children: RefCell { value: [] } }] } }) +``` + +The fact that we don't get infinite output (or at least until the stack +overflows) is one way we can see that we don't have a reference cycle in this +case. Another way we can tell is by looking at the values we get from calling +`Rc::strong_count` and `Rc::weak_count`. In Listing 15-21, let's create a new +inner scope and move the creation of `branch` in there, so that we can see what +happens when `branch` is created and then dropped when it goes out of scope: + +Filename: src/main.rs + +``` +fn main() { + let leaf = Rc::new(Node { + value: 3, + parent: RefCell::new(Weak::new()), + children: RefCell::new(vec![]), + }); + + println!( + "leaf strong = {}, weak = {}", + Rc::strong_count(&leaf), + Rc::weak_count(&leaf), + ); + + { + let branch = Rc::new(Node { + value: 5, + parent: RefCell::new(Weak::new()), + children: RefCell::new(vec![leaf.clone()]), + }); + *leaf.parent.borrow_mut() = Rc::downgrade(&branch); + + println!( + "branch strong = {}, weak = {}", + Rc::strong_count(&branch), + Rc::weak_count(&branch), + ); + + println!( + "leaf strong = {}, weak = {}", + Rc::strong_count(&leaf), + Rc::weak_count(&leaf), + ); + } + + println!("leaf parent = {:?}", leaf.parent.borrow().upgrade()); + println!( + "leaf strong = {}, weak = {}", + Rc::strong_count(&leaf), + Rc::weak_count(&leaf), + ); +} +``` + +Listing 15-21: Creating `branch` in an inner scope and examining strong and +weak reference counts of `leaf` and `branch` + +Right after creating `leaf`, its strong count is 1 (for `leaf` itself) and its +weak count is 0. In the inner scope, after we create `branch` and associate +`leaf` and `branch`, `branch` will have a strong count of 1 (for `branch` +itself) and a weak count of 1 (for `leaf.parent` pointing to `branch` with a +`Weak`). `leaf` will have a strong count of 2, since `branch` now has a +clone the `Rc` of `leaf` stored in `branch.children`. `leaf` still has a weak +count of 0. + +When the inner scope ends, `branch` goes out of scope, and its strong count +decreases to 0, so its `Node` gets dropped. The weak count of 1 from +`leaf.parent` has no bearing on whether `Node` gets dropped or not, so we don't +have a memory leak! + +If we try to access the parent of `leaf` after the end of the scope, we'll get +`None` again like we did before `leaf` had a parent. At the end of the program, +`leaf` has a strong count of 1 and a weak count of 0, since `leaf` is now the +only thing pointing to it again. + +All of the logic managing the counts and whether a value should be dropped or +not was managed by `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 + +We've now covered how you can use different kinds of smart pointers to choose +different guarantees and tradeoffs than those Rust makes 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 where we need an immutable type, and enforces the +borrowing rules at runtime instead of at compile time. + +We've also discussed the `Deref` and `Drop` traits that enable a lot of smart +pointers' functionality. We explored how it's possible to create a reference +cycle that would cause a memory leak, and how to prevent reference cycles by +using `Weak`. + +If this chapter has piqued your interest and you now want to implement your own +smart pointers, check out The Nomicon at +*https://doc.rust-lang.org/stable/nomicon/vec.html* for even more useful +information. + +Next, let's talk about concurrency in Rust. We'll even learn about a few new +smart pointers that can help us with it. diff --git a/src/doc/book/second-edition/nostarch/chapter16.md b/src/doc/book/second-edition/nostarch/chapter16.md new file mode 100644 index 0000000000..e79e7f651b --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter16.md @@ -0,0 +1,1253 @@ + +[TOC] + +# Fearless Concurrency + +Ensuring memory safety isn't Rust's only goal: being a language that is better +equipped to handle concurrent and parallel programming has always been another +major goal of Rust. *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 more important +as more computers have multiple processors for our programs to take advantage +of. Historically, programming in these contexts has been difficult and error +prone: Rust hopes to change that. + +Originally, we thought that memory safety and preventing concurrency problems +were two separate challenges to be solved with different methods. However, over +time, we discovered that ownership and the type system are a powerful set of +tools that 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. We've nicknamed this aspect +of Rust *fearless concurrency*. Fearless concurrency means Rust not only allows +you to have confidence that your code is free of subtle bugs, but also lets you +refactor this kind of code easily without worrying about introducing new bugs. + +> Note: given that Rust's slogan is *fearless concurrency*, 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 strongly opinionated about the solutions they offer you to +deal with concurrent problems. That's a very reasonable strategy, especially +for higher-level languages, but lower-level languages don't have that luxury. +Lower-level languages are expected to enable whichever solution would provide +the best performance in a given situation, and they have fewer abstractions +over the hardware. Rust, therefore, gives us a variety of tools for modeling +our problems in whatever way is appropriate for our situation and requirements. + +Here's what 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. +* *Shared state* concurrency, where multiple threads have access to some piece + of data. +* The `Sync` and `Send` traits, which allow Rust's concurrency guarantees to be + extended to user-defined types as well as types provided by the standard + library. + +## Using Threads to Run Code Simultaneously + +In most operating systems in use today, when your program executes, the context +in which the operating system runs your code is called a *process*. The +operating system runs many processes, and the operating system managing these +processes is what lets multiple programs execute at the same time on your +computer. + +We can take the idea of processes each running a program down one level of +abstraction: your program can also have independent parts that run +simultaneously within the context of your program. The feature that enables +this functionality is called *threads*. + +Splitting up the computation your program needs to do into multiple threads can +improve performance, since the program will be doing multiple things at the +same time. Programming with threads can add complexity, however. Since threads +run simultaneously, there's no inherent guarantee about the order in which the +parts of your code on different threads will run. This can lead to race +conditions where threads are accessing data or resources in an inconsistent +order, deadlocks where two threads both prevent each other from continuing, or +bugs that only happen in certain situations that are hard to reproduce +reliably. Rust lessens the effect of these and other downsides of using +threads, but programming in a multithreaded context still takes thought and +code structured differently than for programs only expected to run in a single +thread. + +There are a few different ways that programming languages implement threads. +Many operating systems provide an API for creating new threads. In addition, +many programming languages provide their own special implementation of threads. +Programming language provided threads are sometimes called *lightweight* or +*green* threads. These languages take a number of green threads and execute +them in the context of a different number of operating system threads. For this +reason, the model where a language calls the operating system APIs to create +threads is sometimes called *1:1*, one OS thread per one language thread. 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. + +Each model has its own advantages and tradeoffs. The tradeoff that's most +important to Rust is runtime support. *Runtime* is a confusing term; it can +have different meaning in different contexts. Here, we mean some code included +by the language in every binary. For some languages, this code is large, and +for others, this code is small. Colloquially, "no runtime" is often what people +will say when they mean "small runtime", since every non-assembly language has +some amount of runtime. Smaller runtimes have fewer features but have the +advantage of resulting in smaller binaries. Smaller binaries make it easier to +combine the language with other languages in more contexts. While many +languages are okay with increasing the runtime 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. + +The green threading model is a feature that requires a larger language runtime +in order to manage the threads. As such, the Rust standard library only +provides an implementation of 1:1 threading. Because Rust is such a low-level +language, there are crates that implement M:N threading if you would rather +trade overhead for aspects such as more control over which threads run when and +lower costs of context switching, for example. + +Now that we've defined what threads are in Rust, let's explore how to use the +thread-related API that the standard library provides for us. + +### Creating a New Thread with `spawn` + +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 +new thread and other text from the main thread: + +Filename: src/main.rs + +``` +use std::thread; + +fn main() { + thread::spawn(|| { + for i in 1..10 { + println!("hi number {} from the spawned thread!", i); + } + }); + + for i in 1..5 { + println!("hi number {} from the main thread!", i); + } +} +``` + +Listing 16-1: Creating a new thread to print one thing while the main thread is +printing something else + +Note that the way this function is written, when the main thread ends, it will +stop the new thread too. The output from this program might be a little +different every time, but it will look similar to this: + +``` +hi number 1 from the main thread! +hi number 1 from the spawned thread! +hi number 2 from the main thread! +hi number 2 from the spawned thread! +hi number 3 from the main thread! +hi number 3 from the spawned thread! +hi number 4 from the main thread! +hi number 4 from the spawned thread! +hi number 5 from the spawned thread! +``` + +The threads will probably take turns, but that's not guaranteed. In this run, +the main thread printed first, even though the print statement from the spawned +thread appears first in the code we wrote. 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 always only see one thread, or if you 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 + +Not only does the code in Listing 16-1 not allow the spawned thread to finish +most of the time since the main thread ends before the spawned thread is done, +there's actualy no guarantee that the spawned thread will get to run at all! We +can fix this by saving the return value of `thread::spawn`, which is a +`JoinHandle`. That looks like Listing 16-2: + +Filename: src/main.rs + +``` +use std::thread; + +fn main() { + let handle = thread::spawn(|| { + for i in 1..10 { + println!("hi number {} from the spawned thread!", i); + } + }); + + for i in 1..5 { + println!("hi number {} from the main thread!", i); + } + + handle.join(); +} +``` + +Listing 16-2: Saving a `JoinHandle` from `thread::spawn` to guarantee the +thread is run to completion + +A `JoinHandle` is an owned value that can wait for a thread to finish, which is +what the `join` method does. By calling `join` on the handle, the current +thread will block until the thread that the handle represents terminates. Since +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: + +``` +hi number 1 from the main thread! +hi number 2 from the main thread! +hi number 1 from the spawned thread! +hi number 3 from the main thread! +hi number 2 from the spawned thread! +hi number 4 from the main thread! +hi number 3 from the spawned thread! +hi number 4 from the spawned thread! +hi number 5 from the spawned thread! +hi number 6 from the spawned thread! +hi number 7 from the spawned thread! +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 +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: + +Filename: src/main.rs + +``` +use std::thread; + +fn main() { + let handle = thread::spawn(|| { + for i in 1..10 { + println!("hi number {} from the spawned thread!", i); + } + }); + + handle.join(); + + for i in 1..5 { + println!("hi number {} from the main thread!", i); + } +} +``` + +The main thread will wait for the spawned thread to finish before the main +thread starts running its `for` loop, so the output won't be interleaved +anymore: + +``` +hi number 1 from the spawned thread! +hi number 2 from the spawned thread! +hi number 3 from the spawned thread! +hi number 4 from the spawned thread! +hi number 5 from the spawned thread! +hi number 6 from the spawned thread! +hi number 7 from the spawned thread! +hi number 8 from the spawned thread! +hi number 9 from the spawned thread! +hi number 1 from the main thread! +hi number 2 from the main thread! +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. + +### Using `move` Closures with Threads + +There's a feature of closures that we didn't cover in Chapter 13 that's often +useful with `thread::spawn`: `move` closures. We said this in Chapter 13: + +> Creating closures that capture values from their environment is mostly used +> in the context of starting new threads. + +Now we're creating new threads, so let's talk about capturing values in +closures! + +Notice the closure that we pass to `thread::spawn` in Listing 16-1 takes no +arguments: we're not using any data from the main thread in the spawned +thread's code. In order to use data in the spawned thread that comes from the +main thread, we need the spawned thread's closure to 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, which won't work the way this example is written: + +Filename: src/main.rs + +``` +use std::thread; + +fn main() { + let v = vec![1, 2, 3]; + + let handle = thread::spawn(|| { + println!("Here's a vector: {:?}", v); + }); + + handle.join(); +} +``` + +Listing 16-3: Attempting to use a vector created by the main thread from +another thread + +The closure uses `v`, so the closure will capture `v` and make `v` part of the +closure's environment. Because `thread::spawn` runs this closure in a new +thread, we can access `v` inside that new thread. + +When we compile this example, however, we'll get the following error: + +``` +error[E0373]: closure may outlive the current function, but it borrows `v`, +which is owned by the current function + --> + | +6 | let handle = thread::spawn(|| { + | ^^ may outlive borrowed value `v` +7 | println!("Here's a vector: {:?}", v); + | - `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 || { +``` + +When we capture something in a closure's environment, Rust will try to infer +how to capture it. `println!` only needs a reference to `v`, so the closure +tries to borrow `v`. There's a problem, though: we don't know how long the +spawned thread will run, so we don't know if the reference to `v` will always +be valid. + +Consider the code in Listing 16-4 that shows a scenario where it's more likely +that the reference to `v` won't be valid: + +Filename: src/main.rs + +``` +use std::thread; + +fn main() { + let v = vec![1, 2, 3]; + + let handle = thread::spawn(|| { + println!("Here's a vector: {:?}", v); + }); + + drop(v); // oh no! + + handle.join(); +} +``` + +Listing 16-4: A thread with a closure that attempts to capture a reference to +`v` from a main thread that drops `v` + +This code could be run, and the spawned thread could immediately get 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 is still running: it immediately +drops `v`, using the `drop` function that we discussed in Chapter 15 that +explicitly drops its argument. Then, the spawned thread starts to execute. `v` +is now invalid, so a reference to it is also invalid. Oh no! + +To fix this problem, we can listen to the advice of the error message: + +``` +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 || { +``` + +By adding the `move` keyword before the closure, we force the closure to take +ownership of the values it's using, rather than inferring borrowing. This +modification to the code from Listing 16-3 shown in Listing 16-5 will compile +and run as we intend: + +Filename: src/main.rs + +``` +use std::thread; + +fn main() { + let v = vec![1, 2, 3]; + + let handle = thread::spawn(move || { + println!("Here's a vector: {:?}", v); + }); + + handle.join(); +} +``` + +Listing 16-5: Using the `move` keyword to force a closure to take ownership of +the values it uses + +What about the code in Listing 16-4 where the main thread called `drop`? If we +add `move` to the closure, we've moved `v` into the closure's environment, and +we can no longer call `drop` on it. We get this compiler error instead: + +``` +error[E0382]: use of moved value: `v` + --> + | +6 | let handle = thread::spawn(move || { + | ------- value moved (into closure) here +... +10 | drop(v); // oh no! + | ^ value used here after move + | + = note: move occurs because `v` has type `std::vec::Vec`, which does + not implement the `Copy` trait +``` + +Rust's ownership rules have saved us again! + +Now that we have a basic understanding of threads and the thread API, let's +talk about what we can actually *do* with threads. + +## Message Passing to Transfer Data Between Threads + +One approach to concurrency that's seen a rise in popularity as of late is +*message passing*, where threads or actors communicate by sending each other +messages containing data. Here's the idea in slogan form: + +> Do not communicate by sharing memory; instead, share memory by +> communicating. +> +> --Effective Go at *http://golang.org/doc/effective_go.html* + +A major tool to accomplish this goal is the *channel*. A channel has two +halves, a transmitter and a receiver. One part of our code can call methods on +the transmitter with the data we want to send, and another part can check the +receiving end for arriving messages. + +We're going to work up to an example where we have one thread that will +generate values and send them down a channel. The main thread will receive the +values and print them out. + +First, though, let's start by creating a channel but not doing anything with it +in Listing 16-6: + +Filename: src/main.rs + +``` +use std::sync::mpsc; + +fn main() { + let (tx, rx) = mpsc::channel(); +} +``` + +Listing 16-6: Creating a channel and assigning the two halves to `tx` and `rx` + +The `mpsc::channel` function crates a new channel. `mpsc` stands for *multiple +producer, single consumer*. In short, we can have multiple *sending* ends of a +channel that produce values, but only one *receiving* end that consumes those +values. We're going to start with a single producer for now, but we'll add +multiple producers once we get this example working. + +`mpsc::channel` returns a tuple: the first element is the sending end, and the +second element is the receiving end. For historical reasons, many people use +`tx` and `rx` to abbreviate *transmitter* and *receiver*, so those are the +names we're using for the variables bound to 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. + +Let's move the transmitting end into a spawned thread and have it send one +string, shown in Listing 16-7: + +Filename: src/main.rs + +``` +use std::thread; +use std::sync::mpsc; + +fn main() { + let (tx, rx) = mpsc::channel(); + + thread::spawn(move || { + let val = String::from("hi"); + tx.send(val).unwrap(); + }); +} +``` + +Listing 16-7: Moving `tx` to a spawned thread and sending "hi" + +We're using `thread::spawn` to create a new thread, just as we did in the +previous section. We use a `move` closure to make `tx` move into the closure so +that the thread owns it. + +The transmitting end of a channel has the `send` method that takes the value we +want to send down the channel. The `send` method returns a `Result` type, +because if the receiving end has already been dropped, there's nowhere to send +a value to, so the send operation would error. In this example, we're simply +calling `unwrap` to ignore this error, but for a real application, we'd want to +handle it properly. Chapter 9 is where you'd go to review strategies for proper +error handling. + +In Listing 16-8, let's get the value from the receiving end of the channel in +the main thread: + +Filename: src/main.rs + +``` +use std::thread; +use std::sync::mpsc; + +fn main() { + let (tx, rx) = mpsc::channel(); + + thread::spawn(move || { + let val = String::from("hi"); + tx.send(val).unwrap(); + }); + + let received = rx.recv().unwrap(); + println!("Got: {}", received); +} +``` + +Listing 16-8: Receiving the value "hi" in the main thread and printing it out + +The receiving end of a channel has two useful methods: `recv` and `try_recv`. +Here, we're using `recv`, which is short for *receive*. This method will block +execution until a value is sent down the channel. Once a value is sent, `recv` +will return it in a `Result`. When the sending end of the channel closes, +`recv` will return an error. The `try_recv` method will not block; it instead +returns a `Result` immediately. + +If we run the code in Listing 16-8, we'll see the value printed out from the +main thread: + +``` +Got: hi +``` + +### How Channels Interact with Ownership + +Let's do an experiment at this point to see how channels and ownership work +together: we'll try to use `val` in the spawned thread after we've sent it down +the channel. Try compiling the code in Listing 16-9: + +Filename: src/main.rs + +``` +use std::thread; +use std::sync::mpsc; + +fn main() { + let (tx, rx) = mpsc::channel(); + + thread::spawn(move || { + let val = String::from("hi"); + tx.send(val).unwrap(); + println!("val is {}", val); + }); + + let received = rx.recv().unwrap(); + println!("Got: {}", received); +} +``` + +Listing 16-9: Attempting to use `val` after we have sent it down the channel + +Here, we try to print out `val` after we've sent it down the channel via +`tx.send`. This is a bad idea: once we've sent the value to another thread, +that thread could modify it or drop it before we try to use the value again. +This could cause errors or unexpected results due to inconsistent or +nonexistent data. + +If we try to compile this code, Rust will error: + +``` +error[E0382]: use of moved value: `val` + --> src/main.rs:10:31 + | +9 | tx.send(val).unwrap(); + | --- value moved here +10 | println!("val is {}", val); + | ^^^ value used here after move + | + = note: move occurs because `val` has type `std::string::String`, which does + not implement the `Copy` trait +``` + +Our concurrency mistake has caused a compile-time error! `send` takes ownership +of its parameter and moves the value so that the value is owned by the +receiver. This means we can't accidentally use the value again after sending +it; the ownership system checks that everything is okay. + +In this regard, message passing is very similar to single ownership in Rust. +Message passing enthusiasts enjoy message passing for similar reasons that +Rustaceans enjoy Rust's ownership: single ownership means certain classes of +problems go away. If only one thread at a time can use some memory, there's no +chance of a data race. + +### Sending Multiple Values and Seeing the Receiver Waiting + +The code in Listing 16-8 compiled and ran, but it wasn't very interesting: it's +hard to see that we have two separate threads talking to each other over a +channel. Listing 16-10 has some modifications that will prove to us that this +code is running concurrently: the spawned thread will now send multiple +messages and pause for a second between each message. + +Filename: src/main.rs + +``` +use std::thread; +use std::sync::mpsc; +use std::time::Duration; + +fn main() { + let (tx, rx) = mpsc::channel(); + + thread::spawn(move || { + let vals = vec![ + String::from("hi"), + String::from("from"), + String::from("the"), + String::from("thread"), + ]; + + for val in vals { + tx.send(val).unwrap(); + thread::sleep(Duration::new(1, 0)); + } + }); + + for received in rx { + println!("Got: {}", received); + } +} +``` + +Listing 16-10: Sending multiple messages and pausing between each one + +This time, we have a vector of strings in the spawned thread that we want to +send to the main thread. We iterate over them, sending each individually and +then pausing 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. + +When running the code in Listing 16-10, we'll see this output, with a one second +pause in between each line: + +``` +Got: hi +Got: from +Got: the +Got: thread +``` + +We don't have any pausing or code that would take a while in the `for` loop in +the main thread, so we can tell that the main thread is waiting to receive +values from the spawned thread. + +### Create Multiple Producers by Cloning the Transmitter + +Near the start of this section, we mentioned that `mpsc` stood for *multiple +producer, single consumer*. We can expand the code from Listing 16-10 to create +multiple threads that all send values to the same receiver. We do that 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 = tx.clone(); +thread::spawn(move || { + let vals = vec![ + String::from("hi"), + String::from("from"), + String::from("the"), + String::from("thread"), + ]; + + for val in vals { + tx1.send(val).unwrap(); + thread::sleep(Duration::new(1, 0)); + } +}); + +thread::spawn(move || { + let vals = vec![ + String::from("more"), + String::from("messages"), + String::from("for"), + String::from("you"), + ]; + + for val in vals { + tx.send(val).unwrap(); + thread::sleep(Duration::new(1, 0)); + } +}); +// ...snip... +``` + +Listing 16-11: Sending multiple messages and pausing between each one + +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 that we can +pass to the first spawned thread. We'll pass the original sending end of the +channel to a second spawned thread, and each thread is sending different +messages to the receiving end of the channel. + +If you run this, you'll *probably* see output like this: + +``` +Got: hi +Got: more +Got: from +Got: messages +Got: for +Got: the +Got: thread +Got: you +``` + +You might see the values in a different order, though. 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, you can make the runs more non-deterministic and create different +output each time. + +Now that we've seen how channels work, let's look at shared-memory concurrency. + +## Shared State Concurrency + +While message passing is a fine way of dealing with concurrency, it's not the +only one. Consider this slogan again: + +> Do not communicate by sharing memory; instead, share memory by +> communicating. + +What would "communicate by sharing memory" look like? And moreover, why would +message passing enthusiasts dislike it, and dislike it enough to invert it +entirely? + +Remember how channels are sort of like single ownership? Shared memory +concurrency is sort of like multiple ownership: multiple threads can access the +same memory location at the same time. As we saw with multiple ownership made +possible by smart pointers in Chapter 15, multiple ownership can add additional +complexity, since we need to manage these different owners somehow. + +Rust's type system and ownership can help a lot here in getting this management +correct, though. For an example, let's look at one of the more common +concurrency primitives for shared memory: mutexes. + +### 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", that is, it only allows one thread to access some data at any given +time. Mutexes have a reputation for being hard to use, since there's a lot you +have to remember: + +1. You have to remember to attempt to acquire the lock before using the data. +2. One you're done with the data that's being guarded by the mutex, you have + to remember to unlock the data so other threads can acquire the lock. + +For a real-world example of a mutex, imagine a panel discussion at a conference +where there is 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 +microphone to the next panelist who would like to speak. It would be rude for a +panelist to start shouting without having the microphone or to steal the +microphone before another panelist was finished. No one else would be able to +speak if a panelist forgot to hand the microphone to the next person when they +finished using it. If the management of the shared microphone went wrong in any +of these ways, the panel would not work as planned! + +Management of mutexes can be incredibly tricky to get right, and that's why so +many people are enthusiastic about channels. However, in Rust, we can't get +locking and unlocking wrong, thanks to the type system and ownership. + +#### The API of `Mutex` + +Let's look at an example of using a mutex in Listing 16-12, without involving +multiple threads for the moment: + +Filename: src/main.rs + +``` +use std::sync::Mutex; + +fn main() { + let m = Mutex::new(5); + + { + let mut num = m.lock().unwrap(); + *num = 6; + } + + println!("m = {:?}", m); +} +``` + +Listing 16-12: Exploring the API of `Mutex` in a single threaded context for +simplicity + +Like many types, we create a `Mutex` through an associated function named +`new`. To access the data inside the mutex, we use the `lock` method to acquire +the lock. This call will block until it's our turn to have the lock. This call +can fail if another thread was holding the lock and then that thread panicked. +In a similar way as we did in Listing 16-6 in the last section, we're using +`unwrap()` for now, rather than better error handling. See Chapter 9 for better +tools. + +Once we have 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 is how +Rust 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 otherwise. + +As you may have suspected, `Mutex` is a smart pointer. Well, more +accurately, the call to `lock` returns a smart pointer called `MutexGuard`. +This smart pointer implements `Deref` to point at our inner data, similar to +the other smart pointers we saw in Chapter 15. In addition, `MutexGuard` has a +`Drop` implementation that releases the lock. This way, we can't forget to +release the lock. It happens for us automatically when the `MutexGuard` goes +out of scope, which it does at the end of the inner scope in Listing 16-12. We +can print out 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 +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 +`Mutex` and how Rust helps us use it correctly. Listing 16-13 has our +starting example: + +Filename: src/main.rs + +``` +use std::sync::Mutex; +use std::thread; + +fn main() { + let counter = Mutex::new(0); + let mut handles = vec![]; + + for _ in 0..10 { + let handle = thread::spawn(|| { + let mut num = counter.lock().unwrap(); + + *num += 1; + }); + handles.push(handle); + } + + for handle in handles { + handle.join().unwrap(); + } + + println!("Result: {}", *counter.lock().unwrap()); +} +``` + +Listing 16-13: The start of a program having 10 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: they're each going to acquire a lock on the `Mutex` by calling the +`lock` method and then add 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 that +another thread can acquire it. + +In the main thread, we're collecting all the join handles like we did in +Listing 16-2, and then calling `join` on each of them to make sure all the +threads finish. At that point, the main thread will acquire the lock and print +out the result of this program. + +We hinted that this example won't compile, let's find out why! + +``` +error[E0373]: closure may outlive the current function, but it borrows +`counter`, which is owned by the current function + --> + | +9 | let handle = thread::spawn(|| { + | ^^ may outlive borrowed value `counter` +10 | let mut num = counter.lock().unwrap(); + | ------- `counter` is borrowed here + | +help: to force the closure to take ownership of `counter` (and any other +referenced variables), use the `move` keyword, as shown: + | let handle = thread::spawn(move || { +``` + +This is similar to the problem we solved in Listing 16-5. Given that we spin up +multiple threads, Rust can't know how long the threads will run and whether +`counter` will still be valid when each thread tries to borrow it. The help +message has a reminder for how to solve this: we can use `move` to give +ownership to each thread. Let's try it by making this change to the closure: + +``` +thread::spawn(move || { +``` + +And trying to compile again. We'll get different errors this time! + +``` +error[E0382]: capture of moved value: `counter` + --> + | +9 | let handle = thread::spawn(move || { + | ------- value moved (into closure) here +10 | let mut num = counter.lock().unwrap(); + | ^^^^^^^ value captured here after move + | + = note: move occurs because `counter` has type `std::sync::Mutex`, + which does not implement the `Copy` trait + +error[E0382]: use of moved value: `counter` + --> + | +9 | let handle = thread::spawn(move || { + | ------- value moved (into closure) here +... +21 | println!("Result: {}", *counter.lock().unwrap()); + | ^^^^^^^ value used here after move + | + = note: move occurs because `counter` has type `std::sync::Mutex`, + which does not implement the `Copy` trait + +error: aborting due to 2 previous errors +``` + +`move` didn't fix this program like it fixed Listing 16-5. Why not? This error +message is a little confusing to read, because it's 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. + +Let's reason this out. 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: + +``` +let handle = thread::spawn(move || { + let mut num = counter.lock().unwrap(); + + *num += 1; +}); +handles.push(handle); + +let handle2 = thread::spawn(move || { + let mut num2 = counter.lock().unwrap(); + + *num2 += 1; +}); +handles.push(handle2); +``` + +Here we're making 2 threads, and we changed the variable names used with the +second thread to `handle2` and `num2`. We're simplifying our example for the +moment to see if we can understand the error message we're getting. This time, +compiling gives us: + +``` +error[E0382]: capture of moved value: `counter` + --> + | +8 | let handle = thread::spawn(move || { + | ------- value moved (into closure) here +... +16 | let mut num2 = counter.lock().unwrap(); + | ^^^^^^^ value captured here after move + | + = note: move occurs because `counter` has type `std::sync::Mutex`, + which does not implement the `Copy` trait + +error[E0382]: use of moved value: `counter` + --> + | +8 | let handle = thread::spawn(move || { + | ------- value moved (into closure) here +... +26 | println!("Result: {}", *counter.lock().unwrap()); + | ^^^^^^^ value used here after move + | + = note: move occurs because `counter` has type `std::sync::Mutex`, + which does not implement the `Copy` trait + +error: aborting due to 2 previous errors +``` + +Aha! In the first error message, Rust is showing us that `counter` is moved +into the closure for the thread that goes with `handle`. That move is +preventing us from capturing `counter` when we try to call `lock` on it and +store the result in `num2`, which is 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 since we were creating multiple threads in a loop, and Rust +can't point to different threads in different iterations of the loop. + +#### Multiple Ownership with Multiple Threads + +In Chapter 15, we were able to have multiple ownership of a value by using the +smart pointer `Rc` to create a reference-counted value. We mentioned in +Chapter 15 that `Rc` was only for single-threaded contexts, but let's try +using `Rc` in this case anyway 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. We'll switch back to the `for` loop for creating the +threads, and keep the `move` keyword with the closure: + +Filename: src/main.rs + +``` +use std::rc::Rc; +use std::sync::Mutex; +use std::thread; + +fn main() { + let counter = Rc::new(Mutex::new(0)); + let mut handles = vec![]; + + for _ in 0..10 { + let counter = counter.clone(); + let handle = thread::spawn(move || { + let mut num = counter.lock().unwrap(); + + *num += 1; + }); + handles.push(handle); + } + + for handle in handles { + handle.join().unwrap(); + } + + println!("Result: {}", *counter.lock().unwrap()); +} +``` + +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! + +``` +error[E0277]: the trait bound `std::rc::Rc>: +std::marker::Send` is not satisfied + --> + | +11 | let handle = thread::spawn(move || { + | ^^^^^^^^^^^^^ the trait `std::marker::Send` is not + implemented for `std::rc::Rc>` + | + = note: `std::rc::Rc>` cannot be sent between threads + safely + = note: required because it appears within the type + `[closure@src/main.rs:11:36: 15:10 + counter:std::rc::Rc>]` + = note: required by `std::thread::spawn` +``` + +Wow, that's quite wordy! 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. + +Unfortunately, `Rc` is not safe to share across threads. When `Rc` +manages the reference count, it has to add to the count for each call to +`clone` and subtract from the count when each clone is dropped. `Rc` doesn't +use any concurrency primitives to make sure that changes to the count happen in +an operation that couldn't be interrupted by another thread. This could lead to +subtle bugs where the counts are wrong, which could lead to memory leaks or +dropping a value before we're done with it. So what if we had a type that was +exactly like `Rc`, but made changes to the reference count in a thread-safe +way? + +#### Atomic Reference Counting with `Arc` + +If you thought that question sounded like a leading one, you'd be right. There +is a type like `Rc` that's safe to use in concurrent situations: `Arc`. +The 'a' stands for *atomic*, so it's an *atomically reference counted* type. +Atomics are an additional kind of concurrency primitive that we won't cover +here; see the standard library documentation for `std::sync::atomic` for more +details. The gist of it is this: atomics work like primitive types, but are +safe to share across threads. + +Why aren't all primitive types atomic, and why aren't all standard library +types implemented to use `Arc` by default? Thread safety comes with a +performance penalty that we only want to pay when we need it. If we're only +doing operations on values within a single thread, our code can run faster +since it doesn't need the guarantees that atomics give us. + +Back to our example: `Arc` and `Rc` are identical except for the atomic +internals of `Arc`. Their API is the same, so we can change the `use` line +and the call to `new`. The code in Listing 16-15 will finally compile and run: + +``` +use std::sync::{Mutex, Arc}; +use std::thread; + +fn main() { + let counter = Arc::new(Mutex::new(0)); + let mut handles = vec![]; + + for _ in 0..10 { + let counter = counter.clone(); + let handle = thread::spawn(move || { + let mut num = counter.lock().unwrap(); + + *num += 1; + }); + handles.push(handle); + } + + for handle in handles { + handle.join().unwrap(); + } + + println!("Result: {}", *counter.lock().unwrap()); +} +``` + +Listing 16-15: Using an `Arc` to wrap the `Mutex` to be able to share +ownership across multiple threads + +This will print: + +``` +Result: 10 +``` + +We did it! We counted from 0 to 10, which may not seem very impressive, but we +learned a lot about `Mutex` and thread safety along the way! The structure +that we've built in this example could be used to do more complicated +operations than just incrementing a counter. Calculations that can be divided +up into independent parts could be split across threads in this way, and we can +use a `Mutex` to allow each thread to update the final result with its part. + +You may have noticed that, since `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 that we used +`RefCell` in Chapter 15 to be able to mutate contents inside an `Rc`, we +use `Mutex` to be able to mutate contents inside of an `Arc`. + +Recall that `Rc` did not prevent every possible problem: we also talked +about the possibility of creating reference cycles where two `Rc` values +refer to each other, which would cause a memory leak. We have a similar problem +with `Mutex` that Rust also doesn't prevent: deadlocks. A *deadlock* is a +situation in which an operation needs to lock two resources, and two threads +have each acquired one of the locks and will now 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 that apply to the use of +mutexes in any language and try implementing them in Rust. The standard library +API documentation for `Mutex` and `MutexGuard` will have useful information. + +Rust's type system and ownership has made sure that our threads have exclusive +access to the shared value when they're updating it, so the threads won't +overwrite each other's answers in unpredictable ways. It took us a while to +work with the compiler to get everything right, but we've saved future time +that might be spent trying to reproduce subtly incorrect scenarios that only +happen when the threads run in a particular order. + +Let's round out this chapter by talking about the `Send` and `Sync` traits and +how we could use them with custom types. + +## Extensible Concurrency with the `Sync` and `Send` Traits + +One interesting aspect of Rust's concurrency model is that the language knows +*very* little about concurrency. Almost everything we've been talking about so +far has been part of the standard library, not the language itself. Because we +don't need the language to provide everything we need to program in a +concurrent context, we're not limited to the concurrency options that the +standard library or language provide: we can write our own or use ones others +have written. + +We said *almost* everything wasn't in the language, so what is? There are two +traits, both in `std::marker`: `Sync` and `Send`. + +### `Send` for Indicating Ownership May Be Transferred to Another Thread + +The `Send` marker trait indicates that ownership of that type may be +transferred between threads. Almost every Rust type is `Send`, but there are +some exceptions. One type provided by the standard library that is not `Send` +is `Rc`: if we clone an `Rc` value and try to transfer ownership of the +clone to another thread, both threads might update the reference count at the +same time. As we mentioned in the previous section, `Rc` is implemented for +use in single-threaded situations where you don't want to pay the performance +penalty of having a threadsafe reference count. + +Because `Rc` is not marked `Send`, Rust's type system and trait bounds +ensure that we can never forget and accidentally send an `Rc` value across +threads unsafely. We tried to do this in Listing 16-14, and 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. + +Any type that is composed entirely of `Send` types is automatically marked as +`Send` as well. Almost all primitive types are `Send`, aside from raw pointers, +which we'll discuss in Chapter 19. Most standard library types are `Send`, +aside from `Rc`. + +### `Sync` for Indicating Access from Multiple Threads is Safe + +The `Sync` marker trait indicates that a type is safe to have references to a +value from multiple threads. Another way to say this is for any type `T`, `T` +is `Sync` if `&T` (a reference to `T`) is `Send` so that 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`. + +`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 the borrow checking at +runtime that `RefCell` does is not threadsafe. `Mutex` is `Sync`, and can +be used to share access with multiple threads as we saw in the previous section. + +### Implementing `Send` and `Sync` Manually is Unsafe + +Usually, we don't need to implement the `Send` and `Sync` traits, since types +that are made up of `Send` and `Sync` traits are automatically also `Send` and +`Sync`. Because they're marker traits, they don't even have any methods to +implement. They're just useful for enforcing concurrency-related invariants. + +Implementing the guarantees that these traits are markers for 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 that aren't made up of `Send` and `Sync` parts requires +careful thought to make sure the safety guarantees are upheld. The Nomicon at *https://doc.rust-lang.org/stable/nomicon/vec.html* +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 we discussed in this chapter. + +As we mentioned, since very little of how Rust deals with concurrency has to be +part of the language, there are many concurrency solutions implemnted as +crates. These evolve more quickly than the standard library; search online for +the current state-of-the-art crates for 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 we write using these +solutions won't have data races or invalid references. Once we get our code +compiling, we can rest assured that our code will happily run on multiple +threads without the kinds of hard-to-track-down bugs common in other +programming languages. Concurrent programming is no longer something to be +afraid of: go forth and make your programs concurrent, fearlessly! + +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/chapter17.md b/src/doc/book/second-edition/nostarch/chapter17.md new file mode 100644 index 0000000000..36d683bb4a --- /dev/null +++ b/src/doc/book/second-edition/nostarch/chapter17.md @@ -0,0 +1,1298 @@ + +[TOC] + +# Is Rust an Object-Oriented Programming Language? + +Object-Oriented Programming is a way of modeling programs that originated with +Simula in the 1960s and became popular with C++ in the 1990s. There are many +competing definitions for what OOP is: under some definitions, Rust is +object-oriented; under other definitions, Rust is not. In this chapter, we'll +explore some characteristics that are commonly considered to be object-oriented +and how those characteristics translate to idiomatic Rust. + +## What Does Object-Oriented Mean? + +There isn't consensus in the programming community about the features a +language needs to have in order to be called object-oriented. Rust is +influenced by many different programming paradigms; we explored the features it +has that come from functional programming in Chapter 13. Some of the +characteristics that object-oriented programming languages tend to share are +objects, encapsulation, and inheritance. Let's take a look at what each of +those mean and whether Rust supports them. + +### Objects Contain Data and Behavior + +The book "Design Patterns: Elements of Reusable Object-Oriented Software," +colloquially referred to as "The Gang of Four book," is a catalog of +object-oriented design patterns. It defines object-oriented programming in this +way: + +> Object-oriented programs are made up of objects. An *object* packages both +> data and the procedures that operate on that data. The procedures are +> typically called *methods* or *operations*. + +Under this definition, then, Rust is object-oriented: structs and enums have +data and `impl` blocks provide methods on structs and enums. Even though +structs and enums with methods aren't *called* objects, they provide the same +functionality that objects do, using the Gang of Four's definition of objects. + +### Encapsulation that Hides Implementation Details + +Another aspect commonly associated with object-oriented programming is the idea +of *encapsulation*: the implementation details of an object aren't accessible +to code using that object. The only way to interact with an object is through +the public API the object offers; code using the object should not be able to +reach into the object's internals and change data or behavior directly. +Encapsulation enables changing and refactoring an object's internals without +needing to change the code that uses the object. + +As we discussed in Chapter 7, we can use the `pub` keyword to decide what +modules, types, functions, and methods in our code should be public, and by +default, everything is private. For example, we can define a struct +`AveragedCollection` that has a field containing a vector of `i32` values. The +struct can also have a field that knows the average of the values in the vector +so that whenever anyone wants to know the average of the values that the struct +has in its vector, we don't have to compute it on-demand. `AveragedCollection` +will cache the calculated average for us. Listing 17-1 has the definition of +the `AveragedCollection` struct: + +Filename: src/lib.rs + +``` +pub struct AveragedCollection { + list: Vec, + average: f64, +} +``` + +Listing 17-1: An `AveragedCollection` struct that maintains a list of integers +and the average of the items in the collection. + +Note that the struct itself is marked `pub` so that other code may use this +struct, but the fields within the struct remain private. This is important in +this case because we want to ensure that whenever a value is added or removed +from the list, we also update the average. We do this by implementing `add`, +`remove`, and `average` methods on the struct as shown in Listing 17-2: + +Filename: src/lib.rs + +``` +impl AveragedCollection { + pub fn add(&mut self, value: i32) { + self.list.push(value); + self.update_average(); + } + + pub fn remove(&mut self) -> Option { + let result = self.list.pop(); + match result { + Some(value) => { + self.update_average(); + Some(value) + }, + None => None, + } + } + + pub fn average(&self) -> f64 { + self.average + } + + fn update_average(&mut self) { + let total: i32 = self.list.iter().sum(); + self.average = total as f64 / self.list.len() as f64; + } +} +``` + +Listing 17-2: Implementations of the public methods +`add`, `remove`, and `average` on `AveragedCollection` + +The public methods `add`, `remove`, and `average` are the only way to modify an +instance of a `AveragedCollection`. When an item is added to `list` using the +`add` method or removed using the `remove` method, the implementations of those +methods call the private `update_average` method that takes care of updating +the `average` field as well. Because the `list` and `average` fields are +private, there's no way for external code to add or remove items to the `list` +field directly, which could cause the `average` field to get out of sync. The +`average` method returns the value in the `average` field, which allows +external code to read the `average` but not modify it. + +Because we've encapsulated the implementation details of `AveragedCollection`, +we could also change aspects like using a different data structure used for the +`list` to use a `HashSet` instead of a `Vec`, for instance. As long as the +signatures of the `add`, `remove`, and `average` public methods stayed the same, +code using `AveragedCollection` wouldn't need to change. This wouldn't +necessarily be the case if we exposed `list` to external code: `HashSet` and +`Vec` have different methods for adding and removing items, so the external +code would likely have to change if it was modifying `list` directly. + +If encapsulation is a required aspect for a language to be considered +object-oriented, then Rust meets that requirement. Using `pub` or not for +different parts of code enables encapsulation of implementation details. + +### Inheritance as a Type System and as Code Sharing + +*Inheritance* is a mechanism that some programming languages provide whereby an +object can be defined to inherit from another object's definition, thus gaining +the parent object's data and behavior without having to define those again. +Inheritance is a characteristic that is part of some people's definitions of +what an OOP language is. + +If a language must have inheritance to be an object-oriented language, then +Rust is not object-oriented. There is not a way to define a struct that +inherits from another struct in order to gain the parent struct's fields and +method implementations. However, if you're used to having inheritance in your +programming toolbox, there are other solutions in Rust depending on the reason +you want to use inheritance. + +There are two main reasons to reach for inheritance. The first is to be able to +re-use code: once a particular behavior is implemented for one type, +inheritance can enable re-using that implementation for a different type. Rust +code can be shared using default trait method implementations instead, which we +saw in Listing 10-14 when we added a default implementation of the `summary` +method on the `Summarizable` trait. Any type implementing the `Summarizable` +trait would have the `summary` method available on it without any further code. +This is similar to a parent class having an implementation of a method, and a +child class inheriting from the parent class also having the implementation of +the method due to the inheritance. We can also choose to override the default +implementation of the `summary` method when we implement the `Summarizable` +trait, which is similar to a child class overriding the implementation of a +method inherited from a parent class. + +The second reason to use inheritance is with the type system: to express that a +child type can be used in the same places that the parent type can be used. +This is also called *polymorphism*, which means that multiple objects can be +substituted for each other at runtime if they have the same shape. + + + +> While many people use "polymorphism" to describe inheritance, it's actually +> a specific kind of polymorphism, called "sub-type polymorphism." There are +> other forms as well; a generic parameter with a trait bound in Rust is +> also polymorphism, more specifically "parametric polymorphism." The exact +> details between the different kinds of polymorphism aren't crucial here, +> so don't worry too much about the details: just know that Rust has multiple +> polymorphism-related features, unlike many OOP languages. + + + +To support this sort of pattern, Rust has *trait objects* so that we can +specify that we would like values of any type, as long as the values implement +a particular trait. + +Inheritance has recently fallen out of favor as a programming design solution +in many programming languages. Using inheritance to re-use some code can +require more code to be shared than you actually need. Subclasses shouldn't +always share all characteristics of their parent class, but inheritance means +the subclass gets all of its parent's data and behavior. This can make a +program's design less flexible, and creates the possibility of calling methods +on subclasses that don't make sense or cause errors since the methods don't +apply to the subclass but must be inherited from the parent class. In addition, +some languages only allow a subclass to inherit from one class, further +restricting the flexibility of a program's design. + +For these reasons, Rust chose to take a different approach with trait objects +instead of inheritance. Let's take a look at how trait objects enable +polymorphism in Rust. + +## Trait Objects for Using Values of Different Types + +In Chapter 8, we talked about a limitation of vectors is that vectors can only +store elements of one type. We had an example in Listing 8-1 where we defined a +`SpreadsheetCell` enum that had variants to hold integers, floats, and text so +that we could store different types of data in each cell and still have a +vector represent a row of cells. This works for cases in which the kinds of +things we want to be able to treat interchangeably are a fixed set of types that +we know when our code gets compiled. + + + +Sometimes we want the set of types that we use to be extensible by the +programmers who use our library. For example, many Graphical User Interface +tools have a concept of a list of items that get drawn on the screen by +iterating through the list and calling a `draw` method on each of the items. +We're going to create a library crate containing the structure of a GUI library +called `rust_gui`. Our GUI library could include some types for people to use, +such as `Button` or `TextField`. Programmers that use `rust_gui` will want to +create more types that can be drawn on the screen: one programmer might add an +`Image`, while another might add a `SelectBox`. We're not going to implement a +fully-fledged GUI library in this chapter, but we will show how the pieces +would fit together. + +When we're writing the `rust_gui` library, we don't know all the types that +other programmers will want to create, so we can't define an `enum` containing +all the types. What we do know is that `rust_gui` needs to be able to keep +track of a bunch of values of all these different types, and it needs to be +able to call a `draw` method on each of these values. Our GUI library doesn't +need to know what will happen exactly when we call the `draw` method, just that +the value will have that method available for us to call. + +In a language with inheritance, we might define a class named `Component` that +has a method named `draw` on it. The other classes like `Button`, `Image`, and +`SelectBox` would inherit from `Component` and thus inherit the `draw` method. +They could each override the `draw` method to define their custom behavior, but +the framework could treat all of the types as if they were `Component` +instances and call `draw` on them. + +### Defining a Trait for the Common Behavior + +In Rust, though, we can define a trait that we'll name `Draw` and that will +have one method named `draw`. Then we can define a vector that takes a *trait +object*, which is a trait behind some sort of pointer, such as a `&` reference +or a `Box` smart pointer. + +We mentioned that we don't call structs and enums "objects" to distinguish +structs and enums from other languages' objects. The data in the struct or enum +fields and the behavior in `impl` blocks is separated, as opposed to other +languages that have data and behavior combined into one concept called an +object. Trait objects *are* more like objects in other languages, in the sense +that they combine the data made up of the pointer to a concrete object with the +behavior of the methods defined in the trait. However, trait objects are +different from objects in other languages because we can't add data to a trait +object. Trait objects aren't as generally useful as objects in other languages: +their purpose is to allow abstraction across common behavior. + +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. Rust's type system will ensure that any value we substitute in +for the trait object will implement the methods of the trait. Then we don't +need to know all the possible types at compile time, and we can treat all the +instances the same way. Listing 17-3 shows how to define a trait named `Draw` +with one method named `draw`: + +Filename: src/lib.rs + +``` +pub trait Draw { + fn draw(&self); +} +``` + +Listing 17-3: Definition of the `Draw` trait + +This should look familiar since we talked about how to define traits in +Chapter 10. Next comes something new: Listing 17-4 has the definition of a +struct named `Screen` that holds a vector named `components` that are of type +`Box`. That `Box` is a trait object: it's a stand-in for any type +inside a `Box` that implements the `Draw` trait. + +Filename: src/lib.rs + +``` +pub struct Screen { + pub components: Vec>, +} +``` + +Listing 17-4: Definition of the `Screen` struct with a `components` field that +holds a vector of trait objects that implement the `Draw` trait + +On the `Screen` struct, we'll define a method named `run`, which will call the +`draw` method on each of its `components` as shown in Listing 17-5: + +Filename: src/lib.rs + +``` +impl Screen { + pub fn run(&self) { + for component in self.components.iter() { + component.draw(); + } + } +} +``` + +Listing 17-5: Implementing a `run` method on `Screen` that calls the `draw` +method on each component + +This is different than defining a struct that uses a generic type parameter +with trait bounds. A generic type parameter can only be substituted with one +concrete type at a time, while trait objects allow for multiple concrete types +to fill in for the trait object at runtime. For example, we could have defined +the `Screen` struct using a generic type and a trait bound as in Listing 17-6: + +Filename: src/lib.rs + +``` +pub struct Screen { + pub components: Vec, +} + +impl Screen + where T: Draw { + pub fn run(&self) { + for component in self.components.iter() { + component.draw(); + } + } +} +``` + +Listing 17-6: An alternate implementation of the `Screen` struct and its `run` +method using generics and trait bounds + +This only lets us have a `Screen` instance that has a list of components that +are all of 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 definition of `Screen` that holds a component list of trait objects in +`Vec>` instead, one `Screen` instance can hold a `Vec` that contains +a `Box