New upstream version 1.27.1+dfsg1

This commit is contained in:
Ximin Luo 2018-07-13 13:55:53 -07:00
parent 2c912e08a8
commit 83c7162d06
3716 changed files with 336004 additions and 53481 deletions

View File

@ -47,6 +47,12 @@ as it's possible that someone else has already reported your error. This doesn't
always work, and sometimes it's hard to know what to search for, so consider this
extra credit. We won't mind if you accidentally file a duplicate report.
Similarly, to help others who encountered the bug find your issue,
consider filing an issue with with a descriptive title, which contains information that might be unique to it.
This can be the language or compiler feature used, the conditions that trigger the bug,
or part of the error message if there is any.
An example could be: **"impossible case reached" on lifetime inference for impl Trait in return position**.
Opening an issue is as easy as following [this
link](https://github.com/rust-lang/rust/issues/new) and filling out the fields.
Here's a template that you can use to file a bug, though it's not necessary to
@ -121,6 +127,7 @@ configuration used in the build process. Some options to note:
#### `[rust]`:
- `debuginfo = true` - Build a compiler with debuginfo. Makes building rustc slower, but then you can use a debugger to debug `rustc`.
- `debuginfo-lines = true` - An alternative to `debuginfo = true` that doesn't let you use a debugger, but doesn't make building rustc slower and still gives you line numbers in backtraces.
- `debuginfo-tools = true` - Build the extended tools with debuginfo.
- `debug-assertions = true` - Makes the log output of `debug!` work.
- `optimize = false` - Disable optimizations to speed up compilation of stage1 rust, but makes the stage1 compiler x100 slower.
@ -135,6 +142,8 @@ file. If you still have a `config.mk` file in your directory - from
### Building
[building]: #building
A default configuration shall use around 3.5 GB of disk space, whereas building a debug configuration may require more than 30 GB.
Dependencies
- [build dependencies](README.md#building-from-source)
- `gdb` 6.2.0 minimum, 7.1 or later recommended for test builds

View File

@ -1,3 +1,173 @@
Version 1.27.1 (2018-07-10)
===========================
Security Notes
--------------
- rustdoc would execute plugins in the /tmp/rustdoc/plugins directory
when running, which enabled executing code as some other user on a
given machine. This release fixes that vulnerability; you can read
more about this on the [blog][rustdoc-sec].
Thank you to Red Hat for responsibily disclosing this vulnerability to us.
Compatibility Notes
-------------------
- The borrow checker was fixed to avoid an additional potential unsoundness when using
match ergonomics: [#51415][51415], [#49534][49534].
[51415]: https://github.com/rust-lang/rust/issues/51415
[49534]: https://github.com/rust-lang/rust/issues/49534
[rustdoc-sec]: https://blog.rust-lang.org/2018/07/06/security-advisory-for-rustdoc.html
Version 1.27.0 (2018-06-21)
==========================
Language
--------
- [Removed 'proc' from the reserved keywords list.][49699] This allows `proc` to
be used as an identifer.
- [The dyn syntax is now available.][49968] This syntax is equivalent to the
bare `Trait` syntax, and should make it clearer when being used in tandem with
`impl Trait`. Since it is equivalent to the following syntax:
`&Trait == &dyn Trait`, `&mut Trait == &mut dyn Trait`, and
`Box<Trait> == Box<dyn Trait>`.
- [Attributes on generic parameters such as types and lifetimes are
now stable.][48851] e.g.
`fn foo<#[lifetime_attr] 'a, #[type_attr] T: 'a>() {}`
- [The `#[must_use]` attribute can now also be used on functions as well as
types.][48925] It provides a lint that by default warns users when the
value returned by a function has not been used.
Compiler
--------
- [Added the `armv5te-unknown-linux-musl` target.][50423]
Libraries
---------
- [SIMD (Single Instruction Multiple Data) on x86/x86_64 is now stable.][49664]
This includes [`arch::x86`] & [`arch::x86_64`] modules which contain
SIMD intrinsics, a new macro called `is_x86_feature_detected!`, the
`#[target_feature(enable="")]` attribute, and adding `target_feature = ""` to
the `cfg` attribute.
- [A lot of methods for `[u8]`, `f32`, and `f64` previously only available in
std are now available in core.][49896]
- [The generic `Rhs` type parameter on `ops::{Shl, ShlAssign, Shr}` now defaults
to `Self`.][49630]
- [`std::str::replace` now has the `#[must_use]` attribute][50177] to clarify
that the operation isn't done in place.
- [`Clone::clone`, `Iterator::collect`, and `ToOwned::to_owned` now have
the `#[must_use]` attribute][49533] to warn about unused potentially
expensive allocations.
Stabilized APIs
---------------
- [`DoubleEndedIterator::rfind`]
- [`DoubleEndedIterator::rfold`]
- [`DoubleEndedIterator::try_rfold`]
- [`Duration::from_micros`]
- [`Duration::from_nanos`]
- [`Duration::subsec_micros`]
- [`Duration::subsec_millis`]
- [`HashMap::remove_entry`]
- [`Iterator::try_fold`]
- [`Iterator::try_for_each`]
- [`NonNull::cast`]
- [`Option::filter`]
- [`String::replace_range`]
- [`Take::set_limit`]
- [`hint::unreachable_unchecked`]
- [`os::unix::process::parent_id`]
- [`process::id`]
- [`ptr::swap_nonoverlapping`]
- [`slice::rsplit_mut`]
- [`slice::rsplit`]
- [`slice::swap_with_slice`]
Cargo
-----
- [`cargo-metadata` now includes `authors`, `categories`, `keywords`,
`readme`, and `repository` fields.][cargo/5386]
- [Added the `--target-dir` optional argument.][cargo/5393] This allows you to specify
a different directory than `target` for placing compilation artifacts.
- [Cargo will be adding automatic target inference for binaries, benchmarks,
examples, and tests in the Rust 2018 edition.][cargo/5335] If your project specifies
specific targets e.g. using `[[bin]]` and have other binaries in locations
where cargo would infer a binary, Cargo will produce a warning. You can
disable this feature ahead of time by setting any of the following `autobins`,
`autobenches`, `autoexamples`, `autotests` to false.
- [Cargo will now cache compiler information.][cargo/5359] This can be disabled by
setting `CARGO_CACHE_RUSTC_INFO=0` in your environment.
Misc
----
- [Added “The Rustc book” into the official documentation.][49707]
[“The Rustc book”] documents and teaches how to use the rustc compiler.
- [All books available on `doc.rust-lang.org` are now searchable.][49623]
Compatibility Notes
-------------------
- [Calling a `CharExt` or `StrExt` method directly on core will no longer
work.][49896] e.g. `::core::prelude::v1::StrExt::is_empty("")` will not
compile, `"".is_empty()` will still compile.
- [`Debug` output on `atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicUsize}`
will only print the inner type.][48553] e.g.
`print!("{:?}", AtomicBool::new(true))` will print `true`
not `AtomicBool(true)`.
- [The maximum number for `repr(align(N))` is now 2²⁹.][50378] Previously you
could enter higher numbers but they were not supported by LLVM. Up to 512MB
alignment should cover all use cases.
[48553]: https://github.com/rust-lang/rust/pull/48553/
[48851]: https://github.com/rust-lang/rust/pull/48851/
[48925]: https://github.com/rust-lang/rust/pull/48925/
[49533]: https://github.com/rust-lang/rust/pull/49533/
[49623]: https://github.com/rust-lang/rust/pull/49623/
[49630]: https://github.com/rust-lang/rust/pull/49630/
[49664]: https://github.com/rust-lang/rust/pull/49664/
[49699]: https://github.com/rust-lang/rust/pull/49699/
[49707]: https://github.com/rust-lang/rust/pull/49707/
[49719]: https://github.com/rust-lang/rust/pull/49719/
[49896]: https://github.com/rust-lang/rust/pull/49896/
[49968]: https://github.com/rust-lang/rust/pull/49968/
[50177]: https://github.com/rust-lang/rust/pull/50177/
[50378]: https://github.com/rust-lang/rust/pull/50378/
[50398]: https://github.com/rust-lang/rust/pull/50398/
[50423]: https://github.com/rust-lang/rust/pull/50423/
[cargo/5203]: https://github.com/rust-lang/cargo/pull/5203/
[cargo/5335]: https://github.com/rust-lang/cargo/pull/5335/
[cargo/5359]: https://github.com/rust-lang/cargo/pull/5359/
[cargo/5386]: https://github.com/rust-lang/cargo/pull/5386/
[cargo/5393]: https://github.com/rust-lang/cargo/pull/5393/
[`DoubleEndedIterator::rfind`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#method.rfind
[`DoubleEndedIterator::rfold`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#method.rfold
[`DoubleEndedIterator::try_rfold`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#method.try_rfold
[`Duration::from_micros`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.from_micros
[`Duration::from_nanos`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.from_nanos
[`Duration::subsec_micros`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.subsec_micros
[`Duration::subsec_millis`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.subsec_millis
[`HashMap::remove_entry`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.remove_entry
[`Iterator::try_fold`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.try_fold
[`Iterator::try_for_each`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.try_for_each
[`NonNull::cast`]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.cast
[`Option::filter`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.filter
[`String::replace_range`]: https://doc.rust-lang.org/std/string/struct.String.html#method.replace_range
[`Take::set_limit`]: https://doc.rust-lang.org/std/io/struct.Take.html#method.set_limit
[`slice::rsplit_mut`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rsplit_mut
[`slice::rsplit`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rsplit
[`slice::swap_with_slice`]: https://doc.rust-lang.org/std/primitive.slice.html#method.swap_with_slice
[`arch::x86_64`]: https://doc.rust-lang.org/std/arch/x86_64/index.html
[`arch::x86`]: https://doc.rust-lang.org/std/arch/x86/index.html
[`fs::read`]:
[`fs::write`]:
[`hint::unreachable_unchecked`]: https://doc.rust-lang.org/std/hint/fn.unreachable_unchecked.html
[`os::unix::process::parent_id`]: https://doc.rust-lang.org/std/os/unix/process/fn.parent_id.html
[`ptr::swap_nonoverlapping`]: https://doc.rust-lang.org/std/ptr/fn.swap_nonoverlapping.html
[`process::id`]: https://doc.rust-lang.org/std/process/fn.id.html
[“The Rustc book”]: https://doc.rust-lang.org/rustc
Version 1.26.2 (2018-06-05)
==========================
@ -8,6 +178,7 @@ Compatibility Notes
[51117]: https://github.com/rust-lang/rust/issues/51117
Version 1.26.1 (2018-05-29)
==========================

View File

@ -262,6 +262,10 @@
# standard library.
#debuginfo-only-std = false
# Enable debuginfo for the extended tools: cargo, rls, rustfmt
# Adding debuginfo makes them several times larger.
#debuginfo-tools = false
# Whether or not jemalloc is built and enabled
#use-jemalloc = true
@ -339,6 +343,12 @@
# rustc to execute.
#lld = false
# Whether to deny warnings in crates
#deny-warnings = true
# Print backtrace on internal compiler errors during bootstrap
#backtrace-on-ice = false
# =============================================================================
# Options for specific targets
#

View File

@ -1 +1 @@
594fb253c2b02b320c728391a425d028e6dc7a09
5f2b325f64ed6caa7179f3e04913db437656ec7e

1189
src/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -40,14 +40,6 @@ members = [
"tools/rls/test_data/workspace_symbol",
]
# Curiously, compiletest will segfault if compiled with opt-level=3 on 64-bit
# MSVC when running the compile-fail test suite when a should-fail test panics.
# But hey if this is removed and it gets past the bots, sounds good to me.
[profile.release]
opt-level = 2
[profile.bench]
opt-level = 2
# These options are controlled from our rustc wrapper script, so turn them off
# here and have them controlled elsewhere.
[profile.dev]

View File

@ -42,3 +42,7 @@ serde_json = "1.0.2"
toml = "0.4"
lazy_static = "0.2"
time = "0.1"
petgraph = "0.4.12"
[dev-dependencies]
pretty_assertions = "0.5"

View File

@ -64,6 +64,10 @@ The script accepts commands, flags, and arguments to determine what to do:
# execute tests in the standard library in stage0
./x.py test --stage 0 src/libstd
# execute tests in the core and standard library in stage0,
# without running doc tests (thus avoid depending on building the compiler)
./x.py test --stage 0 --no-doc src/libcore src/libstd
# execute all doc tests
./x.py test src/doc
```

View File

@ -107,6 +107,13 @@ fn main() {
env::join_paths(&dylib_path).unwrap());
let mut maybe_crate = None;
// Print backtrace in case of ICE
if env::var("RUSTC_BACKTRACE_ON_ICE").is_ok() && env::var("RUST_BACKTRACE").is_err() {
cmd.env("RUST_BACKTRACE", "1");
}
cmd.env("RUSTC_BREAK_ON_ICE", "1");
if let Some(target) = target {
// The stage0 compiler has a special sysroot distinct from what we
// actually downloaded, so we just always pass the `--sysroot` option.
@ -247,9 +254,6 @@ fn main() {
// When running miri tests, we need to generate MIR for all libraries
if env::var("TEST_MIRI").ok().map_or(false, |val| val == "true") {
cmd.arg("-Zalways-encode-mir");
if stage != "0" {
cmd.arg("-Zmiri");
}
cmd.arg("-Zmir-emit-validate=1");
}
@ -279,6 +283,10 @@ fn main() {
cmd.arg("--color=always");
}
if env::var_os("RUSTC_DENY_WARNINGS").is_some() {
cmd.arg("-Dwarnings");
}
if verbose > 1 {
eprintln!("rustc command: {:?}", cmd);
eprintln!("sysroot: {:?}", sysroot);

View File

@ -314,7 +314,7 @@ class RustBuild(object):
self.build_dir = os.path.join(os.getcwd(), "build")
self.clean = False
self.config_toml = ''
self.rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
self.rust_root = ''
self.use_locked_deps = ''
self.use_vendored_sources = ''
self.verbose = False
@ -710,6 +710,7 @@ def bootstrap(help_triggered):
parser = argparse.ArgumentParser(description='Build rust')
parser.add_argument('--config')
parser.add_argument('--build')
parser.add_argument('--src')
parser.add_argument('--clean', action='store_true')
parser.add_argument('-v', '--verbose', action='count', default=0)
@ -718,6 +719,7 @@ def bootstrap(help_triggered):
# Configure initial bootstrap
build = RustBuild()
build.rust_root = args.src or os.path.abspath(os.path.join(__file__, '../../..'))
build.verbose = args.verbose
build.clean = args.clean
@ -768,10 +770,7 @@ def bootstrap(help_triggered):
if 'dev' in data:
build.set_dev_environment()
# No help text depends on submodules. This check saves ~1 minute of git commands, even if
# all the submodules are present and downloaded!
if not help_triggered:
build.update_submodules()
build.update_submodules()
# Fetch/build the bootstrap
build.build = args.build or build.build_triple()
@ -788,6 +787,7 @@ def bootstrap(help_triggered):
env["SRC"] = build.rust_root
env["BOOTSTRAP_PARENT_ID"] = str(os.getpid())
env["BOOTSTRAP_PYTHON"] = sys.executable
env["BUILD_DIR"] = build.build_dir
run(args, env=env, verbose=build.verbose)

View File

@ -19,12 +19,13 @@ use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::{Instant, Duration};
use std::collections::HashMap;
use compile;
use install;
use dist;
use util::{exe, libdir, add_lib_path};
use {Build, Mode};
use {Build, Mode, DocTests};
use cache::{INTERNER, Interned, Cache};
use check;
use test;
@ -35,6 +36,9 @@ use native;
pub use Compiler;
use petgraph::Graph;
use petgraph::graph::NodeIndex;
pub struct Builder<'a> {
pub build: &'a Build,
pub top_stage: u32,
@ -42,6 +46,10 @@ pub struct Builder<'a> {
cache: Cache,
stack: RefCell<Vec<Box<Any>>>,
time_spent_on_dependencies: Cell<Duration>,
pub paths: Vec<PathBuf>,
graph_nodes: RefCell<HashMap<String, NodeIndex>>,
graph: RefCell<Graph<String, bool>>,
parent: Cell<Option<NodeIndex>>,
}
impl<'a> Deref for Builder<'a> {
@ -146,18 +154,17 @@ impl StepDescription {
eprintln!("{:?} not skipped for {:?} -- not in {:?}", pathset,
self.name, builder.config.exclude);
}
let build = builder.build;
let hosts = &build.hosts;
let hosts = &builder.hosts;
// Determine the targets participating in this rule.
let targets = if self.only_hosts {
if !build.config.run_host_only {
if !builder.config.run_host_only {
return; // don't run anything
} else {
&build.hosts
&builder.hosts
}
} else {
&build.targets
&builder.targets
};
for host in hosts {
@ -303,7 +310,8 @@ impl<'a> Builder<'a> {
tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient,
tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy,
native::Llvm, tool::Rustfmt, tool::Miri, native::Lld),
Kind::Check => describe!(check::Std, check::Test, check::Rustc),
Kind::Check => describe!(check::Std, check::Test, check::Rustc, check::CodegenBackend,
check::Rustdoc),
Kind::Test => describe!(test::Tidy, test::Bootstrap, test::Ui, test::RunPass,
test::CompileFail, test::ParseFail, test::RunFail, test::RunPassValgrind,
test::MirOpt, test::Codegen, test::CodegenUnits, test::Incremental, test::Debuginfo,
@ -315,15 +323,15 @@ impl<'a> Builder<'a> {
test::Cargotest, test::Cargo, test::Rls, test::ErrorIndex, test::Distcheck,
test::RunMakeFullDeps,
test::Nomicon, test::Reference, test::RustdocBook, test::RustByExample,
test::TheBook, test::UnstableBook,
test::TheBook, test::UnstableBook, test::RustcBook,
test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme,
// Run run-make last, since these won't pass without make on Windows
test::RunMake),
test::RunMake, test::RustdocUi),
Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook,
doc::Standalone, doc::Std, doc::Test, doc::WhitelistedRustc, doc::Rustc,
doc::ErrorIndex, doc::Nomicon, doc::Reference, doc::Rustdoc, doc::RustByExample,
doc::CargoBook),
doc::RustcBook, doc::CargoBook),
Kind::Dist => describe!(dist::Docs, dist::RustcDocs, dist::Mingw, dist::Rustc,
dist::DebuggerScripts, dist::Std, dist::Analysis, dist::Src,
dist::PlainSourceTarball, dist::Cargo, dist::Rls, dist::Rustfmt, dist::Extended,
@ -351,6 +359,10 @@ impl<'a> Builder<'a> {
cache: Cache::new(),
stack: RefCell::new(Vec::new()),
time_spent_on_dependencies: Cell::new(Duration::new(0, 0)),
paths: vec![],
graph_nodes: RefCell::new(HashMap::new()),
graph: RefCell::new(Graph::new()),
parent: Cell::new(None),
};
let builder = &builder;
@ -367,7 +379,7 @@ impl<'a> Builder<'a> {
Some(help)
}
pub fn run(build: &Build) {
pub fn new(build: &Build) -> Builder {
let (kind, paths) = match build.config.cmd {
Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
Subcommand::Check { ref paths } => (Kind::Check, &paths[..]),
@ -379,12 +391,6 @@ impl<'a> Builder<'a> {
Subcommand::Clean { .. } => panic!(),
};
if let Some(path) = paths.get(0) {
if path == Path::new("nonexistent/path/to/trigger/cargo/metadata") {
return;
}
}
let builder = Builder {
build,
top_stage: build.config.stage.unwrap_or(2),
@ -392,20 +398,33 @@ impl<'a> Builder<'a> {
cache: Cache::new(),
stack: RefCell::new(Vec::new()),
time_spent_on_dependencies: Cell::new(Duration::new(0, 0)),
paths: paths.to_owned(),
graph_nodes: RefCell::new(HashMap::new()),
graph: RefCell::new(Graph::new()),
parent: Cell::new(None),
};
if kind == Kind::Dist {
assert!(!build.config.test_miri, "Do not distribute with miri enabled.\n\
assert!(!builder.config.test_miri, "Do not distribute with miri enabled.\n\
The distributed libraries would include all MIR (increasing binary size).
The distributed MIR would include validation statements.");
}
StepDescription::run(&Builder::get_step_descriptions(builder.kind), &builder, paths);
builder
}
pub fn execute_cli(&self) -> Graph<String, bool> {
self.run_step_descriptions(&Builder::get_step_descriptions(self.kind), &self.paths);
self.graph.borrow().clone()
}
pub fn default_doc(&self, paths: Option<&[PathBuf]>) {
let paths = paths.unwrap_or(&[]);
StepDescription::run(&Builder::get_step_descriptions(Kind::Doc), self, paths);
self.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), paths);
}
fn run_step_descriptions(&self, v: &[StepDescription], paths: &[PathBuf]) {
StepDescription::run(v, self, paths);
}
/// Obtain a compiler at a given stage and for a given host. Explicitly does
@ -457,7 +476,7 @@ impl<'a> Builder<'a> {
pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf {
self.sysroot_libdir(compiler, compiler.host)
.with_file_name(self.build.config.rust_codegen_backends_dir.clone())
.with_file_name(self.config.rust_codegen_backends_dir.clone())
}
/// Returns the compiler's libdir where it stores the dynamic libraries that
@ -467,7 +486,7 @@ impl<'a> Builder<'a> {
/// Windows.
pub fn rustc_libdir(&self, compiler: Compiler) -> PathBuf {
if compiler.is_snapshot(self) {
self.build.rustc_snapshot_libdir()
self.rustc_snapshot_libdir()
} else {
self.sysroot(compiler).join(libdir(&compiler.host))
}
@ -504,12 +523,12 @@ impl<'a> Builder<'a> {
let compiler = self.compiler(self.top_stage, host);
cmd.env("RUSTC_STAGE", compiler.stage.to_string())
.env("RUSTC_SYSROOT", self.sysroot(compiler))
.env("RUSTDOC_LIBDIR", self.sysroot_libdir(compiler, self.build.build))
.env("CFG_RELEASE_CHANNEL", &self.build.config.channel)
.env("RUSTDOC_LIBDIR", self.sysroot_libdir(compiler, self.config.build))
.env("CFG_RELEASE_CHANNEL", &self.config.channel)
.env("RUSTDOC_REAL", self.rustdoc(host))
.env("RUSTDOC_CRATE_VERSION", self.build.rust_version())
.env("RUSTDOC_CRATE_VERSION", self.rust_version())
.env("RUSTC_BOOTSTRAP", "1");
if let Some(linker) = self.build.linker(host) {
if let Some(linker) = self.linker(host) {
cmd.env("RUSTC_TARGET_LINKER", linker);
}
cmd
@ -534,6 +553,12 @@ impl<'a> Builder<'a> {
.arg("--target")
.arg(target);
// Set a flag for `check` so that certain build scripts can do less work
// (e.g. not building/requiring LLVM).
if cmd == "check" {
cargo.env("RUST_CHECK", "1");
}
// If we were invoked from `make` then that's already got a jobserver
// set up for us so no need to tell Cargo about jobs all over again.
if env::var_os("MAKEFLAGS").is_none() && env::var_os("MFLAGS").is_none() {
@ -566,6 +591,8 @@ impl<'a> Builder<'a> {
format!("{} {}", env::var("RUSTFLAGS").unwrap_or_default(), extra_args));
}
let want_rustdoc = self.doc_tests != DocTests::No;
// Customize the compiler we're running. Specify the compiler to cargo
// as our shim and then pass it some various options used to configure
// how the actual compiler itself is called.
@ -582,7 +609,7 @@ impl<'a> Builder<'a> {
.env("RUSTC_LIBDIR", self.rustc_libdir(compiler))
.env("RUSTC_RPATH", self.config.rust_rpath.to_string())
.env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
.env("RUSTDOC_REAL", if cmd == "doc" || cmd == "test" {
.env("RUSTDOC_REAL", if cmd == "doc" || (cmd == "test" && want_rustdoc) {
self.rustdoc(compiler.host)
} else {
PathBuf::from("/path/to/nowhere/rustdoc/not/required")
@ -590,23 +617,27 @@ impl<'a> Builder<'a> {
.env("TEST_MIRI", self.config.test_miri.to_string())
.env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir());
if let Some(host_linker) = self.build.linker(compiler.host) {
if let Some(host_linker) = self.linker(compiler.host) {
cargo.env("RUSTC_HOST_LINKER", host_linker);
}
if let Some(target_linker) = self.build.linker(target) {
if let Some(target_linker) = self.linker(target) {
cargo.env("RUSTC_TARGET_LINKER", target_linker);
}
if let Some(ref error_format) = self.config.rustc_error_format {
cargo.env("RUSTC_ERROR_FORMAT", error_format);
}
if cmd != "build" && cmd != "check" {
cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.build.build)));
if cmd != "build" && cmd != "check" && want_rustdoc {
cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.config.build)));
}
if mode != Mode::Tool {
// Tools don't get debuginfo right now, e.g. cargo and rls don't
// get compiled with debuginfo.
// Adding debuginfo increases their sizes by a factor of 3-4.
if mode == Mode::Tool {
// Tools like cargo and rls don't get debuginfo by default right now, but this can be
// enabled in the config. Adding debuginfo makes them several times larger.
if self.config.rust_debuginfo_tools {
cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string());
cargo.env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string());
}
} else {
cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string());
cargo.env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string());
cargo.env("RUSTC_FORCE_UNSTABLE", "1");
@ -654,7 +685,7 @@ impl<'a> Builder<'a> {
//
// If LLVM support is disabled we need to use the snapshot compiler to compile
// build scripts, as the new compiler doesn't support executables.
if mode == Mode::Libstd || !self.build.config.llvm_enabled {
if mode == Mode::Libstd || !self.config.llvm_enabled {
cargo.env("RUSTC_SNAPSHOT", &self.initial_rustc)
.env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir());
} else {
@ -677,8 +708,17 @@ impl<'a> Builder<'a> {
cargo.env("RUSTC_PRINT_STEP_TIMINGS", "1");
}
if self.config.backtrace_on_ice {
cargo.env("RUSTC_BACKTRACE_ON_ICE", "1");
}
cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity));
// in std, we want to avoid denying warnings for stage 0 as that makes cfg's painful.
if self.config.deny_warnings && !(mode == Mode::Libstd && stage == 0) {
cargo.env("RUSTC_DENY_WARNINGS", "1");
}
// Throughout the build Cargo can execute a number of build scripts
// compiling C/C++ code and we need to pass compilers, archivers, flags, etc
// obtained previously to those build scripts.
@ -728,12 +768,14 @@ impl<'a> Builder<'a> {
}
}
if mode == Mode::Libstd && self.config.extended && compiler.is_final_stage(self) {
if cmd == "build" && mode == Mode::Libstd
&& self.config.extended && compiler.is_final_stage(self)
{
cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string());
}
// For `cargo doc` invocations, make rustdoc print the Rust version into the docs
cargo.env("RUSTDOC_CRATE_VERSION", self.build.rust_version());
cargo.env("RUSTDOC_CRATE_VERSION", self.rust_version());
// Environment variables *required* throughout the build
//
@ -741,7 +783,7 @@ impl<'a> Builder<'a> {
cargo.env("CFG_COMPILER_HOST_TRIPLE", target);
// Set this for all builds to make sure doc builds also get it.
cargo.env("CFG_RELEASE_CHANNEL", &self.build.config.channel);
cargo.env("CFG_RELEASE_CHANNEL", &self.config.channel);
// This one's a bit tricky. As of the time of this writing the compiler
// links to the `winapi` crate on crates.io. This crate provides raw
@ -807,7 +849,7 @@ impl<'a> Builder<'a> {
cargo
}
/// Ensure that a given step is built, returning it's output. This will
/// Ensure that a given step is built, returning its output. This will
/// cache the step, so it is safe (and good!) to call this as often as
/// needed to ensure that all dependencies are built.
pub fn ensure<S: Step>(&'a self, step: S) -> S::Output {
@ -826,14 +868,39 @@ impl<'a> Builder<'a> {
panic!(out);
}
if let Some(out) = self.cache.get(&step) {
self.build.verbose(&format!("{}c {:?}", " ".repeat(stack.len()), step));
self.verbose(&format!("{}c {:?}", " ".repeat(stack.len()), step));
{
let mut graph = self.graph.borrow_mut();
let parent = self.parent.get();
let us = *self.graph_nodes.borrow_mut()
.entry(format!("{:?}", step))
.or_insert_with(|| graph.add_node(format!("{:?}", step)));
if let Some(parent) = parent {
graph.add_edge(parent, us, false);
}
}
return out;
}
self.build.verbose(&format!("{}> {:?}", " ".repeat(stack.len()), step));
self.verbose(&format!("{}> {:?}", " ".repeat(stack.len()), step));
stack.push(Box::new(step.clone()));
}
let prev_parent = self.parent.get();
{
let mut graph = self.graph.borrow_mut();
let parent = self.parent.get();
let us = *self.graph_nodes.borrow_mut()
.entry(format!("{:?}", step))
.or_insert_with(|| graph.add_node(format!("{:?}", step)));
self.parent.set(Some(us));
if let Some(parent) = parent {
graph.add_edge(parent, us, true);
}
}
let (out, dur) = {
let start = Instant::now();
let zero = Duration::new(0, 0);
@ -844,7 +911,9 @@ impl<'a> Builder<'a> {
(out, dur - deps)
};
if self.build.config.print_step_timings && dur > Duration::from_millis(100) {
self.parent.set(prev_parent);
if self.config.print_step_timings && dur > Duration::from_millis(100) {
println!("[TIMING] {:?} -- {}.{:03}",
step,
dur.as_secs(),
@ -856,8 +925,523 @@ impl<'a> Builder<'a> {
let cur_step = stack.pop().expect("step stack empty");
assert_eq!(cur_step.downcast_ref(), Some(&step));
}
self.build.verbose(&format!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step));
self.verbose(&format!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step));
self.cache.put(step, out.clone());
out
}
}
#[cfg(test)]
mod __test {
use config::Config;
use std::thread;
use super::*;
fn configure(host: &[&str], target: &[&str]) -> Config {
let mut config = Config::default_opts();
// don't save toolstates
config.save_toolstates = None;
config.run_host_only = true;
config.dry_run = true;
// try to avoid spurious failures in dist where we create/delete each others file
let dir = config.out.join("tmp-rustbuild-tests")
.join(&thread::current().name().unwrap_or("unknown").replace(":", "-"));
t!(fs::create_dir_all(&dir));
config.out = dir;
config.build = INTERNER.intern_str("A");
config.hosts = vec![config.build].clone().into_iter()
.chain(host.iter().map(|s| INTERNER.intern_str(s))).collect::<Vec<_>>();
config.targets = config.hosts.clone().into_iter()
.chain(target.iter().map(|s| INTERNER.intern_str(s))).collect::<Vec<_>>();
config
}
fn first<A, B>(v: Vec<(A, B)>) -> Vec<A> {
v.into_iter().map(|(a, _)| a).collect::<Vec<_>>()
}
#[test]
fn dist_baseline() {
let build = Build::new(configure(&[], &[]));
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
let a = INTERNER.intern_str("A");
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
dist::Docs { stage: 2, host: a },
]);
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
dist::Mingw { host: a },
]);
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
]);
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
]);
assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
}
#[test]
fn dist_with_targets() {
let build = Build::new(configure(&[], &["B"]));
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
let a = INTERNER.intern_str("A");
let b = INTERNER.intern_str("B");
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
dist::Docs { stage: 2, host: a },
dist::Docs { stage: 2, host: b },
]);
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
dist::Mingw { host: a },
dist::Mingw { host: b },
]);
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
]);
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
]);
assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
}
#[test]
fn dist_with_hosts() {
let build = Build::new(configure(&["B"], &[]));
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
let a = INTERNER.intern_str("A");
let b = INTERNER.intern_str("B");
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
dist::Docs { stage: 2, host: a },
dist::Docs { stage: 2, host: b },
]);
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
dist::Mingw { host: a },
dist::Mingw { host: b },
]);
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
]);
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
]);
assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
}
#[test]
fn dist_with_targets_and_hosts() {
let build = Build::new(configure(&["B"], &["C"]));
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
let a = INTERNER.intern_str("A");
let b = INTERNER.intern_str("B");
let c = INTERNER.intern_str("C");
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
dist::Docs { stage: 2, host: a },
dist::Docs { stage: 2, host: b },
dist::Docs { stage: 2, host: c },
]);
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
dist::Mingw { host: a },
dist::Mingw { host: b },
dist::Mingw { host: c },
]);
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
]);
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: c,
},
]);
assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
}
#[test]
fn dist_with_target_flag() {
let mut config = configure(&["B"], &["C"]);
config.run_host_only = false; // as-if --target=C was passed
let build = Build::new(config);
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
let a = INTERNER.intern_str("A");
let b = INTERNER.intern_str("B");
let c = INTERNER.intern_str("C");
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
dist::Docs { stage: 2, host: a },
dist::Docs { stage: 2, host: b },
dist::Docs { stage: 2, host: c },
]);
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
dist::Mingw { host: a },
dist::Mingw { host: b },
dist::Mingw { host: c },
]);
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[]);
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: c,
},
]);
assert_eq!(first(builder.cache.all::<dist::Src>()), &[]);
}
#[test]
fn dist_with_same_targets_and_hosts() {
let build = Build::new(configure(&["B"], &["B"]));
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
let a = INTERNER.intern_str("A");
let b = INTERNER.intern_str("B");
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[
dist::Docs { stage: 2, host: a },
dist::Docs { stage: 2, host: b },
]);
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[
dist::Mingw { host: a },
dist::Mingw { host: b },
]);
assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
]);
assert_eq!(first(builder.cache.all::<dist::Std>()), &[
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
dist::Std {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
]);
assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
assert_eq!(first(builder.cache.all::<compile::Std>()), &[
compile::Std {
compiler: Compiler { host: a, stage: 0 },
target: a,
},
compile::Std {
compiler: Compiler { host: a, stage: 1 },
target: a,
},
compile::Std {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
compile::Std {
compiler: Compiler { host: a, stage: 1 },
target: b,
},
compile::Std {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
]);
assert_eq!(first(builder.cache.all::<compile::Test>()), &[
compile::Test {
compiler: Compiler { host: a, stage: 0 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 1 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 1 },
target: b,
},
compile::Test {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
]);
assert_eq!(first(builder.cache.all::<compile::Assemble>()), &[
compile::Assemble {
target_compiler: Compiler { host: a, stage: 0 },
},
compile::Assemble {
target_compiler: Compiler { host: a, stage: 1 },
},
compile::Assemble {
target_compiler: Compiler { host: a, stage: 2 },
},
compile::Assemble {
target_compiler: Compiler { host: b, stage: 2 },
},
]);
}
#[test]
fn build_default() {
let build = Build::new(configure(&["B"], &["C"]));
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
let a = INTERNER.intern_str("A");
let b = INTERNER.intern_str("B");
let c = INTERNER.intern_str("C");
assert!(!builder.cache.all::<compile::Std>().is_empty());
assert!(!builder.cache.all::<compile::Assemble>().is_empty());
assert_eq!(first(builder.cache.all::<compile::Rustc>()), &[
compile::Rustc {
compiler: Compiler { host: a, stage: 0 },
target: a,
},
compile::Rustc {
compiler: Compiler { host: a, stage: 1 },
target: a,
},
compile::Rustc {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
compile::Rustc {
compiler: Compiler { host: b, stage: 2 },
target: a,
},
compile::Rustc {
compiler: Compiler { host: a, stage: 0 },
target: b,
},
compile::Rustc {
compiler: Compiler { host: a, stage: 1 },
target: b,
},
compile::Rustc {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
compile::Rustc {
compiler: Compiler { host: b, stage: 2 },
target: b,
},
]);
assert_eq!(first(builder.cache.all::<compile::Test>()), &[
compile::Test {
compiler: Compiler { host: a, stage: 0 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 1 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
compile::Test {
compiler: Compiler { host: b, stage: 2 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 0 },
target: b,
},
compile::Test {
compiler: Compiler { host: a, stage: 1 },
target: b,
},
compile::Test {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
compile::Test {
compiler: Compiler { host: b, stage: 2 },
target: b,
},
compile::Test {
compiler: Compiler { host: a, stage: 2 },
target: c,
},
compile::Test {
compiler: Compiler { host: b, stage: 2 },
target: c,
},
]);
}
#[test]
fn build_with_target_flag() {
let mut config = configure(&["B"], &["C"]);
config.run_host_only = false;
let build = Build::new(config);
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
let a = INTERNER.intern_str("A");
let b = INTERNER.intern_str("B");
let c = INTERNER.intern_str("C");
assert!(!builder.cache.all::<compile::Std>().is_empty());
assert_eq!(first(builder.cache.all::<compile::Assemble>()), &[
compile::Assemble {
target_compiler: Compiler { host: a, stage: 0 },
},
compile::Assemble {
target_compiler: Compiler { host: a, stage: 1 },
},
compile::Assemble {
target_compiler: Compiler { host: b, stage: 1 },
},
compile::Assemble {
target_compiler: Compiler { host: a, stage: 2 },
},
compile::Assemble {
target_compiler: Compiler { host: b, stage: 2 },
},
]);
assert_eq!(first(builder.cache.all::<compile::Rustc>()), &[
compile::Rustc {
compiler: Compiler { host: a, stage: 0 },
target: a,
},
compile::Rustc {
compiler: Compiler { host: a, stage: 1 },
target: a,
},
compile::Rustc {
compiler: Compiler { host: a, stage: 0 },
target: b,
},
compile::Rustc {
compiler: Compiler { host: a, stage: 1 },
target: b,
},
]);
assert_eq!(first(builder.cache.all::<compile::Test>()), &[
compile::Test {
compiler: Compiler { host: a, stage: 0 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 1 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 2 },
target: a,
},
compile::Test {
compiler: Compiler { host: b, stage: 2 },
target: a,
},
compile::Test {
compiler: Compiler { host: a, stage: 0 },
target: b,
},
compile::Test {
compiler: Compiler { host: a, stage: 1 },
target: b,
},
compile::Test {
compiler: Compiler { host: a, stage: 2 },
target: b,
},
compile::Test {
compiler: Compiler { host: b, stage: 2 },
target: b,
},
compile::Test {
compiler: Compiler { host: a, stage: 2 },
target: c,
},
compile::Test {
compiler: Compiler { host: b, stage: 2 },
target: c,
},
]);
}
#[test]
fn test_with_no_doc_stage0() {
let mut config = configure(&[], &[]);
config.stage = Some(0);
config.cmd = Subcommand::Test {
paths: vec!["src/libstd".into()],
test_args: vec![],
rustc_args: vec![],
fail_fast: true,
doc_tests: DocTests::No,
};
let build = Build::new(config);
let mut builder = Builder::new(&build);
let host = INTERNER.intern_str("A");
builder.run_step_descriptions(
&[StepDescription::from::<test::Crate>()],
&["src/libstd".into()],
);
// Ensure we don't build any compiler artifacts.
assert!(builder.cache.all::<compile::Rustc>().is_empty());
assert_eq!(first(builder.cache.all::<test::Crate>()), &[
test::Crate {
compiler: Compiler { host, stage: 0 },
target: host,
mode: Mode::Libstd,
test_kind: test::TestKind::Test,
krate: INTERNER.intern_str("std"),
},
]);
}
}

View File

@ -21,6 +21,7 @@ use std::mem;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::sync::Mutex;
use std::cmp::{PartialOrd, Ord, Ordering};
use builder::Step;
@ -154,6 +155,19 @@ impl AsRef<OsStr> for Interned<String> {
}
}
impl PartialOrd<Interned<String>> for Interned<String> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let l = INTERNER.strs.lock().unwrap();
l.get(*self).partial_cmp(l.get(*other))
}
}
impl Ord for Interned<String> {
fn cmp(&self, other: &Self) -> Ordering {
let l = INTERNER.strs.lock().unwrap();
l.get(*self).cmp(l.get(*other))
}
}
struct TyIntern<T> {
items: Vec<T>,
@ -264,4 +278,16 @@ impl Cache {
.expect("invalid type mapped");
stepcache.get(step).cloned()
}
#[cfg(test)]
pub fn all<S: Ord + Copy + Step>(&mut self) -> Vec<(S, S::Output)> {
let cache = self.0.get_mut();
let type_id = TypeId::of::<S>();
let mut v = cache.remove(&type_id)
.map(|b| b.downcast::<HashMap<S, S::Output>>().expect("correct type"))
.map(|m| m.into_iter().collect::<Vec<_>>())
.unwrap_or_default();
v.sort_by_key(|&(a, _)| a);
v
}
}

View File

@ -79,8 +79,16 @@ pub fn find(build: &mut Build) {
let mut cfg = cc::Build::new();
cfg.cargo_metadata(false).opt_level(2).warnings(false).debug(false)
.target(&target).host(&build.build);
if target.contains("msvc") {
cfg.static_crt(true);
match build.crt_static(target) {
Some(a) => { cfg.static_crt(a); }
None => {
if target.contains("msvc") {
cfg.static_crt(true);
}
if target.contains("musl") {
cfg.static_flag(true);
}
}
}
let config = build.config.target_config.get(&target);
@ -97,8 +105,9 @@ pub fn find(build: &mut Build) {
cc2ar(compiler.path(), &target)
};
build.verbose(&format!("CC_{} = {:?}", &target, compiler.path()));
build.cc.insert(target, compiler);
build.verbose(&format!("CC_{} = {:?}", &target, build.cc(target)));
build.verbose(&format!("CFLAGS_{} = {:?}", &target, build.cflags(target)));
if let Some(ar) = ar {
build.verbose(&format!("AR_{} = {:?}", &target, ar));
build.ar.insert(target, ar);

View File

@ -24,7 +24,7 @@ use Build;
use config::Config;
// The version number
pub const CFG_RELEASE_NUM: &str = "1.26.2";
pub const CFG_RELEASE_NUM: &str = "1.27.1";
pub struct GitInfo {
inner: Option<Info>,

View File

@ -10,10 +10,11 @@
//! Implementation of compiling the compiler and standard library, in "check" mode.
use compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, add_to_sysroot};
use compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, rustc_cargo_env, add_to_sysroot};
use builder::{RunConfig, Builder, ShouldRun, Step};
use {Build, Compiler, Mode};
use cache::Interned;
use tool::{self, prepare_tool_cargo};
use {Compiler, Mode};
use cache::{INTERNER, Interned};
use std::path::PathBuf;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@ -36,24 +37,24 @@ impl Step for Std {
}
fn run(self, builder: &Builder) {
let build = builder.build;
let target = self.target;
let compiler = builder.compiler(0, build.build);
let compiler = builder.compiler(0, builder.config.build);
let out_dir = builder.stage_out(compiler, Mode::Libstd);
builder.clear_if_dirty(&out_dir, &builder.rustc(compiler));
let out_dir = build.stage_out(compiler, Mode::Libstd);
build.clear_if_dirty(&out_dir, &builder.rustc(compiler));
let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "check");
std_cargo(builder, &compiler, target, &mut cargo);
let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage));
let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage));
println!("Checking std artifacts ({} -> {})", &compiler.host, target);
run_cargo(build,
run_cargo(builder,
&mut cargo,
&libstd_stamp(build, compiler, target),
&libstd_stamp(builder, compiler, target),
true);
let libdir = builder.sysroot_libdir(compiler, target);
add_to_sysroot(&libdir, &libstd_stamp(build, compiler, target));
add_to_sysroot(&builder, &libdir, &libstd_stamp(builder, compiler, target));
}
}
@ -83,26 +84,71 @@ impl Step for Rustc {
/// the `compiler` targeting the `target` architecture. The artifacts
/// created will also be linked into the sysroot directory.
fn run(self, builder: &Builder) {
let build = builder.build;
let compiler = builder.compiler(0, build.build);
let compiler = builder.compiler(0, builder.config.build);
let target = self.target;
let stage_out = builder.stage_out(compiler, Mode::Librustc);
build.clear_if_dirty(&stage_out, &libstd_stamp(build, compiler, target));
build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target));
builder.clear_if_dirty(&stage_out, &libstd_stamp(builder, compiler, target));
builder.clear_if_dirty(&stage_out, &libtest_stamp(builder, compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check");
rustc_cargo(build, &mut cargo);
rustc_cargo(builder, &mut cargo);
let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage));
let _folder = builder.fold_output(|| format!("stage{}-rustc", compiler.stage));
println!("Checking compiler artifacts ({} -> {})", &compiler.host, target);
run_cargo(build,
run_cargo(builder,
&mut cargo,
&librustc_stamp(build, compiler, target),
&librustc_stamp(builder, compiler, target),
true);
let libdir = builder.sysroot_libdir(compiler, target);
add_to_sysroot(&libdir, &librustc_stamp(build, compiler, target));
add_to_sysroot(&builder, &libdir, &librustc_stamp(builder, compiler, target));
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CodegenBackend {
pub target: Interned<String>,
pub backend: Interned<String>,
}
impl Step for CodegenBackend {
type Output = ();
const ONLY_HOSTS: bool = true;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.all_krates("rustc_trans")
}
fn make_run(run: RunConfig) {
let backend = run.builder.config.rust_codegen_backends.get(0);
let backend = backend.cloned().unwrap_or_else(|| {
INTERNER.intern_str("llvm")
});
run.builder.ensure(CodegenBackend {
target: run.target,
backend,
});
}
fn run(self, builder: &Builder) {
let compiler = builder.compiler(0, builder.config.build);
let target = self.target;
let backend = self.backend;
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check");
let features = builder.rustc_features().to_string();
cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_trans/Cargo.toml"));
rustc_cargo_env(builder, &mut cargo);
// We won't build LLVM if it's not available, as it shouldn't affect `check`.
let _folder = builder.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
run_cargo(builder,
cargo.arg("--features").arg(features),
&codegen_backend_stamp(builder, compiler, target, backend),
true);
}
}
@ -126,41 +172,105 @@ impl Step for Test {
}
fn run(self, builder: &Builder) {
let build = builder.build;
let compiler = builder.compiler(0, builder.config.build);
let target = self.target;
let compiler = builder.compiler(0, build.build);
let out_dir = build.stage_out(compiler, Mode::Libtest);
build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
let out_dir = builder.stage_out(compiler, Mode::Libtest);
builder.clear_if_dirty(&out_dir, &libstd_stamp(builder, compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "check");
test_cargo(build, &compiler, target, &mut cargo);
test_cargo(builder, &compiler, target, &mut cargo);
let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage));
let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage));
println!("Checking test artifacts ({} -> {})", &compiler.host, target);
run_cargo(build,
run_cargo(builder,
&mut cargo,
&libtest_stamp(build, compiler, target),
&libtest_stamp(builder, compiler, target),
true);
let libdir = builder.sysroot_libdir(compiler, target);
add_to_sysroot(&libdir, &libtest_stamp(build, compiler, target));
add_to_sysroot(builder, &libdir, &libtest_stamp(builder, compiler, target));
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rustdoc {
pub target: Interned<String>,
}
impl Step for Rustdoc {
type Output = ();
const ONLY_HOSTS: bool = true;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
run.path("src/tools/rustdoc")
}
fn make_run(run: RunConfig) {
run.builder.ensure(Rustdoc {
target: run.target,
});
}
fn run(self, builder: &Builder) {
let compiler = builder.compiler(0, builder.config.build);
let target = self.target;
let mut cargo = prepare_tool_cargo(builder,
compiler,
target,
"check",
"src/tools/rustdoc");
let _folder = builder.fold_output(|| format!("stage{}-rustdoc", compiler.stage));
println!("Checking rustdoc artifacts ({} -> {})", &compiler.host, target);
run_cargo(builder,
&mut cargo,
&rustdoc_stamp(builder, compiler, target),
true);
let libdir = builder.sysroot_libdir(compiler, target);
add_to_sysroot(&builder, &libdir, &rustdoc_stamp(builder, compiler, target));
builder.ensure(tool::CleanTools {
compiler,
target,
mode: Mode::Tool,
});
}
}
/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
pub fn libstd_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
build.cargo_out(compiler, Mode::Libstd, target).join(".libstd-check.stamp")
pub fn libstd_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
builder.cargo_out(compiler, Mode::Libstd, target).join(".libstd-check.stamp")
}
/// Cargo's output path for libtest in a given stage, compiled by a particular
/// compiler for the specified target.
pub fn libtest_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
build.cargo_out(compiler, Mode::Libtest, target).join(".libtest-check.stamp")
pub fn libtest_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
builder.cargo_out(compiler, Mode::Libtest, target).join(".libtest-check.stamp")
}
/// Cargo's output path for librustc in a given stage, compiled by a particular
/// compiler for the specified target.
pub fn librustc_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
build.cargo_out(compiler, Mode::Librustc, target).join(".librustc-check.stamp")
pub fn librustc_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
builder.cargo_out(compiler, Mode::Librustc, target).join(".librustc-check.stamp")
}
/// Cargo's output path for librustc_trans in a given stage, compiled by a particular
/// compiler for the specified target and backend.
fn codegen_backend_stamp(builder: &Builder,
compiler: Compiler,
target: Interned<String>,
backend: Interned<String>) -> PathBuf {
builder.cargo_out(compiler, Mode::Librustc, target)
.join(format!(".librustc_trans-{}-check.stamp", backend))
}
/// Cargo's output path for rustdoc in a given stage, compiled by a particular
/// compiler for the specified target.
pub fn rustdoc_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
builder.cargo_out(compiler, Mode::Tool, target).join(".rustdoc-check.stamp")
}

View File

@ -30,15 +30,15 @@ use build_helper::{output, mtime, up_to_date};
use filetime::FileTime;
use serde_json;
use util::{exe, libdir, is_dylib, copy, read_stamp_file, CiEnv};
use {Build, Compiler, Mode};
use util::{exe, libdir, is_dylib, CiEnv};
use {Compiler, Mode};
use native;
use tool;
use cache::{INTERNER, Interned};
use builder::{Step, RunConfig, ShouldRun, Builder};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Std {
pub target: Interned<String>,
pub compiler: Compiler,
@ -65,25 +65,24 @@ impl Step for Std {
/// using the `compiler` targeting the `target` architecture. The artifacts
/// created will also be linked into the sysroot directory.
fn run(self, builder: &Builder) {
let build = builder.build;
let target = self.target;
let compiler = self.compiler;
builder.ensure(StartupObjects { compiler, target });
if build.force_use_stage1(compiler, target) {
let from = builder.compiler(1, build.build);
if builder.force_use_stage1(compiler, target) {
let from = builder.compiler(1, builder.config.build);
builder.ensure(Std {
compiler: from,
target,
});
println!("Uplifting stage1 std ({} -> {})", from.host, target);
builder.info(&format!("Uplifting stage1 std ({} -> {})", from.host, target));
// Even if we're not building std this stage, the new sysroot must
// still contain the musl startup objects.
if target.contains("musl") {
let libdir = builder.sysroot_libdir(compiler, target);
copy_musl_third_party_objects(build, target, &libdir);
copy_musl_third_party_objects(builder, target, &libdir);
}
builder.ensure(StdLink {
@ -96,24 +95,24 @@ impl Step for Std {
if target.contains("musl") {
let libdir = builder.sysroot_libdir(compiler, target);
copy_musl_third_party_objects(build, target, &libdir);
copy_musl_third_party_objects(builder, target, &libdir);
}
let out_dir = build.cargo_out(compiler, Mode::Libstd, target);
build.clear_if_dirty(&out_dir, &builder.rustc(compiler));
let out_dir = builder.cargo_out(compiler, Mode::Libstd, target);
builder.clear_if_dirty(&out_dir, &builder.rustc(compiler));
let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "build");
std_cargo(builder, &compiler, target, &mut cargo);
let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage));
println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
&compiler.host, target);
run_cargo(build,
let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage));
builder.info(&format!("Building stage{} std artifacts ({} -> {})", compiler.stage,
&compiler.host, target));
run_cargo(builder,
&mut cargo,
&libstd_stamp(build, compiler, target),
&libstd_stamp(builder, compiler, target),
false);
builder.ensure(StdLink {
compiler: builder.compiler(compiler.stage, build.build),
compiler: builder.compiler(compiler.stage, builder.config.build),
target_compiler: compiler,
target,
});
@ -126,62 +125,72 @@ impl Step for Std {
/// with a glibc-targeting toolchain, given we have the appropriate startup
/// files. As those shipped with glibc won't work, copy the ones provided by
/// musl so we have them on linux-gnu hosts.
fn copy_musl_third_party_objects(build: &Build,
fn copy_musl_third_party_objects(builder: &Builder,
target: Interned<String>,
into: &Path) {
for &obj in &["crt1.o", "crti.o", "crtn.o"] {
copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj));
builder.copy(&builder.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj));
}
}
/// Configure cargo to compile the standard library, adding appropriate env vars
/// and such.
pub fn std_cargo(build: &Builder,
pub fn std_cargo(builder: &Builder,
compiler: &Compiler,
target: Interned<String>,
cargo: &mut Command) {
let mut features = build.std_features();
if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
}
// When doing a local rebuild we tell cargo that we're stage1 rather than
// stage0. This works fine if the local rust and being-built rust have the
// same view of what the default allocator is, but fails otherwise. Since
// we don't have a way to express an allocator preference yet, work
// around the issue in the case of a local rebuild with jemalloc disabled.
if compiler.stage == 0 && build.local_rebuild && !build.config.use_jemalloc {
features.push_str(" force_alloc_system");
}
if builder.no_std(target) == Some(true) {
// for no-std targets we only compile a few no_std crates
cargo.arg("--features").arg("c mem")
.args(&["-p", "alloc"])
.args(&["-p", "compiler_builtins"])
.args(&["-p", "std_unicode"])
.arg("--manifest-path")
.arg(builder.src.join("src/rustc/compiler_builtins_shim/Cargo.toml"));
} else {
let mut features = builder.std_features();
if compiler.stage != 0 && build.config.sanitizers {
// This variable is used by the sanitizer runtime crates, e.g.
// rustc_lsan, to build the sanitizer runtime from C code
// When this variable is missing, those crates won't compile the C code,
// so we don't set this variable during stage0 where llvm-config is
// missing
// We also only build the runtimes when --enable-sanitizers (or its
// config.toml equivalent) is used
let llvm_config = build.ensure(native::Llvm {
target: build.config.build,
emscripten: false,
});
cargo.env("LLVM_CONFIG", llvm_config);
}
cargo.arg("--features").arg(features)
.arg("--manifest-path")
.arg(build.src.join("src/libstd/Cargo.toml"));
if let Some(target) = build.config.target_config.get(&target) {
if let Some(ref jemalloc) = target.jemalloc {
cargo.env("JEMALLOC_OVERRIDE", jemalloc);
// When doing a local rebuild we tell cargo that we're stage1 rather than
// stage0. This works fine if the local rust and being-built rust have the
// same view of what the default allocator is, but fails otherwise. Since
// we don't have a way to express an allocator preference yet, work
// around the issue in the case of a local rebuild with jemalloc disabled.
if compiler.stage == 0 && builder.local_rebuild && !builder.config.use_jemalloc {
features.push_str(" force_alloc_system");
}
}
if target.contains("musl") {
if let Some(p) = build.musl_root(target) {
cargo.env("MUSL_ROOT", p);
if compiler.stage != 0 && builder.config.sanitizers {
// This variable is used by the sanitizer runtime crates, e.g.
// rustc_lsan, to build the sanitizer runtime from C code
// When this variable is missing, those crates won't compile the C code,
// so we don't set this variable during stage0 where llvm-config is
// missing
// We also only build the runtimes when --enable-sanitizers (or its
// config.toml equivalent) is used
let llvm_config = builder.ensure(native::Llvm {
target: builder.config.build,
emscripten: false,
});
cargo.env("LLVM_CONFIG", llvm_config);
}
cargo.arg("--features").arg(features)
.arg("--manifest-path")
.arg(builder.src.join("src/libstd/Cargo.toml"));
if let Some(target) = builder.config.target_config.get(&target) {
if let Some(ref jemalloc) = target.jemalloc {
cargo.env("JEMALLOC_OVERRIDE", jemalloc);
}
}
if target.contains("musl") {
if let Some(p) = builder.musl_root(target) {
cargo.env("MUSL_ROOT", p);
}
}
}
}
@ -209,24 +218,23 @@ impl Step for StdLink {
/// libraries for `target`, and this method will find them in the relevant
/// output directory.
fn run(self, builder: &Builder) {
let build = builder.build;
let compiler = self.compiler;
let target_compiler = self.target_compiler;
let target = self.target;
println!("Copying stage{} std from stage{} ({} -> {} / {})",
builder.info(&format!("Copying stage{} std from stage{} ({} -> {} / {})",
target_compiler.stage,
compiler.stage,
&compiler.host,
target_compiler.host,
target);
target));
let libdir = builder.sysroot_libdir(target_compiler, target);
add_to_sysroot(&libdir, &libstd_stamp(build, compiler, target));
add_to_sysroot(builder, &libdir, &libstd_stamp(builder, compiler, target));
if build.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" {
if builder.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" {
// The sanitizers are only built in stage1 or above, so the dylibs will
// be missing in stage0 and causes panic. See the `std()` function above
// for reason why the sanitizers are not built in stage0.
copy_apple_sanitizer_dylibs(&build.native_dir(target), "osx", &libdir);
copy_apple_sanitizer_dylibs(builder, &builder.native_dir(target), "osx", &libdir);
}
builder.ensure(tool::CleanTools {
@ -237,7 +245,7 @@ impl Step for StdLink {
}
}
fn copy_apple_sanitizer_dylibs(native_dir: &Path, platform: &str, into: &Path) {
fn copy_apple_sanitizer_dylibs(builder: &Builder, native_dir: &Path, platform: &str, into: &Path) {
for &sanitizer in &["asan", "tsan"] {
let filename = format!("libclang_rt.{}_{}_dynamic.dylib", sanitizer, platform);
let mut src_path = native_dir.join(sanitizer);
@ -245,7 +253,7 @@ fn copy_apple_sanitizer_dylibs(native_dir: &Path, platform: &str, into: &Path) {
src_path.push("lib");
src_path.push("darwin");
src_path.push(&filename);
copy(&src_path, &into.join(filename));
builder.copy(&src_path, &into.join(filename));
}
}
@ -276,15 +284,14 @@ impl Step for StartupObjects {
/// files, so we just use the nightly snapshot compiler to always build them (as
/// no other compilers are guaranteed to be available).
fn run(self, builder: &Builder) {
let build = builder.build;
let for_compiler = self.compiler;
let target = self.target;
if !target.contains("pc-windows-gnu") {
return
}
let src_dir = &build.src.join("src/rtstartup");
let dst_dir = &build.native_dir(target).join("rtstartup");
let src_dir = &builder.src.join("src/rtstartup");
let dst_dir = &builder.native_dir(target).join("rtstartup");
let sysroot_dir = &builder.sysroot_libdir(for_compiler, target);
t!(fs::create_dir_all(dst_dir));
@ -292,8 +299,8 @@ impl Step for StartupObjects {
let src_file = &src_dir.join(file.to_string() + ".rs");
let dst_file = &dst_dir.join(file.to_string() + ".o");
if !up_to_date(src_file, dst_file) {
let mut cmd = Command::new(&build.initial_rustc);
build.run(cmd.env("RUSTC_BOOTSTRAP", "1")
let mut cmd = Command::new(&builder.initial_rustc);
builder.run(cmd.env("RUSTC_BOOTSTRAP", "1")
.arg("--cfg").arg("stage0")
.arg("--target").arg(target)
.arg("--emit=obj")
@ -301,23 +308,23 @@ impl Step for StartupObjects {
.arg(src_file));
}
copy(dst_file, &sysroot_dir.join(file.to_string() + ".o"));
builder.copy(dst_file, &sysroot_dir.join(file.to_string() + ".o"));
}
for obj in ["crt2.o", "dllcrt2.o"].iter() {
let src = compiler_file(build,
build.cc(target),
let src = compiler_file(builder,
builder.cc(target),
target,
obj);
copy(&src, &sysroot_dir.join(obj));
builder.copy(&src, &sysroot_dir.join(obj));
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Test {
pub compiler: Compiler,
pub target: Interned<String>,
pub compiler: Compiler,
}
impl Step for Test {
@ -341,41 +348,41 @@ impl Step for Test {
/// the build using the `compiler` targeting the `target` architecture. The
/// artifacts created will also be linked into the sysroot directory.
fn run(self, builder: &Builder) {
let build = builder.build;
let target = self.target;
let compiler = self.compiler;
builder.ensure(Std { compiler, target });
if build.force_use_stage1(compiler, target) {
if builder.force_use_stage1(compiler, target) {
builder.ensure(Test {
compiler: builder.compiler(1, build.build),
compiler: builder.compiler(1, builder.config.build),
target,
});
println!("Uplifting stage1 test ({} -> {})", &build.build, target);
builder.info(
&format!("Uplifting stage1 test ({} -> {})", builder.config.build, target));
builder.ensure(TestLink {
compiler: builder.compiler(1, build.build),
compiler: builder.compiler(1, builder.config.build),
target_compiler: compiler,
target,
});
return;
}
let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
let out_dir = builder.cargo_out(compiler, Mode::Libtest, target);
builder.clear_if_dirty(&out_dir, &libstd_stamp(builder, compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "build");
test_cargo(build, &compiler, target, &mut cargo);
test_cargo(builder, &compiler, target, &mut cargo);
let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage));
println!("Building stage{} test artifacts ({} -> {})", compiler.stage,
&compiler.host, target);
run_cargo(build,
let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage));
builder.info(&format!("Building stage{} test artifacts ({} -> {})", compiler.stage,
&compiler.host, target));
run_cargo(builder,
&mut cargo,
&libtest_stamp(build, compiler, target),
&libtest_stamp(builder, compiler, target),
false);
builder.ensure(TestLink {
compiler: builder.compiler(compiler.stage, build.build),
compiler: builder.compiler(compiler.stage, builder.config.build),
target_compiler: compiler,
target,
});
@ -383,7 +390,7 @@ impl Step for Test {
}
/// Same as `std_cargo`, but for libtest
pub fn test_cargo(build: &Build,
pub fn test_cargo(builder: &Builder,
_compiler: &Compiler,
_target: Interned<String>,
cargo: &mut Command) {
@ -391,7 +398,7 @@ pub fn test_cargo(build: &Build,
cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
}
cargo.arg("--manifest-path")
.arg(build.src.join("src/libtest/Cargo.toml"));
.arg(builder.src.join("src/libtest/Cargo.toml"));
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@ -410,18 +417,17 @@ impl Step for TestLink {
/// Same as `std_link`, only for libtest
fn run(self, builder: &Builder) {
let build = builder.build;
let compiler = self.compiler;
let target_compiler = self.target_compiler;
let target = self.target;
println!("Copying stage{} test from stage{} ({} -> {} / {})",
builder.info(&format!("Copying stage{} test from stage{} ({} -> {} / {})",
target_compiler.stage,
compiler.stage,
&compiler.host,
target_compiler.host,
target);
add_to_sysroot(&builder.sysroot_libdir(target_compiler, target),
&libtest_stamp(build, compiler, target));
target));
add_to_sysroot(builder, &builder.sysroot_libdir(target_compiler, target),
&libtest_stamp(builder, compiler, target));
builder.ensure(tool::CleanTools {
compiler: target_compiler,
target,
@ -430,10 +436,10 @@ impl Step for TestLink {
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rustc {
pub compiler: Compiler,
pub target: Interned<String>,
pub compiler: Compiler,
}
impl Step for Rustc {
@ -458,20 +464,20 @@ impl Step for Rustc {
/// the `compiler` targeting the `target` architecture. The artifacts
/// created will also be linked into the sysroot directory.
fn run(self, builder: &Builder) {
let build = builder.build;
let compiler = self.compiler;
let target = self.target;
builder.ensure(Test { compiler, target });
if build.force_use_stage1(compiler, target) {
if builder.force_use_stage1(compiler, target) {
builder.ensure(Rustc {
compiler: builder.compiler(1, build.build),
compiler: builder.compiler(1, builder.config.build),
target,
});
println!("Uplifting stage1 rustc ({} -> {})", &build.build, target);
builder.info(&format!("Uplifting stage1 rustc ({} -> {})",
builder.config.build, target));
builder.ensure(RustcLink {
compiler: builder.compiler(1, build.build),
compiler: builder.compiler(1, builder.config.build),
target_compiler: compiler,
target,
});
@ -480,71 +486,71 @@ impl Step for Rustc {
// Ensure that build scripts have a std to link against.
builder.ensure(Std {
compiler: builder.compiler(self.compiler.stage, build.build),
target: build.build,
compiler: builder.compiler(self.compiler.stage, builder.config.build),
target: builder.config.build,
});
let cargo_out = builder.cargo_out(compiler, Mode::Librustc, target);
build.clear_if_dirty(&cargo_out, &libstd_stamp(build, compiler, target));
build.clear_if_dirty(&cargo_out, &libtest_stamp(build, compiler, target));
builder.clear_if_dirty(&cargo_out, &libstd_stamp(builder, compiler, target));
builder.clear_if_dirty(&cargo_out, &libtest_stamp(builder, compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build");
rustc_cargo(build, &mut cargo);
rustc_cargo(builder, &mut cargo);
let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage));
println!("Building stage{} compiler artifacts ({} -> {})",
compiler.stage, &compiler.host, target);
run_cargo(build,
let _folder = builder.fold_output(|| format!("stage{}-rustc", compiler.stage));
builder.info(&format!("Building stage{} compiler artifacts ({} -> {})",
compiler.stage, &compiler.host, target));
run_cargo(builder,
&mut cargo,
&librustc_stamp(build, compiler, target),
&librustc_stamp(builder, compiler, target),
false);
builder.ensure(RustcLink {
compiler: builder.compiler(compiler.stage, build.build),
compiler: builder.compiler(compiler.stage, builder.config.build),
target_compiler: compiler,
target,
});
}
}
pub fn rustc_cargo(build: &Build, cargo: &mut Command) {
cargo.arg("--features").arg(build.rustc_features())
pub fn rustc_cargo(builder: &Builder, cargo: &mut Command) {
cargo.arg("--features").arg(builder.rustc_features())
.arg("--manifest-path")
.arg(build.src.join("src/rustc/Cargo.toml"));
rustc_cargo_env(build, cargo);
.arg(builder.src.join("src/rustc/Cargo.toml"));
rustc_cargo_env(builder, cargo);
}
fn rustc_cargo_env(build: &Build, cargo: &mut Command) {
pub fn rustc_cargo_env(builder: &Builder, cargo: &mut Command) {
// Set some configuration variables picked up by build scripts and
// the compiler alike
cargo.env("CFG_RELEASE", build.rust_release())
.env("CFG_RELEASE_CHANNEL", &build.config.channel)
.env("CFG_VERSION", build.rust_version())
.env("CFG_PREFIX", build.config.prefix.clone().unwrap_or_default())
.env("CFG_CODEGEN_BACKENDS_DIR", &build.config.rust_codegen_backends_dir);
cargo.env("CFG_RELEASE", builder.rust_release())
.env("CFG_RELEASE_CHANNEL", &builder.config.channel)
.env("CFG_VERSION", builder.rust_version())
.env("CFG_PREFIX", builder.config.prefix.clone().unwrap_or_default())
.env("CFG_CODEGEN_BACKENDS_DIR", &builder.config.rust_codegen_backends_dir);
let libdir_relative = build.config.libdir_relative().unwrap_or(Path::new("lib"));
let libdir_relative = builder.config.libdir_relative().unwrap_or(Path::new("lib"));
cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);
// If we're not building a compiler with debugging information then remove
// these two env vars which would be set otherwise.
if build.config.rust_debuginfo_only_std {
if builder.config.rust_debuginfo_only_std {
cargo.env_remove("RUSTC_DEBUGINFO");
cargo.env_remove("RUSTC_DEBUGINFO_LINES");
}
if let Some(ref ver_date) = build.rust_info.commit_date() {
if let Some(ref ver_date) = builder.rust_info.commit_date() {
cargo.env("CFG_VER_DATE", ver_date);
}
if let Some(ref ver_hash) = build.rust_info.sha() {
if let Some(ref ver_hash) = builder.rust_info.sha() {
cargo.env("CFG_VER_HASH", ver_hash);
}
if !build.unstable_features() {
if !builder.unstable_features() {
cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1");
}
if let Some(ref s) = build.config.rustc_default_linker {
if let Some(ref s) = builder.config.rustc_default_linker {
cargo.env("CFG_DEFAULT_LINKER", s);
}
if build.config.rustc_parallel_queries {
if builder.config.rustc_parallel_queries {
cargo.env("RUSTC_PARALLEL_QUERIES", "1");
}
}
@ -565,18 +571,17 @@ impl Step for RustcLink {
/// Same as `std_link`, only for librustc
fn run(self, builder: &Builder) {
let build = builder.build;
let compiler = self.compiler;
let target_compiler = self.target_compiler;
let target = self.target;
println!("Copying stage{} rustc from stage{} ({} -> {} / {})",
builder.info(&format!("Copying stage{} rustc from stage{} ({} -> {} / {})",
target_compiler.stage,
compiler.stage,
&compiler.host,
target_compiler.host,
target);
add_to_sysroot(&builder.sysroot_libdir(target_compiler, target),
&librustc_stamp(build, compiler, target));
target));
add_to_sysroot(builder, &builder.sysroot_libdir(target_compiler, target),
&librustc_stamp(builder, compiler, target));
builder.ensure(tool::CleanTools {
compiler: target_compiler,
target,
@ -609,87 +614,45 @@ impl Step for CodegenBackend {
run.builder.ensure(CodegenBackend {
compiler: run.builder.compiler(run.builder.top_stage, run.host),
target: run.target,
backend
backend,
});
}
fn run(self, builder: &Builder) {
let build = builder.build;
let compiler = self.compiler;
let target = self.target;
let backend = self.backend;
builder.ensure(Rustc { compiler, target });
if build.force_use_stage1(compiler, target) {
if builder.force_use_stage1(compiler, target) {
builder.ensure(CodegenBackend {
compiler: builder.compiler(1, build.build),
compiler: builder.compiler(1, builder.config.build),
target,
backend: self.backend,
backend,
});
return;
}
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build");
let mut features = build.rustc_features().to_string();
let mut features = builder.rustc_features().to_string();
cargo.arg("--manifest-path")
.arg(build.src.join("src/librustc_trans/Cargo.toml"));
rustc_cargo_env(build, &mut cargo);
.arg(builder.src.join("src/librustc_trans/Cargo.toml"));
rustc_cargo_env(builder, &mut cargo);
match &*self.backend {
"llvm" | "emscripten" => {
// Build LLVM for our target. This will implicitly build the
// host LLVM if necessary.
let llvm_config = builder.ensure(native::Llvm {
target,
emscripten: self.backend == "emscripten",
});
features += &build_codegen_backend(&builder, &mut cargo, &compiler, target, backend);
if self.backend == "emscripten" {
features.push_str(" emscripten");
}
println!("Building stage{} codegen artifacts ({} -> {}, {})",
compiler.stage, &compiler.host, target, self.backend);
// Pass down configuration from the LLVM build into the build of
// librustc_llvm and librustc_trans.
if build.is_rust_llvm(target) {
cargo.env("LLVM_RUSTLLVM", "1");
}
cargo.env("LLVM_CONFIG", &llvm_config);
if self.backend != "emscripten" {
let target_config = build.config.target_config.get(&target);
if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
cargo.env("CFG_LLVM_ROOT", s);
}
}
// Building with a static libstdc++ is only supported on linux right now,
// not for MSVC or macOS
if build.config.llvm_static_stdcpp &&
!target.contains("freebsd") &&
!target.contains("windows") &&
!target.contains("apple") {
let file = compiler_file(build,
build.cxx(target).unwrap(),
target,
"libstdc++.a");
cargo.env("LLVM_STATIC_STDCPP", file);
}
if build.config.llvm_link_shared {
cargo.env("LLVM_LINK_SHARED", "1");
}
}
_ => panic!("unknown backend: {}", self.backend),
}
let tmp_stamp = build.cargo_out(compiler, Mode::Librustc, target)
let tmp_stamp = builder.cargo_out(compiler, Mode::Librustc, target)
.join(".tmp.stamp");
let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
let files = run_cargo(build,
let _folder = builder.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
let files = run_cargo(builder,
cargo.arg("--features").arg(features),
&tmp_stamp,
false);
if builder.config.dry_run {
return;
}
let mut files = files.into_iter()
.filter(|f| {
let filename = f.file_name().unwrap().to_str().unwrap();
@ -704,12 +667,69 @@ impl Step for CodegenBackend {
codegen_backend.display(),
f.display());
}
let stamp = codegen_backend_stamp(build, compiler, target, self.backend);
let stamp = codegen_backend_stamp(builder, compiler, target, backend);
let codegen_backend = codegen_backend.to_str().unwrap();
t!(t!(File::create(&stamp)).write_all(codegen_backend.as_bytes()));
}
}
pub fn build_codegen_backend(builder: &Builder,
cargo: &mut Command,
compiler: &Compiler,
target: Interned<String>,
backend: Interned<String>) -> String {
let mut features = String::new();
match &*backend {
"llvm" | "emscripten" => {
// Build LLVM for our target. This will implicitly build the
// host LLVM if necessary.
let llvm_config = builder.ensure(native::Llvm {
target,
emscripten: backend == "emscripten",
});
if backend == "emscripten" {
features.push_str(" emscripten");
}
builder.info(&format!("Building stage{} codegen artifacts ({} -> {}, {})",
compiler.stage, &compiler.host, target, backend));
// Pass down configuration from the LLVM build into the build of
// librustc_llvm and librustc_trans.
if builder.is_rust_llvm(target) {
cargo.env("LLVM_RUSTLLVM", "1");
}
cargo.env("LLVM_CONFIG", &llvm_config);
if backend != "emscripten" {
let target_config = builder.config.target_config.get(&target);
if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
cargo.env("CFG_LLVM_ROOT", s);
}
}
// Building with a static libstdc++ is only supported on linux right now,
// not for MSVC or macOS
if builder.config.llvm_static_stdcpp &&
!target.contains("freebsd") &&
!target.contains("windows") &&
!target.contains("apple") {
let file = compiler_file(builder,
builder.cxx(target).unwrap(),
target,
"libstdc++.a");
cargo.env("LLVM_STATIC_STDCPP", file);
}
if builder.config.llvm_link_shared {
cargo.env("LLVM_LINK_SHARED", "1");
}
}
_ => panic!("unknown backend: {}", backend),
}
features
}
/// Creates the `codegen-backends` folder for a compiler that's about to be
/// assembled as a complete compiler.
///
@ -719,7 +739,6 @@ impl Step for CodegenBackend {
fn copy_codegen_backends_to_sysroot(builder: &Builder,
compiler: Compiler,
target_compiler: Compiler) {
let build = builder.build;
let target = target_compiler.host;
// Note that this step is different than all the other `*Link` steps in
@ -733,8 +752,12 @@ fn copy_codegen_backends_to_sysroot(builder: &Builder,
let dst = builder.sysroot_codegen_backends(target_compiler);
t!(fs::create_dir_all(&dst));
if builder.config.dry_run {
return;
}
for backend in builder.config.rust_codegen_backends.iter() {
let stamp = codegen_backend_stamp(build, compiler, target, *backend);
let stamp = codegen_backend_stamp(builder, compiler, target, *backend);
let mut dylib = String::new();
t!(t!(File::open(&stamp)).read_to_string(&mut dylib));
let file = Path::new(&dylib);
@ -748,7 +771,7 @@ fn copy_codegen_backends_to_sysroot(builder: &Builder,
backend,
&filename[dot..])
};
copy(&file, &dst.join(target_filename));
builder.copy(&file, &dst.join(target_filename));
}
}
@ -764,41 +787,43 @@ fn copy_lld_to_sysroot(builder: &Builder,
t!(fs::create_dir_all(&dst));
let exe = exe("lld", &target);
copy(&lld_install_root.join("bin").join(&exe), &dst.join(&exe));
builder.copy(&lld_install_root.join("bin").join(&exe), &dst.join(&exe));
}
/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
pub fn libstd_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
build.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp")
pub fn libstd_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
builder.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp")
}
/// Cargo's output path for libtest in a given stage, compiled by a particular
/// compiler for the specified target.
pub fn libtest_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp")
pub fn libtest_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
builder.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.
pub fn librustc_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
build.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp")
pub fn librustc_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
builder.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp")
}
fn codegen_backend_stamp(build: &Build,
/// Cargo's output path for librustc_trans in a given stage, compiled by a particular
/// compiler for the specified target and backend.
fn codegen_backend_stamp(builder: &Builder,
compiler: Compiler,
target: Interned<String>,
backend: Interned<String>) -> PathBuf {
build.cargo_out(compiler, Mode::Librustc, target)
builder.cargo_out(compiler, Mode::Librustc, target)
.join(format!(".librustc_trans-{}.stamp", backend))
}
fn compiler_file(build: &Build,
pub fn compiler_file(builder: &Builder,
compiler: &Path,
target: Interned<String>,
file: &str) -> PathBuf {
let mut cmd = Command::new(compiler);
cmd.args(build.cflags(target));
cmd.args(builder.cflags(target));
cmd.arg(format!("-print-file-name={}", file));
let out = output(&mut cmd);
PathBuf::from(out.trim())
@ -823,12 +848,11 @@ impl Step for Sysroot {
/// thinks it is by default, but it's the same as the default for stages
/// 1-3.
fn run(self, builder: &Builder) -> Interned<PathBuf> {
let build = builder.build;
let compiler = self.compiler;
let sysroot = if compiler.stage == 0 {
build.out.join(&compiler.host).join("stage0-sysroot")
builder.out.join(&compiler.host).join("stage0-sysroot")
} else {
build.out.join(&compiler.host).join(format!("stage{}", compiler.stage))
builder.out.join(&compiler.host).join(format!("stage{}", compiler.stage))
};
let _ = fs::remove_dir_all(&sysroot);
t!(fs::create_dir_all(&sysroot));
@ -836,7 +860,7 @@ impl Step for Sysroot {
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Copy, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)]
pub struct Assemble {
/// The compiler which we will produce in this step. Assemble itself will
/// take care of ensuring that the necessary prerequisites to do so exist,
@ -855,14 +879,13 @@ impl Step for Assemble {
/// Prepare a new compiler from the artifacts in `stage`
///
/// This will assemble a compiler in `build/$host/stage$stage`. The compiler
/// must have been previously produced by the `stage - 1` build.build
/// must have been previously produced by the `stage - 1` builder.build
/// compiler.
fn run(self, builder: &Builder) -> Compiler {
let build = builder.build;
let target_compiler = self.target_compiler;
if target_compiler.stage == 0 {
assert_eq!(build.build, target_compiler.host,
assert_eq!(builder.config.build, target_compiler.host,
"Cannot obtain compiler for non-native build triple at stage 0");
// The stage 0 compiler for the build triple is always pre-built.
return target_compiler;
@ -885,14 +908,14 @@ impl Step for Assemble {
// FIXME: It may be faster if we build just a stage 1 compiler and then
// use that to bootstrap this compiler forward.
let build_compiler =
builder.compiler(target_compiler.stage - 1, build.build);
builder.compiler(target_compiler.stage - 1, builder.config.build);
// Build the libraries for this compiler to link to (i.e., the libraries
// it uses at runtime). NOTE: Crates the target compiler compiles don't
// link to these. (FIXME: Is that correct? It seems to be correct most
// of the time but I think we do link to these for stage2/bin compilers
// when not performing a full bootstrap).
if builder.build.config.keep_stage.map_or(false, |s| target_compiler.stage <= s) {
if builder.config.keep_stage.map_or(false, |s| target_compiler.stage <= s) {
builder.verbose("skipping compilation of compiler due to --keep-stage");
let compiler = build_compiler;
for stage in 0..min(target_compiler.stage, builder.config.keep_stage.unwrap()) {
@ -907,7 +930,7 @@ impl Step for Assemble {
compiler: build_compiler,
target: target_compiler.host,
});
for &backend in build.config.rust_codegen_backends.iter() {
for &backend in builder.config.rust_codegen_backends.iter() {
builder.ensure(CodegenBackend {
compiler: build_compiler,
target: target_compiler.host,
@ -916,7 +939,7 @@ impl Step for Assemble {
}
}
let lld_install = if build.config.lld_enabled {
let lld_install = if builder.config.lld_enabled {
Some(builder.ensure(native::Lld {
target: target_compiler.host,
}))
@ -926,17 +949,17 @@ impl Step for Assemble {
let stage = target_compiler.stage;
let host = target_compiler.host;
println!("Assembling stage{} compiler ({})", stage, host);
builder.info(&format!("Assembling stage{} compiler ({})", stage, host));
// Link in all dylibs to the libdir
let sysroot = builder.sysroot(target_compiler);
let sysroot_libdir = sysroot.join(libdir(&*host));
t!(fs::create_dir_all(&sysroot_libdir));
let src_libdir = builder.sysroot_libdir(build_compiler, host);
for f in t!(fs::read_dir(&src_libdir)).map(|f| t!(f)) {
for f in builder.read_dir(&src_libdir) {
let filename = f.file_name().into_string().unwrap();
if is_dylib(&filename) {
copy(&f.path(), &sysroot_libdir.join(&filename));
builder.copy(&f.path(), &sysroot_libdir.join(&filename));
}
}
@ -948,13 +971,13 @@ impl Step for Assemble {
}
// Link the compiler binary itself into place
let out_dir = build.cargo_out(build_compiler, Mode::Librustc, host);
let out_dir = builder.cargo_out(build_compiler, Mode::Librustc, host);
let rustc = out_dir.join(exe("rustc", &*host));
let bindir = sysroot.join("bin");
t!(fs::create_dir_all(&bindir));
let compiler = builder.rustc(target_compiler);
let _ = fs::remove_file(&compiler);
copy(&rustc, &compiler);
builder.copy(&rustc, &compiler);
target_compiler
}
@ -964,10 +987,10 @@ impl Step for Assemble {
///
/// For a particular stage this will link the file listed in `stamp` into the
/// `sysroot_dst` provided.
pub fn add_to_sysroot(sysroot_dst: &Path, stamp: &Path) {
pub fn add_to_sysroot(builder: &Builder, sysroot_dst: &Path, stamp: &Path) {
t!(fs::create_dir_all(&sysroot_dst));
for path in read_stamp_file(stamp) {
copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
for path in builder.read_stamp_file(stamp) {
builder.copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
}
}
@ -994,9 +1017,13 @@ fn stderr_isatty() -> bool {
}
}
pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: bool)
pub fn run_cargo(builder: &Builder, cargo: &mut Command, stamp: &Path, is_check: bool)
-> Vec<PathBuf>
{
if builder.config.dry_run {
return Vec::new();
}
// `target_root_dir` looks like $dir/$target/release
let target_root_dir = stamp.parent().unwrap();
// `target_deps_dir` looks like $dir/$target/release/deps
@ -1011,7 +1038,7 @@ pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: boo
// files we need to probe for later.
let mut deps = Vec::new();
let mut toplevel = Vec::new();
let ok = stream_cargo(build, cargo, &mut |msg| {
let ok = stream_cargo(builder, cargo, &mut |msg| {
let filenames = match msg {
CargoMessage::CompilerArtifact { filenames, .. } => filenames,
_ => return,
@ -1120,37 +1147,42 @@ pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: boo
let max = max.unwrap();
let max_path = max_path.unwrap();
if stamp_contents == new_contents && max <= stamp_mtime {
build.verbose(&format!("not updating {:?}; contents equal and {:?} <= {:?}",
builder.verbose(&format!("not updating {:?}; contents equal and {:?} <= {:?}",
stamp, max, stamp_mtime));
return deps
}
if max > stamp_mtime {
build.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path));
builder.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path));
} else {
build.verbose(&format!("updating {:?} as deps changed", stamp));
builder.verbose(&format!("updating {:?} as deps changed", stamp));
}
t!(t!(File::create(stamp)).write_all(&new_contents));
deps
}
pub fn stream_cargo(
build: &Build,
builder: &Builder,
cargo: &mut Command,
cb: &mut FnMut(CargoMessage),
) -> bool {
if builder.config.dry_run {
return true;
}
// Instruct Cargo to give us json messages on stdout, critically leaving
// stderr as piped so we can get those pretty colors.
cargo.arg("--message-format").arg("json")
.stdout(Stdio::piped());
if stderr_isatty() && build.ci_env == CiEnv::None {
if stderr_isatty() && builder.ci_env == CiEnv::None &&
// if the terminal is reported as dumb, then we don't want to enable color for rustc
env::var_os("TERM").map(|t| t != *"dumb").unwrap_or(true) {
// since we pass message-format=json to cargo, we need to tell the rustc
// wrapper to give us colored output if necessary. This is because we
// only want Cargo's JSON output, not rustcs.
cargo.env("RUSTC_COLOR", "1");
}
build.verbose(&format!("running: {:?}", cargo));
builder.verbose(&format!("running: {:?}", cargo));
let mut child = match cargo.spawn() {
Ok(child) => child,
Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cargo, e),
@ -1172,7 +1204,7 @@ pub fn stream_cargo(
// Make sure Cargo actually succeeded after we read all of its stdout.
let status = t!(child.wait());
if !status.success() {
println!("command did not execute successfully: {:?}\n\
eprintln!("command did not execute successfully: {:?}\n\
expected success, got: {}",
cargo,
status);

View File

@ -15,7 +15,7 @@
use std::collections::{HashMap, HashSet};
use std::env;
use std::fs::File;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process;
@ -69,6 +69,10 @@ pub struct Config {
pub jobs: Option<u32>,
pub cmd: Subcommand,
pub incremental: bool,
pub dry_run: bool,
pub deny_warnings: bool,
pub backtrace_on_ice: bool,
// llvm codegen options
pub llvm_enabled: bool,
@ -91,6 +95,7 @@ pub struct Config {
pub rust_debuginfo: bool,
pub rust_debuginfo_lines: bool,
pub rust_debuginfo_only_std: bool,
pub rust_debuginfo_tools: bool,
pub rust_rpath: bool,
pub rustc_parallel_queries: bool,
pub rustc_default_linker: Option<String>,
@ -143,6 +148,7 @@ pub struct Config {
// These are either the stage0 downloaded binaries or the locally installed ones.
pub initial_cargo: PathBuf,
pub initial_rustc: PathBuf,
pub out: PathBuf,
}
/// Per-target configuration stored in the global configuration structure.
@ -159,6 +165,7 @@ pub struct Target {
pub crt_static: Option<bool>,
pub musl_root: Option<PathBuf>,
pub qemu_rootfs: Option<PathBuf>,
pub no_std: bool,
}
/// Structure of the `config.toml` file that configuration is read from.
@ -277,6 +284,7 @@ struct Rust {
debuginfo: Option<bool>,
debuginfo_lines: Option<bool>,
debuginfo_only_std: Option<bool>,
debuginfo_tools: Option<bool>,
experimental_parallel_queries: Option<bool>,
debug_jemalloc: Option<bool>,
use_jemalloc: Option<bool>,
@ -298,6 +306,8 @@ struct Rust {
codegen_backends_dir: Option<String>,
wasm_syscall: Option<bool>,
lld: Option<bool>,
deny_warnings: Option<bool>,
backtrace_on_ice: Option<bool>,
}
/// TOML representation of how each build target is configured.
@ -317,11 +327,16 @@ struct TomlTarget {
}
impl Config {
pub fn parse(args: &[String]) -> Config {
let flags = Flags::parse(&args);
let file = flags.config.clone();
fn path_from_python(var_key: &str) -> PathBuf {
match env::var_os(var_key) {
// Do not trust paths from Python and normalize them slightly (#49785).
Some(var_val) => Path::new(&var_val).components().collect(),
_ => panic!("expected '{}' to be set", var_key),
}
}
pub fn default_opts() -> Config {
let mut config = Config::default();
config.exclude = flags.exclude;
config.llvm_enabled = true;
config.llvm_optimize = true;
config.llvm_version_check = true;
@ -340,15 +355,42 @@ impl Config {
config.test_miri = false;
config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
config.rust_codegen_backends_dir = "codegen-backends".to_owned();
config.deny_warnings = true;
// set by bootstrap.py
config.build = INTERNER.intern_str(&env::var("BUILD").expect("'BUILD' to be set"));
config.src = Config::path_from_python("SRC");
config.out = Config::path_from_python("BUILD_DIR");
let stage0_root = config.out.join(&config.build).join("stage0/bin");
config.initial_rustc = stage0_root.join(exe("rustc", &config.build));
config.initial_cargo = stage0_root.join(exe("cargo", &config.build));
config
}
pub fn parse(args: &[String]) -> Config {
let flags = Flags::parse(&args);
let file = flags.config.clone();
let mut config = Config::default_opts();
config.exclude = flags.exclude;
config.rustc_error_format = flags.rustc_error_format;
config.on_fail = flags.on_fail;
config.stage = flags.stage;
config.src = flags.src;
config.jobs = flags.jobs;
config.cmd = flags.cmd;
config.incremental = flags.incremental;
config.dry_run = flags.dry_run;
config.keep_stage = flags.keep_stage;
if let Some(value) = flags.warnings {
config.deny_warnings = value;
}
if config.dry_run {
let dir = config.out.join("tmp-dry-run");
t!(fs::create_dir_all(&dir));
config.out = dir;
}
// If --target was specified but --host wasn't specified, don't run any host-only tests.
config.run_host_only = !(flags.host.is_empty() && !flags.target.is_empty());
@ -368,12 +410,7 @@ impl Config {
}).unwrap_or_else(|| TomlConfig::default());
let build = toml.build.clone().unwrap_or(Build::default());
set(&mut config.build, build.build.clone().map(|x| INTERNER.intern_string(x)));
set(&mut config.build, flags.build);
if config.build.is_empty() {
// set by bootstrap.py
config.build = INTERNER.intern_str(&env::var("BUILD").unwrap());
}
// set by bootstrap.py
config.hosts.push(config.build.clone());
for host in build.host.iter() {
let host = INTERNER.intern_str(host);
@ -437,6 +474,7 @@ impl Config {
let mut llvm_assertions = None;
let mut debuginfo_lines = None;
let mut debuginfo_only_std = None;
let mut debuginfo_tools = None;
let mut debug = None;
let mut debug_jemalloc = None;
let mut debuginfo = None;
@ -474,6 +512,7 @@ impl Config {
debuginfo = rust.debuginfo;
debuginfo_lines = rust.debuginfo_lines;
debuginfo_only_std = rust.debuginfo_only_std;
debuginfo_tools = rust.debuginfo_tools;
optimize = rust.optimize;
ignore_git = rust.ignore_git;
debug_jemalloc = rust.debug_jemalloc;
@ -493,6 +532,8 @@ impl Config {
config.rustc_default_linker = rust.default_linker.clone();
config.musl_root = rust.musl_root.clone().map(PathBuf::from);
config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from);
set(&mut config.deny_warnings, rust.deny_warnings.or(flags.warnings));
set(&mut config.backtrace_on_ice, rust.backtrace_on_ice);
if let Some(ref backends) = rust.codegen_backends {
config.rust_codegen_backends = backends.iter()
@ -514,13 +555,13 @@ impl Config {
let mut target = Target::default();
if let Some(ref s) = cfg.llvm_config {
target.llvm_config = Some(env::current_dir().unwrap().join(s));
target.llvm_config = Some(config.src.join(s));
}
if let Some(ref s) = cfg.jemalloc {
target.jemalloc = Some(env::current_dir().unwrap().join(s));
target.jemalloc = Some(config.src.join(s));
}
if let Some(ref s) = cfg.android_ndk {
target.ndk = Some(env::current_dir().unwrap().join(s));
target.ndk = Some(config.src.join(s));
}
target.cc = cfg.cc.clone().map(PathBuf::from);
target.cxx = cfg.cxx.clone().map(PathBuf::from);
@ -541,22 +582,12 @@ impl Config {
set(&mut config.rust_dist_src, t.src_tarball);
}
let cwd = t!(env::current_dir());
let out = cwd.join("build");
let stage0_root = out.join(&config.build).join("stage0/bin");
config.initial_rustc = match build.rustc {
Some(s) => PathBuf::from(s),
None => stage0_root.join(exe("rustc", &config.build)),
};
config.initial_cargo = match build.cargo {
Some(s) => PathBuf::from(s),
None => stage0_root.join(exe("cargo", &config.build)),
};
// Now that we've reached the end of our configuration, infer the
// default values for all options that we haven't otherwise stored yet.
set(&mut config.initial_rustc, build.rustc.map(PathBuf::from));
set(&mut config.initial_cargo, build.cargo.map(PathBuf::from));
let default = false;
config.llvm_assertions = llvm_assertions.unwrap_or(default);
@ -566,6 +597,7 @@ impl Config {
};
config.rust_debuginfo_lines = debuginfo_lines.unwrap_or(default);
config.rust_debuginfo_only_std = debuginfo_only_std.unwrap_or(default);
config.rust_debuginfo_tools = debuginfo_tools.unwrap_or(false);
let default = debug == Some(true);
config.debug_jemalloc = debug_jemalloc.unwrap_or(default);

View File

@ -79,6 +79,7 @@ o("llvm-release-debuginfo", "llvm.release-debuginfo", "build LLVM with debugger
o("debuginfo", "rust.debuginfo", "build with debugger metadata")
o("debuginfo-lines", "rust.debuginfo-lines", "build with line number debugger metadata")
o("debuginfo-only-std", "rust.debuginfo-only-std", "build only libstd with debugging information")
o("debuginfo-tools", "rust.debuginfo-tools", "build extended tools with debugging information")
o("debug-jemalloc", "rust.debug-jemalloc", "build jemalloc with --enable-debug --enable-fill")
v("save-toolstates", "rust.save-toolstates", "save build and test status of external tools into this file")
@ -119,6 +120,8 @@ v("musl-root-arm", "target.arm-unknown-linux-musleabi.musl-root",
"arm-unknown-linux-musleabi install directory")
v("musl-root-armhf", "target.arm-unknown-linux-musleabihf.musl-root",
"arm-unknown-linux-musleabihf install directory")
v("musl-root-armv5te", "target.armv5te-unknown-linux-musleabi.musl-root",
"armv5te-unknown-linux-musleabi install directory")
v("musl-root-armv7", "target.armv7-unknown-linux-musleabihf.musl-root",
"armv7-unknown-linux-musleabihf install directory")
v("musl-root-aarch64", "target.aarch64-unknown-linux-musl.musl-root",
@ -145,7 +148,7 @@ o("jemalloc", "rust.use-jemalloc", "build liballoc with jemalloc")
o("full-bootstrap", "build.full-bootstrap", "build three compilers instead of two")
o("extended", "build.extended", "build an extended rust tool set")
v("tools", "build.tools", "List of extended tools will be installed")
v("tools", None, "List of extended tools will be installed")
v("build", "build.build", "GNUs ./configure syntax LLVM build triple")
v("host", None, "GNUs ./configure syntax LLVM host triples")
v("target", None, "GNUs ./configure syntax LLVM target triples")
@ -321,6 +324,8 @@ for key in known_args:
set('target.{}.llvm-config'.format(build()), value + '/bin/llvm-config')
elif option.name == 'jemalloc-root':
set('target.{}.jemalloc'.format(build()), value + '/libjemalloc_pic.a')
elif option.name == 'tools':
set('build.tools', value.split(','))
elif option.name == 'host':
set('build.host', value.split(','))
elif option.name == 'target':

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Documentation generation for rustbuild.
//! Documentation generation for rustbuilder.
//!
//! This module implements generation for all bits and pieces of documentation
//! for the Rust project. This notably includes suites like the rust book, the
@ -23,14 +23,15 @@ use std::io::prelude::*;
use std::io;
use std::path::{PathBuf, Path};
use {Build, Mode};
use Mode;
use build_helper::up_to_date;
use util::{cp_r, symlink_dir};
use util::symlink_dir;
use builder::{Builder, Compiler, RunConfig, ShouldRun, Step};
use tool::Tool;
use compile;
use cache::{INTERNER, Interned};
use config::Config;
macro_rules! book {
($($name:ident, $path:expr, $book_name:expr;)+) => {
@ -46,7 +47,7 @@ macro_rules! book {
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.path($path).default_condition(builder.build.config.docs)
run.path($path).default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
@ -70,6 +71,7 @@ book!(
Nomicon, "src/doc/nomicon", "nomicon";
Reference, "src/doc/reference", "reference";
Rustdoc, "src/doc/rustdoc", "rustdoc";
RustcBook, "src/doc/rustc", "rustc";
RustByExample, "src/doc/rust-by-example", "rust-by-example";
);
@ -93,7 +95,7 @@ impl Step for Rustbook {
/// This will not actually generate any documentation if the documentation has
/// already been generated.
fn run(self, builder: &Builder) {
let src = builder.build.src.join("src/doc");
let src = builder.src.join("src/doc");
builder.ensure(RustbookSrc {
target: self.target,
name: self.name,
@ -113,7 +115,7 @@ impl Step for UnstableBook {
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.path("src/doc/unstable-book").default_condition(builder.build.config.docs)
run.path("src/doc/unstable-book").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
@ -129,7 +131,7 @@ impl Step for UnstableBook {
builder.ensure(RustbookSrc {
target: self.target,
name: INTERNER.intern_str("unstable-book"),
src: builder.build.md_doc_out(self.target),
src: builder.md_doc_out(self.target),
})
}
}
@ -146,7 +148,7 @@ impl Step for CargoBook {
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.path("src/tools/cargo/src/doc/book").default_condition(builder.build.config.docs)
run.path("src/tools/cargo/src/doc/book").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
@ -157,22 +159,20 @@ impl Step for CargoBook {
}
fn run(self, builder: &Builder) {
let build = builder.build;
let target = self.target;
let name = self.name;
let src = build.src.join("src/tools/cargo/src/doc");
let src = builder.src.join("src/tools/cargo/src/doc");
let out = build.doc_out(target);
let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
let out = out.join(name);
println!("Cargo Book ({}) - {}", target, name);
builder.info(&format!("Cargo Book ({}) - {}", target, name));
let _ = fs::remove_dir_all(&out);
build.run(builder.tool_cmd(Tool::Rustbook)
builder.run(builder.tool_cmd(Tool::Rustbook)
.arg("build")
.arg(&src)
.arg("-d")
@ -199,23 +199,23 @@ impl Step for RustbookSrc {
/// This will not actually generate any documentation if the documentation has
/// already been generated.
fn run(self, builder: &Builder) {
let build = builder.build;
let target = self.target;
let name = self.name;
let src = self.src;
let out = build.doc_out(target);
let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
let out = out.join(name);
let src = src.join(name);
let index = out.join("index.html");
let rustbook = builder.tool_exe(Tool::Rustbook);
let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
if up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
return
}
println!("Rustbook ({}) - {}", target, name);
builder.info(&format!("Rustbook ({}) - {}", target, name));
let _ = fs::remove_dir_all(&out);
build.run(builder.tool_cmd(Tool::Rustbook)
builder.run(rustbook_cmd
.arg("build")
.arg(&src)
.arg("-d")
@ -236,12 +236,12 @@ impl Step for TheBook {
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.path("src/doc/book").default_condition(builder.build.config.docs)
run.path("src/doc/book").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
run.builder.ensure(TheBook {
compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
target: run.target,
name: "book",
});
@ -257,7 +257,6 @@ impl Step for TheBook {
/// * Index page
/// * Redirect pages
fn run(self, builder: &Builder) {
let build = builder.build;
let compiler = self.compiler;
let target = self.target;
let name = self.name;
@ -281,12 +280,12 @@ impl Step for TheBook {
// build the index page
let index = format!("{}/index.md", name);
println!("Documenting book index ({})", target);
builder.info(&format!("Documenting book index ({})", target));
invoke_rustdoc(builder, compiler, 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"))) {
builder.info(&format!("Documenting book redirect pages ({})", target));
for file in t!(fs::read_dir(builder.src.join("src/doc/book/redirects"))) {
let file = t!(file);
let path = file.path();
let path = path.to_str().unwrap();
@ -297,13 +296,12 @@ impl Step for TheBook {
}
fn invoke_rustdoc(builder: &Builder, compiler: Compiler, target: Interned<String>, markdown: &str) {
let build = builder.build;
let out = build.doc_out(target);
let out = builder.doc_out(target);
let path = build.src.join("src/doc").join(markdown);
let path = builder.src.join("src/doc").join(markdown);
let favicon = build.src.join("src/doc/favicon.inc");
let footer = build.src.join("src/doc/footer.inc");
let favicon = builder.src.join("src/doc/favicon.inc");
let footer = builder.src.join("src/doc/footer.inc");
let version_info = out.join("version_info.html");
let mut cmd = builder.rustdoc_cmd(compiler.host);
@ -321,7 +319,7 @@ fn invoke_rustdoc(builder: &Builder, compiler: Compiler, target: Interned<String
.arg("--markdown-css")
.arg("../rust.css");
build.run(&mut cmd);
builder.run(&mut cmd);
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
@ -336,12 +334,12 @@ impl Step for Standalone {
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.path("src/doc").default_condition(builder.build.config.docs)
run.path("src/doc").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
run.builder.ensure(Standalone {
compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
target: run.target,
});
}
@ -355,31 +353,30 @@ impl Step for Standalone {
///
/// In the end, this is just a glorified wrapper around rustdoc!
fn run(self, builder: &Builder) {
let build = builder.build;
let target = self.target;
let compiler = self.compiler;
println!("Documenting standalone ({})", target);
let out = build.doc_out(target);
builder.info(&format!("Documenting standalone ({})", target));
let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
let favicon = build.src.join("src/doc/favicon.inc");
let footer = build.src.join("src/doc/footer.inc");
let full_toc = build.src.join("src/doc/full-toc.inc");
t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css")));
let favicon = builder.src.join("src/doc/favicon.inc");
let footer = builder.src.join("src/doc/footer.inc");
let full_toc = builder.src.join("src/doc/full-toc.inc");
t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css")));
let version_input = build.src.join("src/doc/version_info.html.template");
let version_input = builder.src.join("src/doc/version_info.html.template");
let version_info = out.join("version_info.html");
if !up_to_date(&version_input, &version_info) {
if !builder.config.dry_run && !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(""));
let info = info.replace("VERSION", &builder.rust_release())
.replace("SHORT_HASH", builder.rust_info.sha_short().unwrap_or(""))
.replace("STAMP", builder.rust_info.sha().unwrap_or(""));
t!(t!(File::create(&version_info)).write_all(info.as_bytes()));
}
for file in t!(fs::read_dir(build.src.join("src/doc"))) {
for file in t!(fs::read_dir(builder.src.join("src/doc"))) {
let file = t!(file);
let path = file.path();
let filename = path.file_name().unwrap().to_str().unwrap();
@ -394,7 +391,7 @@ impl Step for Standalone {
up_to_date(&favicon, &html) &&
up_to_date(&full_toc, &html) &&
up_to_date(&version_info, &html) &&
up_to_date(&rustdoc, &html) {
(builder.config.dry_run || up_to_date(&rustdoc, &html)) {
continue
}
@ -414,7 +411,7 @@ impl Step for Standalone {
} else {
cmd.arg("--markdown-css").arg("rust.css");
}
build.run(&mut cmd);
builder.run(&mut cmd);
}
}
}
@ -431,7 +428,7 @@ impl Step for Std {
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.all_krates("std").default_condition(builder.build.config.docs)
run.all_krates("std").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
@ -446,22 +443,21 @@ impl Step for Std {
/// This will generate all documentation for the standard library and its
/// dependencies. This is largely just a wrapper around `cargo doc`.
fn run(self, builder: &Builder) {
let build = builder.build;
let stage = self.stage;
let target = self.target;
println!("Documenting stage{} std ({})", stage, target);
let out = build.doc_out(target);
builder.info(&format!("Documenting stage{} std ({})", stage, target));
let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = builder.compiler(stage, build.build);
let compiler = builder.compiler(stage, builder.config.build);
let rustdoc = builder.rustdoc(compiler.host);
let compiler = if build.force_use_stage1(compiler, target) {
let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
compiler
};
builder.ensure(compile::Std { compiler, target });
let out_dir = build.stage_out(compiler, Mode::Libstd)
let out_dir = builder.stage_out(compiler, Mode::Libstd)
.join(target).join("doc");
// Here what we're doing is creating a *symlink* (directory junction on
@ -477,9 +473,9 @@ impl Step for Std {
//
// This way rustdoc generates output directly into the output, and rustdoc
// will also directly handle merging.
let my_out = build.crate_doc_out(target);
build.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&my_out, &out_dir));
let my_out = builder.crate_doc_out(target);
builder.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "doc");
compile::std_cargo(builder, &compiler, target, &mut cargo);
@ -495,8 +491,8 @@ impl Step for Std {
t!(fs::create_dir_all(out_dir.join(krate)));
}
build.run(&mut cargo);
cp_r(&my_out, &out);
builder.run(&mut cargo);
builder.cp_r(&my_out, &out);
}
}
@ -512,7 +508,7 @@ impl Step for Test {
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.krate("test").default_condition(builder.build.config.docs)
run.krate("test").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
@ -527,15 +523,14 @@ impl Step for Test {
/// This will generate all documentation for libtest and its dependencies. This
/// is largely just a wrapper around `cargo doc`.
fn run(self, builder: &Builder) {
let build = builder.build;
let stage = self.stage;
let target = self.target;
println!("Documenting stage{} test ({})", stage, target);
let out = build.doc_out(target);
builder.info(&format!("Documenting stage{} test ({})", stage, target));
let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = builder.compiler(stage, build.build);
let compiler = builder.compiler(stage, builder.config.build);
let rustdoc = builder.rustdoc(compiler.host);
let compiler = if build.force_use_stage1(compiler, target) {
let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
compiler
@ -545,21 +540,21 @@ impl Step for Test {
builder.ensure(Std { stage, target });
builder.ensure(compile::Test { compiler, target });
let out_dir = build.stage_out(compiler, Mode::Libtest)
let out_dir = builder.stage_out(compiler, Mode::Libtest)
.join(target).join("doc");
// See docs in std above for why we symlink
let my_out = build.crate_doc_out(target);
build.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&my_out, &out_dir));
let my_out = builder.crate_doc_out(target);
builder.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "doc");
compile::test_cargo(build, &compiler, target, &mut cargo);
compile::test_cargo(builder, &compiler, target, &mut cargo);
cargo.arg("--no-deps").arg("-p").arg("test");
build.run(&mut cargo);
cp_r(&my_out, &out);
builder.run(&mut cargo);
builder.cp_r(&my_out, &out);
}
}
@ -576,7 +571,7 @@ impl Step for WhitelistedRustc {
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.krate("rustc-main").default_condition(builder.build.config.docs)
run.krate("rustc-main").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
@ -596,15 +591,14 @@ impl Step for WhitelistedRustc {
/// here as we want to be able to keep it separate from the standard
/// documentation. This is largely just a wrapper around `cargo doc`.
fn run(self, builder: &Builder) {
let build = builder.build;
let stage = self.stage;
let target = self.target;
println!("Documenting stage{} whitelisted compiler ({})", stage, target);
let out = build.doc_out(target);
builder.info(&format!("Documenting stage{} whitelisted compiler ({})", stage, target));
let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = builder.compiler(stage, build.build);
let compiler = builder.compiler(stage, builder.config.build);
let rustdoc = builder.rustdoc(compiler.host);
let compiler = if build.force_use_stage1(compiler, target) {
let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
compiler
@ -614,16 +608,16 @@ impl Step for WhitelistedRustc {
builder.ensure(Std { stage, target });
builder.ensure(compile::Rustc { compiler, target });
let out_dir = build.stage_out(compiler, Mode::Librustc)
let out_dir = builder.stage_out(compiler, Mode::Librustc)
.join(target).join("doc");
// See docs in std above for why we symlink
let my_out = build.crate_doc_out(target);
build.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&my_out, &out_dir));
let my_out = builder.crate_doc_out(target);
builder.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc");
compile::rustc_cargo(build, &mut cargo);
compile::rustc_cargo(builder, &mut cargo);
// We don't want to build docs for internal compiler dependencies in this
// step (there is another step for that). Therefore, we whitelist the crates
@ -633,8 +627,8 @@ impl Step for WhitelistedRustc {
cargo.arg("-p").arg(krate);
}
build.run(&mut cargo);
cp_r(&my_out, &out);
builder.run(&mut cargo);
builder.cp_r(&my_out, &out);
}
}
@ -651,7 +645,7 @@ impl Step for Rustc {
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.krate("rustc-main").default_condition(builder.build.config.docs)
run.krate("rustc-main").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
@ -668,22 +662,21 @@ impl Step for Rustc {
/// we do not merge it with the other documentation from std, test and
/// proc_macros. This is largely just a wrapper around `cargo doc`.
fn run(self, builder: &Builder) {
let build = builder.build;
let stage = self.stage;
let target = self.target;
println!("Documenting stage{} compiler ({})", stage, target);
let out = build.compiler_doc_out(target);
builder.info(&format!("Documenting stage{} compiler ({})", stage, target));
let out = builder.compiler_doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = builder.compiler(stage, build.build);
let compiler = builder.compiler(stage, builder.config.build);
let rustdoc = builder.rustdoc(compiler.host);
let compiler = if build.force_use_stage1(compiler, target) {
let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
compiler
};
if !build.config.compiler_docs {
println!("\tskipping - compiler docs disabled");
if !builder.config.compiler_docs {
builder.info(&format!("\tskipping - compiler docs disabled"));
return;
}
@ -691,15 +684,16 @@ impl Step for Rustc {
builder.ensure(Std { stage, target });
builder.ensure(compile::Rustc { compiler, target });
let out_dir = build.stage_out(compiler, Mode::Librustc)
let out_dir = builder.stage_out(compiler, Mode::Librustc)
.join(target).join("doc");
// We do not symlink to the same shared folder that already contains std library
// documentation from previous steps as we do not want to include that.
build.clear_if_dirty(&out, &rustdoc);
t!(symlink_dir_force(&out, &out_dir));
builder.clear_if_dirty(&out, &rustdoc);
t!(symlink_dir_force(&builder.config, &out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc");
compile::rustc_cargo(build, &mut cargo);
cargo.env("RUSTDOCFLAGS", "--document-private-items");
compile::rustc_cargo(builder, &mut cargo);
// Only include compiler crates, no dependencies of those, such as `libc`.
cargo.arg("--no-deps");
@ -708,19 +702,19 @@ impl Step for Rustc {
let mut compiler_crates = HashSet::new();
for root_crate in &["rustc", "rustc_driver"] {
let interned_root_crate = INTERNER.intern_str(root_crate);
find_compiler_crates(&build, &interned_root_crate, &mut compiler_crates);
find_compiler_crates(builder, &interned_root_crate, &mut compiler_crates);
}
for krate in &compiler_crates {
cargo.arg("-p").arg(krate);
}
build.run(&mut cargo);
builder.run(&mut cargo);
}
}
fn find_compiler_crates(
build: &Build,
builder: &Builder,
name: &Interned<String>,
crates: &mut HashSet<Interned<String>>
) {
@ -728,9 +722,9 @@ fn find_compiler_crates(
crates.insert(*name);
// Look for dependencies.
for dep in build.crates.get(name).unwrap().deps.iter() {
if build.crates.get(dep).unwrap().is_local(build) {
find_compiler_crates(build, dep, crates);
for dep in builder.crates.get(name).unwrap().deps.iter() {
if builder.crates.get(dep).unwrap().is_local(builder) {
find_compiler_crates(builder, dep, crates);
}
}
}
@ -747,7 +741,7 @@ impl Step for ErrorIndex {
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.path("src/tools/error_index_generator").default_condition(builder.build.config.docs)
run.path("src/tools/error_index_generator").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
@ -759,21 +753,20 @@ impl Step for ErrorIndex {
/// Generates the HTML rendered error-index by running the
/// `error_index_generator` tool.
fn run(self, builder: &Builder) {
let build = builder.build;
let target = self.target;
println!("Documenting error index ({})", target);
let out = build.doc_out(target);
builder.info(&format!("Documenting error index ({})", target));
let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
let mut index = builder.tool_cmd(Tool::ErrorIndex);
index.arg("html");
index.arg(out.join("error-index.html"));
// FIXME: shouldn't have to pass this env var
index.env("CFG_BUILD", &build.build)
.env("RUSTC_ERROR_METADATA_DST", build.extended_error_dir());
index.env("CFG_BUILD", &builder.config.build)
.env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir());
build.run(&mut index);
builder.run(&mut index);
}
}
@ -789,7 +782,7 @@ impl Step for UnstableBookGen {
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.path("src/tools/unstable-book-gen").default_condition(builder.build.config.docs)
run.path("src/tools/unstable-book-gen").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
@ -799,27 +792,29 @@ impl Step for UnstableBookGen {
}
fn run(self, builder: &Builder) {
let build = builder.build;
let target = self.target;
builder.ensure(compile::Std {
compiler: builder.compiler(builder.top_stage, build.build),
compiler: builder.compiler(builder.top_stage, builder.config.build),
target,
});
println!("Generating unstable book md files ({})", target);
let out = build.md_doc_out(target).join("unstable-book");
t!(fs::create_dir_all(&out));
t!(fs::remove_dir_all(&out));
builder.info(&format!("Generating unstable book md files ({})", target));
let out = builder.md_doc_out(target).join("unstable-book");
builder.create_dir(&out);
builder.remove_dir(&out);
let mut cmd = builder.tool_cmd(Tool::UnstableBookGen);
cmd.arg(build.src.join("src"));
cmd.arg(builder.src.join("src"));
cmd.arg(out);
build.run(&mut cmd);
builder.run(&mut cmd);
}
}
fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> {
fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()> {
if config.dry_run {
return Ok(());
}
if let Ok(m) = fs::symlink_metadata(dst) {
if m.file_type().is_dir() {
try!(fs::remove_dir_all(dst));
@ -832,5 +827,5 @@ fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> {
}
}
symlink_dir(src, dst)
symlink_dir(config, src, dst)
}

View File

@ -13,14 +13,13 @@
//! This module implements the command-line parsing of the build system which
//! has various flags to configure how it's run.
use std::env;
use std::fs;
use std::path::PathBuf;
use std::process;
use getopts::Options;
use Build;
use {Build, DocTests};
use config::Config;
use metadata;
use builder::Builder;
@ -33,17 +32,19 @@ pub struct Flags {
pub on_fail: Option<String>,
pub stage: Option<u32>,
pub keep_stage: Option<u32>,
pub build: Option<Interned<String>>,
pub host: Vec<Interned<String>>,
pub target: Vec<Interned<String>>,
pub config: Option<PathBuf>,
pub src: PathBuf,
pub jobs: Option<u32>,
pub cmd: Subcommand,
pub incremental: bool,
pub exclude: Vec<PathBuf>,
pub rustc_error_format: Option<String>,
pub dry_run: bool,
// true => deny
pub warnings: Option<bool>,
}
pub enum Subcommand {
@ -61,7 +62,7 @@ pub enum Subcommand {
test_args: Vec<String>,
rustc_args: Vec<String>,
fail_fast: bool,
doc_tests: bool,
doc_tests: DocTests,
},
Bench {
paths: Vec<PathBuf>,
@ -114,11 +115,14 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
opts.optmulti("", "target", "target targets to build", "TARGET");
opts.optmulti("", "exclude", "build paths to exclude", "PATH");
opts.optopt("", "on-fail", "command to run on failure", "CMD");
opts.optflag("", "dry-run", "dry run; don't build anything");
opts.optopt("", "stage", "stage to build", "N");
opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
opts.optflag("h", "help", "print this help message");
opts.optopt("", "warnings", "if value is deny, will deny warnings, otherwise use default",
"VALUE");
opts.optopt("", "error-format", "rustc error format", "FORMAT");
// fn usage()
@ -167,7 +171,8 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
"extra options to pass the compiler when running tests",
"ARGS",
);
opts.optflag("", "doc", "run doc tests");
opts.optflag("", "no-doc", "do not run doc tests");
opts.optflag("", "doc", "only run doc tests");
},
"bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
"clean" => { opts.optflag("", "all", "clean all build artifacts"); },
@ -278,10 +283,6 @@ Arguments:
_ => { }
};
// Get any optional paths which occur after the subcommand
let cwd = t!(env::current_dir());
let src = matches.opt_str("src").map(PathBuf::from)
.or_else(|| env::var_os("SRC").map(PathBuf::from))
.unwrap_or(cwd.clone());
let paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| {
@ -324,7 +325,13 @@ Arguments:
test_args: matches.opt_strs("test-args"),
rustc_args: matches.opt_strs("rustc-args"),
fail_fast: !matches.opt_present("no-fail-fast"),
doc_tests: matches.opt_present("doc"),
doc_tests: if matches.opt_present("doc") {
DocTests::Only
} else if matches.opt_present("no-doc") {
DocTests::No
} else {
DocTests::Yes
}
}
}
"bench" => {
@ -362,19 +369,13 @@ Arguments:
};
let mut stage = matches.opt_str("stage").map(|j| j.parse().unwrap());
if matches.opt_present("incremental") && stage.is_none() {
stage = Some(1);
}
Flags {
verbose: matches.opt_count("verbose"),
stage,
stage: matches.opt_str("stage").map(|j| j.parse().unwrap()),
dry_run: matches.opt_present("dry-run"),
on_fail: matches.opt_str("on-fail"),
rustc_error_format: matches.opt_str("error-format"),
keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()),
build: matches.opt_str("build").map(|s| INTERNER.intern_string(s)),
host: split(matches.opt_strs("host"))
.into_iter().map(|x| INTERNER.intern_string(x)).collect::<Vec<_>>(),
target: split(matches.opt_strs("target"))
@ -385,7 +386,7 @@ Arguments:
incremental: matches.opt_present("incremental"),
exclude: split(matches.opt_strs("exclude"))
.into_iter().map(|p| p.into()).collect::<Vec<_>>(),
src,
warnings: matches.opt_str("warnings").map(|v| v == "deny"),
}
}
}
@ -417,10 +418,10 @@ impl Subcommand {
}
}
pub fn doc_tests(&self) -> bool {
pub fn doc_tests(&self) -> DocTests {
match *self {
Subcommand::Test { doc_tests, .. } => doc_tests,
_ => false,
_ => DocTests::Yes,
}
}
}

View File

@ -62,8 +62,7 @@ fn install_sh(
stage: u32,
host: Option<Interned<String>>
) {
let build = builder.build;
println!("Install {} stage{} ({:?})", package, stage, host);
builder.info(&format!("Install {} stage{} ({:?})", package, stage, host));
let prefix_default = PathBuf::from("/usr/local");
let sysconfdir_default = PathBuf::from("/etc");
@ -72,13 +71,15 @@ fn install_sh(
let bindir_default = PathBuf::from("bin");
let libdir_default = PathBuf::from("lib");
let mandir_default = datadir_default.join("man");
let prefix = build.config.prefix.as_ref().unwrap_or(&prefix_default);
let sysconfdir = build.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
let datadir = build.config.datadir.as_ref().unwrap_or(&datadir_default);
let docdir = build.config.docdir.as_ref().unwrap_or(&docdir_default);
let bindir = build.config.bindir.as_ref().unwrap_or(&bindir_default);
let libdir = build.config.libdir.as_ref().unwrap_or(&libdir_default);
let mandir = build.config.mandir.as_ref().unwrap_or(&mandir_default);
let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| {
fs::canonicalize(p).expect(&format!("could not canonicalize {}", p.display()))
});
let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default);
let docdir = builder.config.docdir.as_ref().unwrap_or(&docdir_default);
let bindir = builder.config.bindir.as_ref().unwrap_or(&bindir_default);
let libdir = builder.config.libdir.as_ref().unwrap_or(&libdir_default);
let mandir = builder.config.mandir.as_ref().unwrap_or(&mandir_default);
let sysconfdir = prefix.join(sysconfdir);
let datadir = prefix.join(datadir);
@ -97,18 +98,18 @@ fn install_sh(
let libdir = add_destdir(&libdir, &destdir);
let mandir = add_destdir(&mandir, &destdir);
let empty_dir = build.out.join("tmp/empty_dir");
let empty_dir = builder.out.join("tmp/empty_dir");
t!(fs::create_dir_all(&empty_dir));
let package_name = if let Some(host) = host {
format!("{}-{}", pkgname(build, name), host)
format!("{}-{}", pkgname(builder, name), host)
} else {
pkgname(build, name)
pkgname(builder, name)
};
let mut cmd = Command::new("sh");
cmd.current_dir(&empty_dir)
.arg(sanitize_sh(&tmpdir(build).join(&package_name).join("install.sh")))
.arg(sanitize_sh(&tmpdir(builder).join(&package_name).join("install.sh")))
.arg(format!("--prefix={}", sanitize_sh(&prefix)))
.arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir)))
.arg(format!("--datadir={}", sanitize_sh(&datadir)))
@ -117,7 +118,7 @@ fn install_sh(
.arg(format!("--libdir={}", sanitize_sh(&libdir)))
.arg(format!("--mandir={}", sanitize_sh(&mandir)))
.arg("--disable-ldconfig");
build.run(&mut cmd);
builder.run(&mut cmd);
t!(fs::remove_dir_all(&empty_dir));
}
@ -178,7 +179,7 @@ macro_rules! install {
run.builder.ensure($name {
stage: run.builder.top_stage,
target: run.target,
host: run.builder.build.build,
host: run.builder.config.build,
});
}
@ -195,7 +196,7 @@ install!((self, builder, _config),
install_docs(builder, self.stage, self.target);
};
Std, "src/libstd", true, only_hosts: true, {
for target in &builder.build.targets {
for target in &builder.targets {
builder.ensure(dist::Std {
compiler: builder.compiler(self.stage, self.host),
target: *target
@ -212,7 +213,7 @@ install!((self, builder, _config),
Self::should_install(builder) {
install_rls(builder, self.stage, self.target);
} else {
println!("skipping Install RLS stage{} ({})", self.stage, self.target);
builder.info(&format!("skipping Install RLS stage{} ({})", self.stage, self.target));
}
};
Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, {
@ -220,7 +221,8 @@ install!((self, builder, _config),
Self::should_install(builder) {
install_rustfmt(builder, self.stage, self.target);
} else {
println!("skipping Install Rustfmt stage{} ({})", self.stage, self.target);
builder.info(
&format!("skipping Install Rustfmt stage{} ({})", self.stage, self.target));
}
};
Analysis, "analysis", Self::should_build(_config), only_hosts: false, {

View File

@ -122,12 +122,10 @@ struct JOBOBJECT_BASIC_LIMIT_INFORMATION {
}
pub unsafe fn setup(build: &mut Build) {
// Tell Windows to not show any UI on errors (such as not finding a required dll
// during startup or terminating abnormally). This is important for running tests,
// since some of them use abnormal termination by design.
// This mode is inherited by all child processes.
let mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags
SetErrorMode(mode | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
// Enable the Windows Error Reporting dialog which msys disables,
// so we can JIT debug rustc
let mode = SetErrorMode(0);
SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX);
// Create a new job object for us to use
let job = CreateJobObjectW(0 as *mut _, 0 as *const _);

View File

@ -115,7 +115,6 @@
#![deny(warnings)]
#![feature(core_intrinsics)]
#![feature(slice_concat_ext)]
#[macro_use]
extern crate build_helper;
@ -131,6 +130,11 @@ extern crate getopts;
extern crate num_cpus;
extern crate toml;
extern crate time;
extern crate petgraph;
#[cfg(test)]
#[macro_use]
extern crate pretty_assertions;
#[cfg(unix)]
extern crate libc;
@ -138,13 +142,15 @@ extern crate libc;
use std::cell::{RefCell, Cell};
use std::collections::{HashSet, HashMap};
use std::env;
use std::fs::{self, File};
use std::io::Read;
use std::fs::{self, OpenOptions, File};
use std::io::{self, Seek, SeekFrom, Write, Read};
use std::path::{PathBuf, Path};
use std::process::{self, Command};
use std::slice;
use std::str;
use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime};
use filetime::FileTime;
use util::{exe, libdir, OutputFolder, CiEnv};
@ -198,12 +204,22 @@ use toolstate::ToolState;
/// Each compiler has a `stage` that it is associated with and a `host` that
/// corresponds to the platform the compiler runs on. This structure is used as
/// a parameter to many methods below.
#[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)]
#[derive(Eq, PartialOrd, Ord, PartialEq, Clone, Copy, Hash, Debug)]
pub struct Compiler {
stage: u32,
host: Interned<String>,
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum DocTests {
// Default, run normal tests and doc tests.
Yes,
// Do not run any doc tests.
No,
// Only run doc tests.
Only,
}
/// Global configuration for the build system.
///
/// This structure transitively contains all configuration for the build system.
@ -227,7 +243,7 @@ pub struct Build {
rustfmt_info: channel::GitInfo,
local_rebuild: bool,
fail_fast: bool,
doc_tests: bool,
doc_tests: DocTests,
verbosity: usize,
// Targets for which to build.
@ -288,7 +304,7 @@ impl Crate {
///
/// These entries currently correspond to the various output directories of the
/// build system, with each mod generating output in a different directory.
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Mode {
/// Build the standard library, placing output in the "stageN-std" directory.
Libstd,
@ -309,9 +325,8 @@ impl Build {
///
/// By default all build output will be placed in the current directory.
pub fn new(config: Config) -> Build {
let cwd = t!(env::current_dir());
let src = config.src.clone();
let out = cwd.join("build");
let out = config.out.clone();
let is_sudo = match env::var_os("SUDO_USER") {
Some(sudo_user) => {
@ -327,7 +342,7 @@ impl Build {
let rls_info = channel::GitInfo::new(&config, &src.join("src/tools/rls"));
let rustfmt_info = channel::GitInfo::new(&config, &src.join("src/tools/rustfmt"));
Build {
let mut build = Build {
initial_rustc: config.initial_rustc.clone(),
initial_cargo: config.initial_cargo.clone(),
local_rebuild: config.local_rebuild,
@ -358,7 +373,30 @@ impl Build {
delayed_failures: RefCell::new(Vec::new()),
prerelease_version: Cell::new(None),
tool_artifacts: Default::default(),
};
build.verbose("finding compilers");
cc_detect::find(&mut build);
build.verbose("running sanity check");
sanity::check(&mut build);
// If local-rust is the same major.minor as the current version, then force a
// local-rebuild
let local_version_verbose = output(
Command::new(&build.initial_rustc).arg("--version").arg("--verbose"));
let local_release = local_version_verbose
.lines().filter(|x| x.starts_with("release:"))
.next().unwrap().trim_left_matches("release:").trim();
let my_version = channel::CFG_RELEASE_NUM;
if local_release.split('.').take(2).eq(my_version.split('.').take(2)) {
build.verbose(&format!("auto-detected local-rebuild {}", local_release));
build.local_rebuild = true;
}
build.verbose("learning about cargo");
metadata::build(&mut build);
build
}
pub fn build_triple(&self) -> &[Interned<String>] {
@ -377,25 +415,28 @@ impl Build {
return clean::clean(self, all);
}
self.verbose("finding compilers");
cc_detect::find(self);
self.verbose("running sanity check");
sanity::check(self);
// If local-rust is the same major.minor as the current version, then force a local-rebuild
let local_version_verbose = output(
Command::new(&self.initial_rustc).arg("--version").arg("--verbose"));
let local_release = local_version_verbose
.lines().filter(|x| x.starts_with("release:"))
.next().unwrap().trim_left_matches("release:").trim();
let my_version = channel::CFG_RELEASE_NUM;
if local_release.split('.').take(2).eq(my_version.split('.').take(2)) {
self.verbose(&format!("auto-detected local-rebuild {}", local_release));
self.local_rebuild = true;
{
let builder = builder::Builder::new(&self);
if let Some(path) = builder.paths.get(0) {
if path == Path::new("nonexistent/path/to/trigger/cargo/metadata") {
return;
}
}
}
self.verbose("learning about cargo");
metadata::build(self);
builder::Builder::run(&self);
if !self.config.dry_run {
{
self.config.dry_run = true;
let builder = builder::Builder::new(&self);
builder.execute_cli();
}
self.config.dry_run = false;
let builder = builder::Builder::new(&self);
builder.execute_cli();
} else {
let builder = builder::Builder::new(&self);
let _ = builder.execute_cli();
}
// Check for postponed failures from `test --no-fail-fast`.
let failures = self.delayed_failures.borrow();
@ -586,12 +627,14 @@ impl Build {
/// Runs a command, printing out nice contextual information if it fails.
fn run(&self, cmd: &mut Command) {
if self.config.dry_run { return; }
self.verbose(&format!("running: {:?}", cmd));
run_silent(cmd)
}
/// Runs a command, printing out nice contextual information if it fails.
fn run_quiet(&self, cmd: &mut Command) {
if self.config.dry_run { return; }
self.verbose(&format!("running: {:?}", cmd));
run_suppressed(cmd)
}
@ -600,6 +643,7 @@ impl Build {
/// Exits if the command failed to execute at all, otherwise returns its
/// `status.success()`.
fn try_run(&self, cmd: &mut Command) -> bool {
if self.config.dry_run { return true; }
self.verbose(&format!("running: {:?}", cmd));
try_run_silent(cmd)
}
@ -608,6 +652,7 @@ impl Build {
/// Exits if the command failed to execute at all, otherwise returns its
/// `status.success()`.
fn try_run_quiet(&self, cmd: &mut Command) -> bool {
if self.config.dry_run { return true; }
self.verbose(&format!("running: {:?}", cmd));
try_run_suppressed(cmd)
}
@ -623,6 +668,11 @@ impl Build {
}
}
fn info(&self, msg: &str) {
if self.config.dry_run { return; }
println!("{}", msg);
}
/// Returns the number of parallel jobs that have been configured for this
/// build.
fn jobs(&self) -> u32 {
@ -709,6 +759,12 @@ impl Build {
.map(|p| &**p)
}
/// Returns true if this is a no-std `target`, if defined
fn no_std(&self, target: Interned<String>) -> Option<bool> {
self.config.target_config.get(&target)
.map(|t| t.no_std)
}
/// Returns whether the target will be tested using the `remote-test-client`
/// and `remote-test-server` binaries.
fn remote_tested(&self, target: Interned<String>) -> bool {
@ -930,7 +986,7 @@ impl Build {
pub fn fold_output<D, F>(&self, name: F) -> Option<OutputFolder>
where D: Into<String>, F: FnOnce() -> D
{
if self.ci_env == CiEnv::Travis {
if !self.config.dry_run && self.ci_env == CiEnv::Travis {
Some(OutputFolder::new(name().into()))
} else {
None
@ -978,8 +1034,173 @@ impl Build {
}
ret
}
fn read_stamp_file(&self, stamp: &Path) -> Vec<PathBuf> {
if self.config.dry_run {
return Vec::new();
}
let mut paths = Vec::new();
let mut contents = Vec::new();
t!(t!(File::open(stamp)).read_to_end(&mut contents));
// This is the method we use for extracting paths from the stamp file passed to us. See
// run_cargo for more information (in compile.rs).
for part in contents.split(|b| *b == 0) {
if part.is_empty() {
continue
}
let path = PathBuf::from(t!(str::from_utf8(part)));
paths.push(path);
}
paths
}
/// Copies a file from `src` to `dst`
pub fn copy(&self, src: &Path, dst: &Path) {
if self.config.dry_run { return; }
let _ = fs::remove_file(&dst);
// Attempt to "easy copy" by creating a hard link (symlinks don't work on
// windows), but if that fails just fall back to a slow `copy` operation.
if let Ok(()) = fs::hard_link(src, dst) {
return
}
if let Err(e) = fs::copy(src, dst) {
panic!("failed to copy `{}` to `{}`: {}", src.display(),
dst.display(), e)
}
let metadata = t!(src.metadata());
t!(fs::set_permissions(dst, metadata.permissions()));
let atime = FileTime::from_last_access_time(&metadata);
let mtime = FileTime::from_last_modification_time(&metadata);
t!(filetime::set_file_times(dst, atime, mtime));
}
/// Search-and-replaces within a file. (Not maximally efficiently: allocates a
/// new string for each replacement.)
pub fn replace_in_file(&self, path: &Path, replacements: &[(&str, &str)]) {
if self.config.dry_run { return; }
let mut contents = String::new();
let mut file = t!(OpenOptions::new().read(true).write(true).open(path));
t!(file.read_to_string(&mut contents));
for &(target, replacement) in replacements {
contents = contents.replace(target, replacement);
}
t!(file.seek(SeekFrom::Start(0)));
t!(file.set_len(0));
t!(file.write_all(contents.as_bytes()));
}
/// Copies the `src` directory recursively to `dst`. Both are assumed to exist
/// when this function is called.
pub fn cp_r(&self, src: &Path, dst: &Path) {
if self.config.dry_run { return; }
for f in t!(fs::read_dir(src)) {
let f = t!(f);
let path = f.path();
let name = path.file_name().unwrap();
let dst = dst.join(name);
if t!(f.file_type()).is_dir() {
t!(fs::create_dir_all(&dst));
self.cp_r(&path, &dst);
} else {
let _ = fs::remove_file(&dst);
self.copy(&path, &dst);
}
}
}
/// Copies the `src` directory recursively to `dst`. Both are assumed to exist
/// when this function is called. Unwanted files or directories can be skipped
/// by returning `false` from the filter function.
pub fn cp_filtered(&self, src: &Path, dst: &Path, filter: &Fn(&Path) -> bool) {
// Immediately recurse with an empty relative path
self.recurse_(src, dst, Path::new(""), filter)
}
// Inner function does the actual work
fn recurse_(&self, src: &Path, dst: &Path, relative: &Path, filter: &Fn(&Path) -> bool) {
for f in self.read_dir(src) {
let path = f.path();
let name = path.file_name().unwrap();
let dst = dst.join(name);
let relative = relative.join(name);
// Only copy file or directory if the filter function returns true
if filter(&relative) {
if t!(f.file_type()).is_dir() {
let _ = fs::remove_dir_all(&dst);
self.create_dir(&dst);
self.recurse_(&path, &dst, &relative, filter);
} else {
let _ = fs::remove_file(&dst);
self.copy(&path, &dst);
}
}
}
}
fn copy_to_folder(&self, src: &Path, dest_folder: &Path) {
let file_name = src.file_name().unwrap();
let dest = dest_folder.join(file_name);
self.copy(src, &dest);
}
fn install(&self, src: &Path, dstdir: &Path, perms: u32) {
if self.config.dry_run { return; }
let dst = dstdir.join(src.file_name().unwrap());
t!(fs::create_dir_all(dstdir));
drop(fs::remove_file(&dst));
{
let mut s = t!(fs::File::open(&src));
let mut d = t!(fs::File::create(&dst));
io::copy(&mut s, &mut d).expect("failed to copy");
}
chmod(&dst, perms);
}
fn create(&self, path: &Path, s: &str) {
if self.config.dry_run { return; }
t!(fs::write(path, s));
}
fn read(&self, path: &Path) -> String {
if self.config.dry_run { return String::new(); }
t!(fs::read_to_string(path))
}
fn create_dir(&self, dir: &Path) {
if self.config.dry_run { return; }
t!(fs::create_dir_all(dir))
}
fn remove_dir(&self, dir: &Path) {
if self.config.dry_run { return; }
t!(fs::remove_dir_all(dir))
}
fn read_dir(&self, dir: &Path) -> impl Iterator<Item=fs::DirEntry> {
let iter = match fs::read_dir(dir) {
Ok(v) => v,
Err(_) if self.config.dry_run => return vec![].into_iter(),
Err(err) => panic!("could not read dir {:?}: {:?}", dir, err),
};
iter.map(|e| t!(e)).collect::<Vec<_>>().into_iter()
}
fn remove(&self, f: &Path) {
if self.config.dry_run { return; }
fs::remove_file(f).unwrap_or_else(|_| panic!("failed to remove {:?}", f));
}
}
#[cfg(unix)]
fn chmod(path: &Path, perms: u32) {
use std::os::unix::fs::*;
t!(fs::set_permissions(path, fs::Permissions::from_mode(perms)));
}
#[cfg(windows)]
fn chmod(_path: &Path, _perms: u32) {}
impl<'a> Compiler {
pub fn with_stage(mut self, stage: u32) -> Compiler {
self.stage = stage;

View File

@ -29,7 +29,6 @@ use build_helper::output;
use cmake;
use cc;
use Build;
use util::{self, exe};
use build_helper::up_to_date;
use builder::{Builder, RunConfig, ShouldRun, Step};
@ -60,39 +59,38 @@ impl Step for Llvm {
/// Compile LLVM for `target`.
fn run(self, builder: &Builder) -> PathBuf {
let build = builder.build;
let target = self.target;
let emscripten = self.emscripten;
// If we're using a custom LLVM bail out here, but we can only use a
// custom LLVM for the build triple.
if !self.emscripten {
if let Some(config) = build.config.target_config.get(&target) {
if let Some(config) = builder.config.target_config.get(&target) {
if let Some(ref s) = config.llvm_config {
check_llvm_version(build, s);
check_llvm_version(builder, s);
return s.to_path_buf()
}
}
}
let rebuild_trigger = build.src.join("src/rustllvm/llvm-rebuild-trigger");
let rebuild_trigger = builder.src.join("src/rustllvm/llvm-rebuild-trigger");
let mut rebuild_trigger_contents = String::new();
t!(t!(File::open(&rebuild_trigger)).read_to_string(&mut rebuild_trigger_contents));
let (out_dir, llvm_config_ret_dir) = if emscripten {
let dir = build.emscripten_llvm_out(target);
let dir = builder.emscripten_llvm_out(target);
let config_dir = dir.join("bin");
(dir, config_dir)
} else {
let mut dir = build.llvm_out(build.config.build);
if !build.config.build.contains("msvc") || build.config.ninja {
let mut dir = builder.llvm_out(builder.config.build);
if !builder.config.build.contains("msvc") || builder.config.ninja {
dir.push("build");
}
(build.llvm_out(target), dir.join("bin"))
(builder.llvm_out(target), dir.join("bin"))
};
let done_stamp = out_dir.join("llvm-finished-building");
let build_llvm_config = llvm_config_ret_dir
.join(exe("llvm-config", &*build.config.build));
.join(exe("llvm-config", &*builder.config.build));
if done_stamp.exists() {
let mut done_contents = String::new();
t!(t!(File::open(&done_stamp)).read_to_string(&mut done_contents));
@ -104,17 +102,17 @@ impl Step for Llvm {
}
}
let _folder = build.fold_output(|| "llvm");
let _folder = builder.fold_output(|| "llvm");
let descriptor = if emscripten { "Emscripten " } else { "" };
println!("Building {}LLVM for {}", descriptor, target);
let _time = util::timeit();
builder.info(&format!("Building {}LLVM for {}", descriptor, target));
let _time = util::timeit(&builder);
t!(fs::create_dir_all(&out_dir));
// http://llvm.org/docs/CMake.html
let root = if self.emscripten { "src/llvm-emscripten" } else { "src/llvm" };
let mut cfg = cmake::Config::new(build.src.join(root));
let mut cfg = cmake::Config::new(builder.src.join(root));
let profile = match (build.config.llvm_optimize, build.config.llvm_release_debuginfo) {
let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) {
(false, _) => "Debug",
(true, false) => "Release",
(true, true) => "RelWithDebInfo",
@ -125,7 +123,7 @@ impl Step for Llvm {
let llvm_targets = if self.emscripten {
"JSBackend"
} else {
match build.config.llvm_targets {
match builder.config.llvm_targets {
Some(ref s) => s,
None => "X86;ARM;AArch64;Mips;PowerPC;SystemZ;MSP430;Sparc;NVPTX;Hexagon",
}
@ -134,10 +132,10 @@ impl Step for Llvm {
let llvm_exp_targets = if self.emscripten {
""
} else {
&build.config.llvm_experimental_targets[..]
&builder.config.llvm_experimental_targets[..]
};
let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"};
let assertions = if builder.config.llvm_assertions {"ON"} else {"OFF"};
cfg.out_dir(&out_dir)
.profile(profile)
@ -151,7 +149,8 @@ impl Step for Llvm {
.define("WITH_POLLY", "OFF")
.define("LLVM_ENABLE_TERMINFO", "OFF")
.define("LLVM_ENABLE_LIBEDIT", "OFF")
.define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string())
.define("LLVM_ENABLE_LIBXML2", "OFF")
.define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string())
.define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
.define("LLVM_DEFAULT_TARGET_TRIPLE", target);
@ -183,22 +182,22 @@ impl Step for Llvm {
cfg.define("LLVM_BUILD_32_BITS", "ON");
}
if let Some(num_linkers) = build.config.llvm_link_jobs {
if let Some(num_linkers) = builder.config.llvm_link_jobs {
if num_linkers > 0 {
cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string());
}
}
// http://llvm.org/docs/HowToCrossCompileLLVM.html
if target != build.build && !emscripten {
if target != builder.config.build && !emscripten {
builder.ensure(Llvm {
target: build.build,
target: builder.config.build,
emscripten: false,
});
// FIXME: if the llvm root for the build triple is overridden then we
// should use llvm-tblgen from there, also should verify that it
// actually exists most of the time in normal installs of LLVM.
let host = build.llvm_out(build.build).join("bin/llvm-tblgen");
let host = builder.llvm_out(builder.config.build).join("bin/llvm-tblgen");
cfg.define("CMAKE_CROSSCOMPILING", "True")
.define("LLVM_TABLEGEN", &host);
@ -208,15 +207,20 @@ impl Step for Llvm {
cfg.define("CMAKE_SYSTEM_NAME", "FreeBSD");
}
cfg.define("LLVM_NATIVE_BUILD", build.llvm_out(build.build).join("build"));
cfg.define("LLVM_NATIVE_BUILD", builder.llvm_out(builder.config.build).join("build"));
}
configure_cmake(build, target, &mut cfg, false);
configure_cmake(builder, target, &mut cfg, false);
// 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
// tools and libs on all platforms.
if builder.config.dry_run {
return build_llvm_config;
}
cfg.build();
t!(t!(File::create(&done_stamp)).write_all(rebuild_trigger_contents.as_bytes()));
@ -225,11 +229,15 @@ impl Step for Llvm {
}
}
fn check_llvm_version(build: &Build, llvm_config: &Path) {
if !build.config.llvm_version_check {
fn check_llvm_version(builder: &Builder, llvm_config: &Path) {
if !builder.config.llvm_version_check {
return
}
if builder.config.dry_run {
return;
}
let mut cmd = Command::new(llvm_config);
let version = output(cmd.arg("--version"));
let mut parts = version.split('.').take(2)
@ -242,15 +250,15 @@ fn check_llvm_version(build: &Build, llvm_config: &Path) {
panic!("\n\nbad LLVM version: {}, need >=3.9\n\n", version)
}
fn configure_cmake(build: &Build,
fn configure_cmake(builder: &Builder,
target: Interned<String>,
cfg: &mut cmake::Config,
building_dist_binaries: bool) {
if build.config.ninja {
if builder.config.ninja {
cfg.generator("Ninja");
}
cfg.target(&target)
.host(&build.config.build);
.host(&builder.config.build);
let sanitize_cc = |cc: &Path| {
if target.contains("msvc") {
@ -263,29 +271,29 @@ fn configure_cmake(build: &Build,
// MSVC with CMake uses msbuild by default which doesn't respect these
// vars that we'd otherwise configure. In that case we just skip this
// entirely.
if target.contains("msvc") && !build.config.ninja {
if target.contains("msvc") && !builder.config.ninja {
return
}
let cc = build.cc(target);
let cxx = build.cxx(target).unwrap();
let cc = builder.cc(target);
let cxx = builder.cxx(target).unwrap();
// Handle msvc + ninja + ccache specially (this is what the bots use)
if target.contains("msvc") &&
build.config.ninja &&
build.config.ccache.is_some() {
builder.config.ninja &&
builder.config.ccache.is_some() {
let mut cc = env::current_exe().expect("failed to get cwd");
cc.set_file_name("sccache-plus-cl.exe");
cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc))
.define("CMAKE_CXX_COMPILER", sanitize_cc(&cc));
cfg.env("SCCACHE_PATH",
build.config.ccache.as_ref().unwrap())
builder.config.ccache.as_ref().unwrap())
.env("SCCACHE_TARGET", target);
// If ccache is configured we inform the build a little differently hwo
// to invoke ccache while also invoking our compilers.
} else if let Some(ref ccache) = build.config.ccache {
} else if let Some(ref ccache) = builder.config.ccache {
cfg.define("CMAKE_C_COMPILER", ccache)
.define("CMAKE_C_COMPILER_ARG1", sanitize_cc(cc))
.define("CMAKE_CXX_COMPILER", ccache)
@ -295,16 +303,16 @@ fn configure_cmake(build: &Build,
.define("CMAKE_CXX_COMPILER", sanitize_cc(cxx));
}
cfg.build_arg("-j").build_arg(build.jobs().to_string());
cfg.define("CMAKE_C_FLAGS", build.cflags(target).join(" "));
let mut cxxflags = build.cflags(target).join(" ");
cfg.build_arg("-j").build_arg(builder.jobs().to_string());
cfg.define("CMAKE_C_FLAGS", builder.cflags(target).join(" "));
let mut cxxflags = builder.cflags(target).join(" ");
if building_dist_binaries {
if build.config.llvm_static_stdcpp && !target.contains("windows") {
if builder.config.llvm_static_stdcpp && !target.contains("windows") {
cxxflags.push_str(" -static-libstdc++");
}
}
cfg.define("CMAKE_CXX_FLAGS", cxxflags);
if let Some(ar) = build.ar(target) {
if let Some(ar) = builder.ar(target) {
if ar.is_absolute() {
// LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it
// tries to resolve this path in the LLVM build directory.
@ -336,27 +344,29 @@ impl Step for Lld {
/// Compile LLVM for `target`.
fn run(self, builder: &Builder) -> PathBuf {
if builder.config.dry_run {
return PathBuf::from("lld-out-dir-test-gen");
}
let target = self.target;
let build = builder.build;
let llvm_config = builder.ensure(Llvm {
target: self.target,
emscripten: false,
});
let out_dir = build.lld_out(target);
let out_dir = builder.lld_out(target);
let done_stamp = out_dir.join("lld-finished-building");
if done_stamp.exists() {
return out_dir
}
let _folder = build.fold_output(|| "lld");
println!("Building LLD for {}", target);
let _time = util::timeit();
let _folder = builder.fold_output(|| "lld");
builder.info(&format!("Building LLD for {}", target));
let _time = util::timeit(&builder);
t!(fs::create_dir_all(&out_dir));
let mut cfg = cmake::Config::new(build.src.join("src/tools/lld"));
configure_cmake(build, target, &mut cfg, true);
let mut cfg = cmake::Config::new(builder.src.join("src/tools/lld"));
configure_cmake(builder, target, &mut cfg, true);
cfg.out_dir(&out_dir)
.profile("Release")
@ -389,16 +399,18 @@ impl Step for TestHelpers {
/// Compiles the `rust_test_helpers.c` library which we used in various
/// `run-pass` test suites for ABI testing.
fn run(self, builder: &Builder) {
let build = builder.build;
if builder.config.dry_run {
return;
}
let target = self.target;
let dst = build.test_helpers_out(target);
let src = build.src.join("src/test/auxiliary/rust_test_helpers.c");
let dst = builder.test_helpers_out(target);
let src = builder.src.join("src/test/auxiliary/rust_test_helpers.c");
if up_to_date(&src, &dst.join("librust_test_helpers.a")) {
return
}
let _folder = build.fold_output(|| "build_test_helpers");
println!("Building test helpers");
let _folder = builder.fold_output(|| "build_test_helpers");
builder.info(&format!("Building test helpers"));
t!(fs::create_dir_all(&dst));
let mut cfg = cc::Build::new();
@ -406,20 +418,20 @@ impl Step for TestHelpers {
// extra configuration, so inform gcc of these compilers. Note, though, that
// on MSVC we still need gcc's detection of env vars (ugh).
if !target.contains("msvc") {
if let Some(ar) = build.ar(target) {
if let Some(ar) = builder.ar(target) {
cfg.archiver(ar);
}
cfg.compiler(build.cc(target));
cfg.compiler(builder.cc(target));
}
cfg.cargo_metadata(false)
.out_dir(&dst)
.target(&target)
.host(&build.build)
.host(&builder.config.build)
.opt_level(0)
.warnings(false)
.debug(false)
.file(build.src.join("src/test/auxiliary/rust_test_helpers.c"))
.file(builder.src.join("src/test/auxiliary/rust_test_helpers.c"))
.compile("rust_test_helpers");
}
}
@ -441,9 +453,11 @@ impl Step for Openssl {
}
fn run(self, builder: &Builder) {
let build = builder.build;
if builder.config.dry_run {
return;
}
let target = self.target;
let out = match build.openssl_dir(target) {
let out = match builder.openssl_dir(target) {
Some(dir) => dir,
None => return,
};
@ -479,7 +493,8 @@ impl Step for Openssl {
}
// Ensure the hash is correct.
let mut shasum = if target.contains("apple") || build.build.contains("netbsd") {
let mut shasum = if target.contains("apple") ||
builder.config.build.contains("netbsd") {
let mut cmd = Command::new("shasum");
cmd.arg("-a").arg("256");
cmd
@ -512,10 +527,10 @@ impl Step for Openssl {
t!(fs::rename(&tmp, &tarball));
}
let obj = out.join(format!("openssl-{}", OPENSSL_VERS));
let dst = build.openssl_install_dir(target).unwrap();
let dst = builder.openssl_install_dir(target).unwrap();
drop(fs::remove_dir_all(&obj));
drop(fs::remove_dir_all(&dst));
build.run(Command::new("tar").arg("zxf").arg(&tarball).current_dir(&out));
builder.run(Command::new("tar").arg("zxf").arg(&tarball).current_dir(&out));
let mut configure = Command::new("perl");
configure.arg(obj.join("Configure"));
@ -565,8 +580,8 @@ impl Step for Openssl {
_ => panic!("don't know how to configure OpenSSL for {}", target),
};
configure.arg(os);
configure.env("CC", build.cc(target));
for flag in build.cflags(target) {
configure.env("CC", builder.cc(target));
for flag in builder.cflags(target) {
configure.arg(flag);
}
// There is no specific os target for android aarch64 or x86_64,
@ -578,7 +593,7 @@ impl Step for Openssl {
if target == "sparc64-unknown-netbsd" {
// Need -m64 to get assembly generated correctly for sparc64.
configure.arg("-m64");
if build.build.contains("netbsd") {
if builder.config.build.contains("netbsd") {
// Disable sparc64 asm on NetBSD builders, it uses
// m4(1)'s -B flag, which NetBSD m4 does not support.
configure.arg("no-asm");
@ -591,12 +606,12 @@ impl Step for Openssl {
configure.arg("no-asm");
}
configure.current_dir(&obj);
println!("Configuring openssl for {}", target);
build.run_quiet(&mut configure);
println!("Building openssl for {}", target);
build.run_quiet(Command::new("make").arg("-j1").current_dir(&obj));
println!("Installing openssl for {}", target);
build.run_quiet(Command::new("make").arg("install").arg("-j1").current_dir(&obj));
builder.info(&format!("Configuring openssl for {}", target));
builder.run_quiet(&mut configure);
builder.info(&format!("Building openssl for {}", target));
builder.run_quiet(Command::new("make").arg("-j1").current_dir(&obj));
builder.info(&format!("Installing openssl for {}", target));
builder.run_quiet(Command::new("make").arg("install").arg("-j1").current_dir(&obj));
let mut f = t!(File::create(&stamp));
t!(f.write_all(OPENSSL_VERS.as_bytes()));

View File

@ -140,14 +140,18 @@ pub fn check(build: &mut Build) {
continue;
}
cmd_finder.must_have(build.cc(*target));
if let Some(ar) = build.ar(*target) {
cmd_finder.must_have(ar);
if !build.config.dry_run {
cmd_finder.must_have(build.cc(*target));
if let Some(ar) = build.ar(*target) {
cmd_finder.must_have(ar);
}
}
}
for host in &build.hosts {
cmd_finder.must_have(build.cxx(*host).unwrap());
if !build.config.dry_run {
cmd_finder.must_have(build.cxx(*host).unwrap());
}
// The msvc hosts don't use jemalloc, turn it off globally to
// avoid packaging the dummy liballoc_jemalloc on that platform.
@ -169,6 +173,19 @@ pub fn check(build: &mut Build) {
panic!("the iOS target is only supported on macOS");
}
if target.contains("-none-") {
if build.no_std(*target).is_none() {
let target = build.config.target_config.entry(target.clone())
.or_insert(Default::default());
target.no_std = true;
}
if build.no_std(*target) == Some(false) {
panic!("All the *-none-* targets are no-std targets")
}
}
// Make sure musl-root is valid
if target.contains("musl") {
// If this is a native target (host is also musl) and no musl-root is given,

File diff suppressed because it is too large Load Diff

View File

@ -10,14 +10,14 @@
use std::fs;
use std::env;
use std::iter;
use std::path::PathBuf;
use std::process::{Command, exit};
use std::slice::SliceConcatExt;
use Mode;
use Compiler;
use builder::{Step, RunConfig, ShouldRun, Builder};
use util::{copy, exe, add_lib_path};
use util::{exe, add_lib_path};
use compile::{self, libtest_stamp, libstd_stamp, librustc_stamp};
use native;
use channel::GitInfo;
@ -39,7 +39,6 @@ impl Step for CleanTools {
}
fn run(self, builder: &Builder) {
let build = builder.build;
let compiler = self.compiler;
let target = self.target;
let mode = self.mode;
@ -47,7 +46,7 @@ impl Step for CleanTools {
// This is for the original compiler, but if we're forced to use stage 1, then
// std/test/rustc stamps won't exist in stage 2, so we need to get those from stage 1, since
// we copy the libs forward.
let tools_dir = build.stage_out(compiler, Mode::Tool);
let tools_dir = builder.stage_out(compiler, Mode::Tool);
let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
@ -56,13 +55,13 @@ impl Step for CleanTools {
for &cur_mode in &[Mode::Libstd, Mode::Libtest, Mode::Librustc] {
let stamp = match cur_mode {
Mode::Libstd => libstd_stamp(build, compiler, target),
Mode::Libtest => libtest_stamp(build, compiler, target),
Mode::Librustc => librustc_stamp(build, compiler, target),
Mode::Libstd => libstd_stamp(builder, compiler, target),
Mode::Libtest => libtest_stamp(builder, compiler, target),
Mode::Librustc => librustc_stamp(builder, compiler, target),
_ => panic!(),
};
if build.clear_if_dirty(&tools_dir, &stamp) {
if builder.clear_if_dirty(&tools_dir, &stamp) {
break;
}
@ -98,7 +97,6 @@ impl Step for ToolBuild {
/// This will build the specified tool with the specified `host` compiler in
/// `stage` into the normal cargo output directory.
fn run(self, builder: &Builder) -> Option<PathBuf> {
let build = builder.build;
let compiler = self.compiler;
let target = self.target;
let tool = self.tool;
@ -115,10 +113,10 @@ impl Step for ToolBuild {
let mut cargo = prepare_tool_cargo(builder, compiler, target, "build", path);
cargo.arg("--features").arg(self.extra_features.join(" "));
let _folder = build.fold_output(|| format!("stage{}-{}", compiler.stage, tool));
println!("Building stage{} tool {} ({})", compiler.stage, tool, target);
let _folder = builder.fold_output(|| format!("stage{}-{}", compiler.stage, tool));
builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target));
let mut duplicates = Vec::new();
let is_expected = compile::stream_cargo(build, &mut cargo, &mut |msg| {
let is_expected = compile::stream_cargo(builder, &mut cargo, &mut |msg| {
// Only care about big things like the RLS/Cargo for now
if tool != "rls" && tool != "cargo" {
return
@ -157,7 +155,7 @@ impl Step for ToolBuild {
}
}
let mut artifacts = build.tool_artifacts.borrow_mut();
let mut artifacts = builder.tool_artifacts.borrow_mut();
let prev_artifacts = artifacts
.entry(target)
.or_insert_with(Default::default);
@ -191,7 +189,7 @@ impl Step for ToolBuild {
panic!("tools should not compile multiple copies of the same crate");
}
build.save_toolstate(tool, if is_expected {
builder.save_toolstate(tool, if is_expected {
ToolState::TestFail
} else {
ToolState::BuildFail
@ -204,10 +202,10 @@ impl Step for ToolBuild {
return None;
}
} else {
let cargo_out = build.cargo_out(compiler, Mode::Tool, target)
let cargo_out = builder.cargo_out(compiler, Mode::Tool, target)
.join(exe(tool, &compiler.host));
let bin = build.tools_dir(compiler).join(exe(tool, &compiler.host));
copy(&cargo_out, &bin);
let bin = builder.tools_dir(compiler).join(exe(tool, &compiler.host));
builder.copy(&cargo_out, &bin);
Some(bin)
}
}
@ -220,16 +218,15 @@ pub fn prepare_tool_cargo(
command: &'static str,
path: &'static str,
) -> Command {
let build = builder.build;
let mut cargo = builder.cargo(compiler, Mode::Tool, target, command);
let dir = build.src.join(path);
let dir = builder.src.join(path);
cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
// We don't want to build tools dynamically as they'll be running across
// stages and such and it's just easier if they're not dynamically linked.
cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
if let Some(dir) = build.openssl_install_dir(target) {
if let Some(dir) = builder.openssl_install_dir(target) {
cargo.env("OPENSSL_STATIC", "1");
cargo.env("OPENSSL_DIR", dir);
cargo.env("LIBZ_SYS_STATIC", "1");
@ -239,10 +236,10 @@ pub fn prepare_tool_cargo(
// own copy
cargo.env("LZMA_API_STATIC", "1");
cargo.env("CFG_RELEASE_CHANNEL", &build.config.channel);
cargo.env("CFG_VERSION", build.rust_version());
cargo.env("CFG_RELEASE_CHANNEL", &builder.config.channel);
cargo.env("CFG_VERSION", builder.rust_version());
let info = GitInfo::new(&build.config, &dir);
let info = GitInfo::new(&builder.config, &dir);
if let Some(sha) = info.sha() {
cargo.env("CFG_COMMIT_HASH", sha);
}
@ -270,8 +267,8 @@ macro_rules! tool {
match tool {
$(Tool::$name =>
self.ensure($name {
compiler: self.compiler(stage, self.build.build),
target: self.build.build,
compiler: self.compiler(stage, self.config.build),
target: self.config.build,
}),
)+
}
@ -305,7 +302,7 @@ macro_rules! tool {
fn make_run(run: RunConfig) {
run.builder.ensure($name {
compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
target: run.target,
});
}
@ -355,7 +352,7 @@ impl Step for RemoteTestServer {
fn make_run(run: RunConfig) {
run.builder.ensure(RemoteTestServer {
compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
target: run.target,
});
}
@ -394,26 +391,25 @@ impl Step for Rustdoc {
}
fn run(self, builder: &Builder) -> PathBuf {
let build = builder.build;
let target_compiler = builder.compiler(builder.top_stage, self.host);
let target = target_compiler.host;
let build_compiler = if target_compiler.stage == 0 {
builder.compiler(0, builder.build.build)
builder.compiler(0, builder.config.build)
} else if target_compiler.stage >= 2 {
// Past stage 2, we consider the compiler to be ABI-compatible and hence capable of
// building rustdoc itself.
builder.compiler(target_compiler.stage, builder.build.build)
builder.compiler(target_compiler.stage, builder.config.build)
} else {
// Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
// we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage
// compilers, which isn't what we want.
builder.compiler(target_compiler.stage - 1, builder.build.build)
builder.compiler(target_compiler.stage - 1, builder.config.build)
};
builder.ensure(compile::Rustc { compiler: build_compiler, target });
builder.ensure(compile::Rustc {
compiler: build_compiler,
target: builder.build.build,
target: builder.config.build,
});
let mut cargo = prepare_tool_cargo(builder,
@ -426,14 +422,15 @@ impl Step for Rustdoc {
cargo.env("RUSTC_DEBUGINFO", builder.config.rust_debuginfo.to_string())
.env("RUSTC_DEBUGINFO_LINES", builder.config.rust_debuginfo_lines.to_string());
let _folder = build.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage));
println!("Building rustdoc for stage{} ({})", target_compiler.stage, target_compiler.host);
build.run(&mut cargo);
let _folder = builder.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage));
builder.info(&format!("Building rustdoc for stage{} ({})",
target_compiler.stage, target_compiler.host));
builder.run(&mut cargo);
// Cargo adds a number of paths to the dylib search path on windows, which results in
// the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
// rustdoc a different name.
let tool_rustdoc = build.cargo_out(build_compiler, Mode::Tool, target)
let tool_rustdoc = builder.cargo_out(build_compiler, Mode::Tool, target)
.join(exe("rustdoc-tool-binary", &target_compiler.host));
// don't create a stage0-sysroot/bin directory.
@ -443,7 +440,7 @@ impl Step for Rustdoc {
t!(fs::create_dir_all(&bindir));
let bin_rustdoc = bindir.join(exe("rustdoc", &*target_compiler.host));
let _ = fs::remove_file(&bin_rustdoc);
copy(&tool_rustdoc, &bin_rustdoc);
builder.copy(&tool_rustdoc, &bin_rustdoc);
bin_rustdoc
} else {
tool_rustdoc
@ -464,12 +461,12 @@ impl Step for Cargo {
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.path("src/tools/cargo").default_condition(builder.build.config.extended)
run.path("src/tools/cargo").default_condition(builder.config.extended)
}
fn make_run(run: RunConfig) {
run.builder.ensure(Cargo {
compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
target: run.target,
});
}
@ -482,7 +479,7 @@ impl Step for Cargo {
// compiler to be available, so we need to depend on that.
builder.ensure(compile::Rustc {
compiler: self.compiler,
target: builder.build.build,
target: builder.config.build,
});
builder.ensure(ToolBuild {
compiler: self.compiler,
@ -518,12 +515,12 @@ macro_rules! tool_extended {
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.path($path).default_condition(builder.build.config.extended)
run.path($path).default_condition(builder.config.extended)
}
fn make_run(run: RunConfig) {
run.builder.ensure($name {
compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
target: run.target,
extra_features: Vec::new(),
});
@ -554,20 +551,11 @@ tool_extended!((self, builder),
// compiler to be available, so we need to depend on that.
builder.ensure(compile::Rustc {
compiler: self.compiler,
target: builder.build.build,
target: builder.config.build,
});
};
Miri, miri, "src/tools/miri", "miri", {};
Rls, rls, "src/tools/rls", "rls", {
let clippy = builder.ensure(Clippy {
compiler: self.compiler,
target: self.target,
extra_features: Vec::new(),
});
let channel = &builder.config.channel;
if clippy.is_some() && channel != "stable" && channel != "beta" {
self.extra_features.push("clippy".to_owned());
}
builder.ensure(native::Openssl {
target: self.target,
});
@ -575,7 +563,7 @@ tool_extended!((self, builder),
// compiler to be available, so we need to depend on that.
builder.ensure(compile::Rustc {
compiler: self.compiler,
target: builder.build.build,
target: builder.config.build,
});
};
Rustfmt, rustfmt, "src/tools/rustfmt", "rustfmt", {};
@ -586,7 +574,7 @@ impl<'a> Builder<'a> {
/// `host`.
pub fn tool_cmd(&self, tool: Tool) -> Command {
let mut cmd = Command::new(self.tool_exe(tool));
let compiler = self.compiler(self.tool_default_stage(tool), self.build.build);
let compiler = self.compiler(self.tool_default_stage(tool), self.config.build);
self.prepare_tool_cmd(compiler, &mut cmd);
cmd
}
@ -597,7 +585,7 @@ impl<'a> Builder<'a> {
/// right location to run `compiler`.
fn prepare_tool_cmd(&self, compiler: Compiler, cmd: &mut Command) {
let host = &compiler.host;
let mut paths: Vec<PathBuf> = vec![
let mut lib_paths: Vec<PathBuf> = vec![
PathBuf::from(&self.sysroot_libdir(compiler, compiler.host)),
self.cargo_out(compiler, Mode::Tool, *host).join("deps"),
];
@ -614,11 +602,46 @@ impl<'a> Builder<'a> {
}
for path in env::split_paths(v) {
if !curpaths.contains(&path) {
paths.push(path);
lib_paths.push(path);
}
}
}
}
add_lib_path(paths, cmd);
// Add the llvm/bin directory to PATH since it contains lots of
// useful, platform-independent tools
if let Some(llvm_bin_path) = self.llvm_bin_path() {
if host.contains("windows") {
// On Windows, PATH and the dynamic library path are the same,
// so we just add the LLVM bin path to lib_path
lib_paths.push(llvm_bin_path);
} else {
let old_path = env::var_os("PATH").unwrap_or_default();
let new_path = env::join_paths(iter::once(llvm_bin_path)
.chain(env::split_paths(&old_path)))
.expect("Could not add LLVM bin path to PATH");
cmd.env("PATH", new_path);
}
}
add_lib_path(lib_paths, cmd);
}
fn llvm_bin_path(&self) -> Option<PathBuf> {
if self.config.llvm_enabled && !self.config.dry_run {
let llvm_config = self.ensure(native::Llvm {
target: self.config.build,
emscripten: false,
});
// Add the llvm/bin directory to PATH since it contains lots of
// useful, platform-independent tools
let llvm_bin_path = llvm_config.parent()
.expect("Expected llvm-config to be contained in directory");
assert!(llvm_bin_path.is_dir());
Some(llvm_bin_path.to_path_buf())
} else {
None
}
}
}

View File

@ -15,13 +15,14 @@
use std::env;
use std::str;
use std::fs::{self, File, OpenOptions};
use std::io::{self, Read, Write, Seek, SeekFrom};
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::{SystemTime, Instant};
use filetime::{self, FileTime};
use config::Config;
use builder::Builder;
/// Returns the `name` as the filename of a static library for `target`.
pub fn staticlib(name: &str, target: &str) -> String {
@ -32,102 +33,6 @@ pub fn staticlib(name: &str, target: &str) -> String {
}
}
/// Copies a file from `src` to `dst`
pub fn copy(src: &Path, dst: &Path) {
let _ = fs::remove_file(&dst);
// Attempt to "easy copy" by creating a hard link (symlinks don't work on
// windows), but if that fails just fall back to a slow `copy` operation.
if let Ok(()) = fs::hard_link(src, dst) {
return
}
if let Err(e) = fs::copy(src, dst) {
panic!("failed to copy `{}` to `{}`: {}", src.display(),
dst.display(), e)
}
let metadata = t!(src.metadata());
t!(fs::set_permissions(dst, metadata.permissions()));
let atime = FileTime::from_last_access_time(&metadata);
let mtime = FileTime::from_last_modification_time(&metadata);
t!(filetime::set_file_times(dst, atime, mtime));
}
/// Search-and-replaces within a file. (Not maximally efficiently: allocates a
/// new string for each replacement.)
pub fn replace_in_file(path: &Path, replacements: &[(&str, &str)]) {
let mut contents = String::new();
let mut file = t!(OpenOptions::new().read(true).write(true).open(path));
t!(file.read_to_string(&mut contents));
for &(target, replacement) in replacements {
contents = contents.replace(target, replacement);
}
t!(file.seek(SeekFrom::Start(0)));
t!(file.set_len(0));
t!(file.write_all(contents.as_bytes()));
}
pub fn read_stamp_file(stamp: &Path) -> Vec<PathBuf> {
let mut paths = Vec::new();
let mut contents = Vec::new();
t!(t!(File::open(stamp)).read_to_end(&mut contents));
// This is the method we use for extracting paths from the stamp file passed to us. See
// run_cargo for more information (in compile.rs).
for part in contents.split(|b| *b == 0) {
if part.is_empty() {
continue
}
let path = PathBuf::from(t!(str::from_utf8(part)));
paths.push(path);
}
paths
}
/// Copies the `src` directory recursively to `dst`. Both are assumed to exist
/// when this function is called.
pub fn cp_r(src: &Path, dst: &Path) {
for f in t!(fs::read_dir(src)) {
let f = t!(f);
let path = f.path();
let name = path.file_name().unwrap();
let dst = dst.join(name);
if t!(f.file_type()).is_dir() {
t!(fs::create_dir_all(&dst));
cp_r(&path, &dst);
} else {
let _ = fs::remove_file(&dst);
copy(&path, &dst);
}
}
}
/// Copies the `src` directory recursively to `dst`. Both are assumed to exist
/// when this function is called. Unwanted files or directories can be skipped
/// by returning `false` from the filter function.
pub fn cp_filtered(src: &Path, dst: &Path, filter: &Fn(&Path) -> bool) {
// Inner function does the actual work
fn recurse(src: &Path, dst: &Path, relative: &Path, filter: &Fn(&Path) -> bool) {
for f in t!(fs::read_dir(src)) {
let f = t!(f);
let path = f.path();
let name = path.file_name().unwrap();
let dst = dst.join(name);
let relative = relative.join(name);
// Only copy file or directory if the filter function returns true
if filter(&relative) {
if t!(f.file_type()).is_dir() {
let _ = fs::remove_dir_all(&dst);
t!(fs::create_dir(&dst));
recurse(&path, &dst, &relative, filter);
} else {
let _ = fs::remove_file(&dst);
copy(&path, &dst);
}
}
}
}
// Immediately recurse with an empty relative path
recurse(src, dst, Path::new(""), filter)
}
/// Given an executable called `name`, return the filename for the
/// executable for a particular target.
pub fn exe(name: &str, target: &str) -> String {
@ -196,25 +101,28 @@ pub fn push_exe_path(mut buf: PathBuf, components: &[&str]) -> PathBuf {
buf
}
pub struct TimeIt(Instant);
pub struct TimeIt(bool, Instant);
/// Returns an RAII structure that prints out how long it took to drop.
pub fn timeit() -> TimeIt {
TimeIt(Instant::now())
pub fn timeit(builder: &Builder) -> TimeIt {
TimeIt(builder.config.dry_run, Instant::now())
}
impl Drop for TimeIt {
fn drop(&mut self) {
let time = self.0.elapsed();
println!("\tfinished in {}.{:03}",
time.as_secs(),
time.subsec_nanos() / 1_000_000);
let time = self.1.elapsed();
if !self.0 {
println!("\tfinished in {}.{:03}",
time.as_secs(),
time.subsec_nanos() / 1_000_000);
}
}
}
/// Symlinks two directories, using junctions on Windows and normal symlinks on
/// Unix.
pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> {
pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
if config.dry_run { return Ok(()); }
let _ = fs::remove_dir(dest);
return symlink_dir_inner(src, dest);

View File

@ -8,13 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![deny(warnings)]
use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::{fs, env};
use std::time::{SystemTime, UNIX_EPOCH};
use std::{env, fs};
/// A helper macro to `unwrap` a result except also print out details like:
///
@ -26,10 +24,12 @@ use std::time::{SystemTime, UNIX_EPOCH};
/// using a `Result` with `try!`, but this may change one day...
#[macro_export]
macro_rules! t {
($e:expr) => (match $e {
Ok(e) => e,
Err(e) => panic!("{} failed with {}", stringify!($e), e),
})
($e:expr) => {
match $e {
Ok(e) => e,
Err(e) => panic!("{} failed with {}", stringify!($e), e),
}
};
}
pub fn run(cmd: &mut Command) {
@ -46,14 +46,17 @@ pub fn run_silent(cmd: &mut Command) {
pub fn try_run_silent(cmd: &mut Command) -> bool {
let status = match cmd.status() {
Ok(status) => status,
Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
cmd, e)),
Err(e) => fail(&format!(
"failed to execute command: {:?}\nerror: {}",
cmd, e
)),
};
if !status.success() {
println!("\n\ncommand did not execute successfully: {:?}\n\
expected success, got: {}\n\n",
cmd,
status);
println!(
"\n\ncommand did not execute successfully: {:?}\n\
expected success, got: {}\n\n",
cmd, status
);
}
status.success()
}
@ -67,18 +70,22 @@ pub fn run_suppressed(cmd: &mut Command) {
pub fn try_run_suppressed(cmd: &mut Command) -> bool {
let output = match cmd.output() {
Ok(status) => status,
Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
cmd, e)),
Err(e) => fail(&format!(
"failed to execute command: {:?}\nerror: {}",
cmd, e
)),
};
if !output.status.success() {
println!("\n\ncommand did not execute successfully: {:?}\n\
expected success, got: {}\n\n\
stdout ----\n{}\n\
stderr ----\n{}\n\n",
cmd,
output.status,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr));
println!(
"\n\ncommand did not execute successfully: {:?}\n\
expected success, got: {}\n\n\
stdout ----\n{}\n\
stderr ----\n{}\n\n",
cmd,
output.status,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
output.status.success()
}
@ -94,9 +101,9 @@ pub fn gnu_target(target: &str) -> String {
}
pub fn make(host: &str) -> PathBuf {
if host.contains("bitrig") || host.contains("dragonfly") ||
host.contains("freebsd") || host.contains("netbsd") ||
host.contains("openbsd") {
if host.contains("bitrig") || host.contains("dragonfly") || host.contains("freebsd")
|| host.contains("netbsd") || host.contains("openbsd")
{
PathBuf::from("gmake")
} else {
PathBuf::from("make")
@ -106,23 +113,27 @@ pub fn make(host: &str) -> PathBuf {
pub fn output(cmd: &mut Command) -> String {
let output = match cmd.stderr(Stdio::inherit()).output() {
Ok(status) => status,
Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
cmd, e)),
Err(e) => fail(&format!(
"failed to execute command: {:?}\nerror: {}",
cmd, e
)),
};
if !output.status.success() {
panic!("command did not execute successfully: {:?}\n\
expected success, got: {}",
cmd,
output.status);
panic!(
"command did not execute successfully: {:?}\n\
expected success, got: {}",
cmd, output.status
);
}
String::from_utf8(output.stdout).unwrap()
}
pub fn rerun_if_changed_anything_in_dir(dir: &Path) {
let mut stack = dir.read_dir().unwrap()
.map(|e| e.unwrap())
.filter(|e| &*e.file_name() != ".git")
.collect::<Vec<_>>();
let mut stack = dir.read_dir()
.unwrap()
.map(|e| e.unwrap())
.filter(|e| &*e.file_name() != ".git")
.collect::<Vec<_>>();
while let Some(entry) = stack.pop() {
let path = entry.path();
if entry.file_type().unwrap().is_dir() {
@ -135,7 +146,9 @@ pub fn rerun_if_changed_anything_in_dir(dir: &Path) {
/// Returns the last-modified time for `path`, or zero if it doesn't exist.
pub fn mtime(path: &Path) -> SystemTime {
fs::metadata(path).and_then(|f| f.modified()).unwrap_or(UNIX_EPOCH)
fs::metadata(path)
.and_then(|f| f.modified())
.unwrap_or(UNIX_EPOCH)
}
/// Returns whether `dst` is up to date given that the file or files in `src`
@ -176,11 +189,12 @@ impl Drop for NativeLibBoilerplate {
// If Err is returned, then everything is up-to-date and further build actions can be skipped.
// Timestamps are created automatically when the result of `native_lib_boilerplate` goes out
// of scope, so all the build actions should be completed until then.
pub fn native_lib_boilerplate(src_name: &str,
out_name: &str,
link_name: &str,
search_subdir: &str)
-> Result<NativeLibBoilerplate, ()> {
pub fn native_lib_boilerplate(
src_name: &str,
out_name: &str,
link_name: &str,
search_subdir: &str,
) -> Result<NativeLibBoilerplate, ()> {
let current_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let src_dir = current_dir.join("..").join(src_name);
rerun_if_changed_anything_in_dir(&src_dir);
@ -193,11 +207,17 @@ pub fn native_lib_boilerplate(src_name: &str,
} else {
println!("cargo:rustc-link-lib=static={}", link_name);
}
println!("cargo:rustc-link-search=native={}", out_dir.join(search_subdir).display());
println!(
"cargo:rustc-link-search=native={}",
out_dir.join(search_subdir).display()
);
let timestamp = out_dir.join("rustbuild.timestamp");
if !up_to_date(Path::new("build.rs"), &timestamp) || !up_to_date(&src_dir, &timestamp) {
Ok(NativeLibBoilerplate { src_dir: src_dir, out_dir: out_dir })
Ok(NativeLibBoilerplate {
src_dir: src_dir,
out_dir: out_dir,
})
} else {
Err(())
}
@ -215,10 +235,12 @@ pub fn sanitizer_lib_boilerplate(sanitizer_name: &str) -> Result<NativeLibBoiler
),
_ => return Err(()),
};
native_lib_boilerplate("libcompiler_builtins/compiler-rt",
sanitizer_name,
&link_name,
search_path)
native_lib_boilerplate(
"libcompiler_builtins/compiler-rt",
sanitizer_name,
&link_name,
search_path,
)
}
fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool {

View File

@ -20,7 +20,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
bzip2 \
patch \
libssl-dev \
pkg-config
pkg-config \
gcc-arm-none-eabi \
libnewlib-arm-none-eabi
WORKDIR /build
@ -41,6 +43,10 @@ ENV STAGING_DIR=/tmp
COPY scripts/musl.sh /build
RUN env \
CC=arm-linux-gnueabi-gcc CFLAGS="-march=armv5te -marm -mfloat-abi=soft" \
CXX=arm-linux-gnueabi-g++ CXXFLAGS="-march=armv5te -marm -mfloat-abi=soft" \
bash musl.sh armv5te && \
env \
CC=arm-linux-gnueabi-gcc CFLAGS="-march=armv6 -marm" \
CXX=arm-linux-gnueabi-g++ CXXFLAGS="-march=armv6 -marm" \
bash musl.sh arm && \
@ -66,6 +72,14 @@ RUN env \
bash musl.sh mipsel && \
rm -rf /build/*
# FIXME(mozilla/sccache#235) this shouldn't be necessary but is currently
# necessary to disambiguate the mips compiler with the mipsel compiler. We want
# to give these two wrapper scripts (currently identical ones) different hashes
# to ensure that sccache understands that they're different compilers.
RUN \
echo "# a" >> /usr/local/mips-linux-musl/bin/mips-openwrt-linux-musl-wrapper.sh && \
echo "# b" >> /usr/local/mipsel-linux-musl/bin/mipsel-openwrt-linux-musl-wrapper.sh
ENV TARGETS=asmjs-unknown-emscripten
ENV TARGETS=$TARGETS,wasm32-unknown-emscripten
ENV TARGETS=$TARGETS,x86_64-rumprun-netbsd
@ -74,10 +88,15 @@ ENV TARGETS=$TARGETS,mipsel-unknown-linux-musl
ENV TARGETS=$TARGETS,arm-unknown-linux-musleabi
ENV TARGETS=$TARGETS,arm-unknown-linux-musleabihf
ENV TARGETS=$TARGETS,armv5te-unknown-linux-gnueabi
ENV TARGETS=$TARGETS,armv5te-unknown-linux-musleabi
ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabihf
ENV TARGETS=$TARGETS,aarch64-unknown-linux-musl
ENV TARGETS=$TARGETS,sparc64-unknown-linux-gnu
ENV TARGETS=$TARGETS,x86_64-unknown-redox
ENV TARGETS=$TARGETS,thumbv6m-none-eabi
ENV TARGETS=$TARGETS,thumbv7m-none-eabi
ENV TARGETS=$TARGETS,thumbv7em-none-eabi
ENV TARGETS=$TARGETS,thumbv7em-none-eabihf
# FIXME: remove armv5te vars after https://github.com/alexcrichton/cc-rs/issues/271
# get fixed and cc update
@ -86,9 +105,12 @@ ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
CC_sparc64_unknown_linux_gnu=sparc64-linux-gnu-gcc \
CC_x86_64_unknown_redox=x86_64-unknown-redox-gcc \
CC_armv5te_unknown_linux_gnueabi=arm-linux-gnueabi-gcc \
CFLAGS_armv5te_unknown_linux_gnueabi="-march=armv5te -marm -mfloat-abi=soft"
CFLAGS_armv5te_unknown_linux_gnueabi="-march=armv5te -marm -mfloat-abi=soft" \
CC_armv5te_unknown_linux_musleabi=arm-linux-gnueabi-gcc \
CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft"
ENV RUST_CONFIGURE_ARGS \
--musl-root-armv5te=/musl-armv5te \
--musl-root-arm=/musl-arm \
--musl-root-armhf=/musl-armhf \
--musl-root-armv7=/musl-armv7 \

View File

@ -0,0 +1,23 @@
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 \
libssl-dev \
pkg-config \
mingw-w64
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
ENV SCRIPT python2.7 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu

View File

@ -104,8 +104,6 @@ if [ "$SCCACHE_BUCKET" != "" ]; then
args="$args --env SCCACHE_REGION"
args="$args --env AWS_ACCESS_KEY_ID"
args="$args --env AWS_SECRET_ACCESS_KEY"
args="$args --env SCCACHE_ERROR_LOG=/tmp/sccache/sccache.log"
args="$args --volume $objdir/tmp:/tmp/sccache"
else
mkdir -p $HOME/.cache/sccache
args="$args --env SCCACHE_DIR=/sccache --volume $HOME/.cache/sccache:/sccache"
@ -132,6 +130,7 @@ exec docker \
--env TRAVIS \
--env TRAVIS_BRANCH \
--env TOOLSTATE_REPO_ACCESS_TOKEN \
--env CI_JOB_NAME="${CI_JOB_NAME-$IMAGE}" \
--volume "$HOME/.cargo:/cargo" \
--volume "$HOME/rustsrc:$HOME/rustsrc" \
--init \

View File

@ -40,7 +40,7 @@ if [ ! -d $MUSL ]; then
fi
cd $MUSL
./configure --disable-shared --prefix=/musl-$TAG $@
./configure --enable-optimize --enable-debug --disable-shared --prefix=/musl-$TAG $@
if [ "$TAG" = "i586" -o "$TAG" = "i686" ]; then
hide_output make -j$(nproc) AR=ar RANLIB=ranlib
else

View File

@ -13,6 +13,6 @@
set -ex
curl -fo /usr/local/bin/sccache \
https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-05-12-sccache-x86_64-unknown-linux-musl
https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2018-04-02-sccache-x86_64-unknown-linux-musl
chmod +x /usr/local/bin/sccache

View File

@ -25,6 +25,12 @@ ENV RUST_CONFIGURE_ARGS \
--set build.nodejs=/node-v9.2.0-linux-x64/bin/node \
--set rust.lld
# Some run-make tests have assertions about code size, and enabling debug
# assertions in libstd causes the binary to be much bigger than it would
# otherwise normally be. We already test libstd with debug assertions in lots of
# other contexts as well
ENV NO_DEBUG_ASSERTIONS=1
ENV SCRIPT python2.7 /checkout/x.py test --target $TARGETS \
src/test/run-make \
src/test/ui \
@ -34,4 +40,3 @@ ENV SCRIPT python2.7 /checkout/x.py test --target $TARGETS \
src/test/mir-opt \
src/test/codegen-units \
src/libcore \
src/libstd_unicode/ \

View File

@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
ENV RUST_CONFIGURE_ARGS \
--build=x86_64-unknown-linux-gnu \
--enable-debug \

View File

@ -30,8 +30,7 @@ python2.7 "$X_PY" test --no-fail-fast \
src/doc/reference \
src/doc/rust-by-example \
src/tools/rls \
src/tools/rustfmt \
src/tools/clippy
src/tools/rustfmt
set -e
cat "$TOOLSTATE_FILE"
@ -65,8 +64,6 @@ verify_status reference src/doc/reference
verify_status rust-by-example src/doc/rust-by-example
verify_status rls src/tool/rls
verify_status rustfmt src/tool/rustfmt
verify_status clippy-driver src/tool/clippy
#verify_status miri src/tool/miri
if [ "$RUST_RELEASE_CHANNEL" = nightly -a -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then
. "$(dirname $0)/repo.sh"

View File

@ -11,6 +11,10 @@
set -e
if [ -n "$CI_JOB_NAME" ]; then
echo "[CI_JOB_NAME=$CI_JOB_NAME]"
fi
if [ "$NO_CHANGE_USER" = "" ]; then
if [ "$LOCAL_USER_ID" != "" ]; then
useradd --shell /bin/bash -u $LOCAL_USER_ID -o -c "" -m user
@ -74,9 +78,9 @@ fi
# sccache server at the start of the build, but no need to worry if this fails.
SCCACHE_IDLE_TIMEOUT=10800 sccache --start-server || true
if [ "$PARALLEL_CHECK" != "" ]; then
if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then
$SRC/configure --enable-experimental-parallel-queries
python2.7 ../x.py check
CARGO_INCREMENTAL=0 python2.7 ../x.py check
rm -f config.toml
rm -rf build
fi

View File

@ -18,3 +18,4 @@ opt-level = 'z'
[features]
debug = []
allocator-api = []

View File

@ -100,24 +100,24 @@ impl Drop for Instance {
unsafe impl<'a> Alloc for &'a GlobalDlmalloc {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
get().alloc(layout)
Alloc::alloc(&mut *get(), layout)
}
unsafe fn alloc_zeroed(&mut self, layout: Layout)
-> Result<*mut u8, AllocErr>
{
get().alloc_zeroed(layout)
Alloc::alloc_zeroed(&mut *get(), layout)
}
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
get().dealloc(ptr, layout)
Alloc::dealloc(&mut *get(), ptr, layout)
}
unsafe fn realloc(&mut self,
ptr: *mut u8,
old_layout: Layout,
new_layout: Layout) -> Result<*mut u8, AllocErr> {
get().realloc(ptr, old_layout, new_layout)
Alloc::realloc(&mut *get(), ptr, old_layout, new_layout)
}
// fn oom(&mut self, err: AllocErr) -> ! {

View File

@ -1,20 +1,27 @@
#![feature(allocator_api, alloc)]
#![cfg_attr(feature = "allocator-api", feature(allocator_api, alloc))]
#![cfg_attr(target_arch = "wasm32", feature(link_llvm_intrinsics))]
#![cfg_attr(not(feature = "allocator-api"), allow(dead_code))]
#![no_std]
#[cfg(feature = "allocator-api")]
extern crate alloc;
#[cfg(feature = "allocator-api")]
use alloc::heap::{Alloc, Layout, AllocErr};
use core::cmp;
use core::ptr;
#[cfg(feature = "allocator-api")]
pub use self::global::GlobalDlmalloc;
#[cfg(feature = "allocator-api")]
mod global;
mod dlmalloc;
pub struct Dlmalloc(dlmalloc::Dlmalloc);
pub const DLMALLOC_INIT: Dlmalloc = Dlmalloc(dlmalloc::DLMALLOC_INIT);
#[cfg(target_arch = "wasm32")]
#[path = "wasm.rs"]
mod sys;
@ -31,16 +38,56 @@ impl Dlmalloc {
pub fn new() -> Dlmalloc {
Dlmalloc(dlmalloc::Dlmalloc::new())
}
#[inline]
pub unsafe fn malloc(&mut self, size: usize, align: usize) -> *mut u8 {
if align <= self.0.malloc_alignment() {
self.0.malloc(size)
} else {
self.0.memalign(align, size)
}
}
#[inline]
pub unsafe fn calloc(&mut self, size: usize, align: usize) -> *mut u8 {
let ptr = self.malloc(size, align);
if !ptr.is_null() && self.0.calloc_must_clear(ptr) {
ptr::write_bytes(ptr, 0, size);
}
ptr
}
#[inline]
pub unsafe fn free(&mut self, ptr: *mut u8, size: usize, align: usize) {
drop((size, align));
self.0.free(ptr)
}
#[inline]
pub unsafe fn realloc(&mut self,
ptr: *mut u8,
old_size: usize,
old_align: usize,
new_size: usize) -> *mut u8 {
if old_align <= self.0.malloc_alignment() {
self.0.realloc(ptr, new_size)
} else {
let res = self.malloc(new_size, old_align);
if !res.is_null() {
let size = cmp::min(old_size, new_size);
ptr::copy_nonoverlapping(ptr, res, size);
self.free(ptr, old_size, old_align);
}
res
}
}
}
#[cfg(feature = "allocator-api")]
unsafe impl Alloc for Dlmalloc {
#[inline]
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
let ptr = if layout.align() <= self.0.malloc_alignment() {
self.0.malloc(layout.size())
} else {
self.0.memalign(layout.align(), layout.size())
};
let ptr = <Dlmalloc>::malloc(self, layout.size(), layout.align());
if ptr.is_null() {
Err(AllocErr::Exhausted { request: layout })
} else {
@ -52,18 +99,17 @@ unsafe impl Alloc for Dlmalloc {
unsafe fn alloc_zeroed(&mut self, layout: Layout)
-> Result<*mut u8, AllocErr>
{
let size = layout.size();
let ptr = self.alloc(layout)?;
if self.0.calloc_must_clear(ptr) {
ptr::write_bytes(ptr, 0, size);
let ptr = <Dlmalloc>::calloc(self, layout.size(), layout.align());
if ptr.is_null() {
Err(AllocErr::Exhausted { request: layout })
} else {
Ok(ptr)
}
Ok(ptr)
}
#[inline]
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
drop(layout);
self.0.free(ptr)
<Dlmalloc>::free(self, ptr, layout.size(), layout.align())
}
#[inline]
@ -76,91 +122,19 @@ unsafe impl Alloc for Dlmalloc {
details: "cannot change alignment on `realloc`",
})
}
let ptr = <Dlmalloc>::realloc(
self,
ptr,
old_layout.size(),
old_layout.align(),
new_layout.size(),
);
if new_layout.align() <= self.0.malloc_alignment() {
let ptr = self.0.realloc(ptr, new_layout.size());
if !ptr.is_null() {
Ok(ptr as *mut u8)
} else {
Err(AllocErr::Exhausted { request: new_layout })
}
if ptr.is_null() {
Err(AllocErr::Exhausted { request: new_layout })
} else {
let res = self.alloc(new_layout.clone());
if let Ok(new_ptr) = res {
let size = cmp::min(old_layout.size(), new_layout.size());
ptr::copy_nonoverlapping(ptr, new_ptr, size);
self.dealloc(ptr, old_layout);
}
res
Ok(ptr)
}
}
// fn oom(&mut self, err: AllocErr) -> ! {
// System.oom(err)
// }
// #[inline]
// fn usable_size(&self, layout: &Layout) -> (usize, usize) {
// (&self).usable_size(layout)
// }
//
// #[inline]
// unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
// (&*self).alloc_excess(layout)
// }
//
// #[inline]
// unsafe fn realloc_excess(&mut self,
// ptr: *mut u8,
// layout: Layout,
// new_layout: Layout) -> Result<Excess, AllocErr> {
// (&*self).realloc_excess(ptr, layout, new_layout)
// }
//
// #[inline]
// unsafe fn grow_in_place(&mut self,
// ptr: *mut u8,
// layout: Layout,
// new_layout: Layout) -> Result<(), CannotReallocInPlace> {
// (&*self).grow_in_place(ptr, layout, new_layout)
// }
//
// #[inline]
// unsafe fn shrink_in_place(&mut self,
// ptr: *mut u8,
// layout: Layout,
// new_layout: Layout) -> Result<(), CannotReallocInPlace> {
// (&*self).shrink_in_place(ptr, layout, new_layout)
// }
}
// unsafe impl<'a> Alloc for &'a Dlmalloc {
// #[inline]
// unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
// panic!()
// }
//
// // #[inline]
// // unsafe fn alloc_zeroed(&mut self, layout: Layout)
// // -> Result<*mut u8, AllocErr>
// // {
// // panic!()
// // }
//
// #[inline]
// unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
// panic!()
// }
//
// // #[inline]
// // unsafe fn realloc(&mut self,
// // ptr: *mut u8,
// // old_layout: Layout,
// // new_layout: Layout) -> Result<*mut u8, AllocErr> {
// // panic!()
// // }
//
// fn oom(&mut self, err: AllocErr) -> ! {
// System.oom(err)
// }
// }

View File

@ -59,7 +59,7 @@ fn stress() {
for i in 0..cmp::min(old.size(), new.size()) {
tmp.push(*ptr.offset(i as isize));
}
let ptr = a.realloc(ptr, old, new.clone()).unwrap_or_else(|e| {
let ptr = Alloc::realloc(&mut a, ptr, old, new.clone()).unwrap_or_else(|e| {
System.oom(e)
});
for (i, byte) in tmp.iter().enumerate() {

View File

@ -1,12 +1,11 @@
## What to expect when you file an issue here
### First edition
Thank you for caring about the quality of the book! Each edition has
different types of issues we can accept, please read on for details.
The first edition of the book is no longer being actively worked on.
### 2018 edition
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.
This version of the book is under development, please file issues liberally!
### Second edition
@ -23,4 +22,10 @@ to see which chapters have been frozen.
Please see CONTRIBUTING.md for more details.
### First edition
The first edition of the book is frozen, and bugs filed against it will
be closed.
Thank you for reading, you may now delete this text!

View File

@ -1,10 +1,13 @@
## What to expect when you open a pull request here
### First edition
### 2018 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.
The 2018 is a "living" edition; it's not scheduled for in-print publication at
this time, and so is able to be updated at any time. We'd love pull requests to
fix issues with this edition, but we're not interested in extremely large
changes without discussing them first. If you'd like to make a big change,
please open an issue first! We'd hate for you to do some hard work that we
ultimately wouldn't accept.
### Second edition
@ -21,4 +24,10 @@ to see which chapters have been frozen.
Please see CONTRIBUTING.md for more details.
### First edition
The first edition is frozen, and no longer accepting changes. Pull requests
made against it will be closed.
Thank you for reading, you may now delete this text!

View File

@ -13,6 +13,6 @@ addons:
- aspell
- aspell-en
before_script:
- (cargo install mdbook --vers 0.1.2 --force || true)
- (cargo install mdbook --vers 0.1.5 --force || true)
script:
- bash ci/build.sh

142
src/doc/book/2018-edition/Cargo.lock generated Normal file
View File

@ -0,0 +1,142 @@
[[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 = "docopt"
version = "0.6.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.33"
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.33 (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-syntax"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rust-book"
version = "0.0.1"
dependencies = [
"docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-serialize"
version = "0.3.24"
source = "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 = "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.33 (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 = "utf8-ranges"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "walkdir"
version = "0.1.8"
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.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
"checksum docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)" = "4a7ef30445607f6fc8720f0a0a2c7442284b629cf0d049286860fae23e71c4d9"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "236eb37a62591d4a41a89b7763d7de3e06ca02d5ab2815446a8bae5d2f8c2d57"
"checksum libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "5ba3df4dcb460b9dfbd070d41c94c19209620c191b0340b929ce748a2bcd42d2"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "67f84c44fbb2f91db7fef94554e6b2ac05909c9c0b0bc23bb98d3a1aebfe7f7c"
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
"checksum walkdir 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c66c0b9792f0a765345452775f3adbd28dde9d33f30d13e5dcc5ae17cf6f3780"
"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"

View File

@ -0,0 +1,36 @@
[package]
name = "rust-book"
version = "0.0.1"
authors = ["Steve Klabnik <steve@steveklabnik.com>"]
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"
[[bin]]
name = "convert_quotes"
path = "tools/src/bin/convert_quotes.rs"
[dependencies]
walkdir = "0.1.5"
docopt = "0.6.82"
rustc-serialize = "0.3.19"
regex = "0.1.73"
lazy_static = "0.2.1"

View File

@ -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.

View File

@ -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.

View File

@ -0,0 +1,3 @@
[book]
title = "The Rust Programming Language"
author = "Steve Klabnik and Carol Nichols, with Contributions from the Rust Community"

View File

@ -0,0 +1,22 @@
#!/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 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
set -eu
dir=$1
mkdir -p "tmp/$dir"
for f in $dir/*.md
do
cat "$f" | cargo run --bin convert_quotes > "tmp/$f"
mv "tmp/$f" "$f"
done

View File

@ -0,0 +1,502 @@
personal_ws-1.1 en 0 utf-8
abcabcabc
abcd
abcdefghijklmnopqrstuvwxyz
adaptor
adaptors
AddAssign
Addr
aggregator
AGraph
aliasability
alignof
alloc
allocator
Amir
anotherusername
APIs
app's
aren
args
associativity
async
atomics
AveragedCollection
backend
backported
backtrace
backtraces
BACKTRACE
Backtraces
Bazs
benchmarking
bioinformatics
bitand
BitAnd
BitAndAssign
bitor
BitOr
BitOrAssign
bitwise
Bitwise
bitxor
BitXor
BitXorAssign
Bjarne
Boehm
bool
Boolean
Booleans
Bors
BorrowMutError
BTreeSet
BuildHasher
Cacher
Cagain
callsite
CamelCase
cargodoc
ChangeColor
ChangeColorMessage
charset
choo
chXX
chYY
coercions
combinator
ConcreteType
config
Config
const
constant's
copyeditor
couldn
CPUs
cratesio
CRLF
cryptocurrencies
cryptographic
cryptographically
CStr
CString
ctrl
Ctrl
customizable
CustomSmartPointer
CustomSmartPointers
datas
deallocate
deallocated
deallocating
deallocation
debuginfo
decrementing
deps
deref
Deref
dereference
Dereference
dereferenced
dereferences
dereferencing
DerefMut
DeriveInput
destructor
destructure
destructured
destructures
destructuring
Destructuring
deterministically
DevOps
didn
Dobrý
doccargo
doccratesio
DOCTYPE
doesn
disambiguating
DivAssign
DraftPost
DSTs
ebooks
Edsger
egular
else's
emoji
encodings
enum
Enum
enums
enum's
Enums
eprintln
Erlang
ErrorKind
Executables
expr
extern
favicon
FFFD
FFFF
figcaption
fieldname
filename
Filename
filesystem
Filesystem
filesystems
Firefox
FnBox
FnMut
FnOnce
formatter
formatters
FrenchToast
FromIterator
frontend
getter
GGraph
GitHub
gitignore
grapheme
Grapheme
growable
gzip
hardcode
hardcoded
hardcoding
hasher
hashers
HashMap
HashSet
Haskell
hasn
HelloMacro
helloworld
HelloWorld
HelloWorldName
Hmmm
Hoare
Hola
homogenous
html
hyperoptimize
Iceburgh
ident
IDE
IDEs
IDE's
IEEE
impl
implementor
implementors
ImportantExcerpt
incrementing
IndexMut
indices
init
initializer
inline
instantiation
internet
IntoIterator
InvalidDigit
invariants
ioerror
iokind
ioresult
iostdin
IpAddr
IpAddrKind
irst
isize
iter
iterator's
JavaScript
JoinHandle
Kay's
kinded
lang
latin
liballoc
libc
libcollections
libcore
libpanic
librarys
libreoffice
libstd
lifecycle
LimitTracker
LLVM
lobally
locators
LockResult
login
lookup
loopback
lossy
lval
macOS
Matsakis
mathematic
memoization
metadata
Metadata
metaprogramming
mibbit
Mibbit
millis
minigrep
mixup
mkdir
MockMessenger
modifiability
modularity
monomorphization
Monomorphization
monomorphized
MoveMessage
Mozilla
mpsc
msvc
MulAssign
multibyte
multithreaded
mutex
mutex's
Mutex
mutexes
Mutexes
MutexGuard
MyBox
namespace
namespaced
namespaces
namespacing
natively
newfound
NewJob
NewsArticle
NewThread
newtype
newtypes
nitty
nocapture
nomicon
nondeterministic
nonequality
nongeneric
NotFound
null's
OCaml
offsetof
online
OpenGL
optimizations
OptionalFloatingPointNumber
OptionalNumber
OsStr
OsString
other's
OutlinePrint
overloadable
overread
param
parameterize
ParseIntError
PartialEq
PartialOrd
PendingReview
PendingReviewPost
PlaceholderType
polymorphism
PoolCreationError
portia
powershell
PowerShell
powi
preprocessing
Preprocessing
preprocessor
PrimaryColor
println
priv
proc
pthreads
pushups
QuitMessage
quux
RAII
randcrate
RangeFrom
RangeTo
RangeFull
README
READMEs
rect
recurse
recv
redeclaring
Refactoring
refactor
refactoring
refcell
RefCell
RefMut
refutability
reimplement
RemAssign
repr
representable
request's
resizes
resizing
retweet
rewordings
rint
ripgrep
runnable
runtime
runtimes
Rustacean
Rustaceans
rUsT
rustc
rustdoc
Rustonomicon
rustfmt
rustup
screenshot
searchstring
SecondaryColor
SelectBox
semver
SemVer
serde
ShlAssign
ShrAssign
shouldn
Simula
situps
sizeof
Smalltalk
snuck
someproject
someusername
SPDX
spdx
SpreadsheetCell
sqrt
stackoverflow
startup
StaticRef
stderr
stdin
Stdin
stdlib
stdout
steveklabnik's
stringify
Stroustrup
Stroustrup's
struct
Struct
structs
struct's
Structs
SubAssign
subclasses
subcommand
subcommands
subdirectories
subdirectory
submodule
submodules
Submodules
suboptimal
substring
subteams
subtree
subtyping
supertrait
supertraits
TcpListener
TcpStream
templating
test's
TextField
That'd
there'd
ThreadPool
timestamp
Tiếng
timeline
tlborm
TODO
TokenStream
toml
TOML
toolchain
toolchains
ToString
tradeoff
tradeoffs
TrafficLight
transcoding
trpl
tuesday
tuple
tuples
turbofish
Turon
typeof
TypeName
UFCS
unary
Unary
uncomment
Uncomment
unevaluated
Uninstalling
uninstall
unix
unpopulated
unoptimized
UnsafeCell
unsafety
unsized
unsynchronized
URIs
UsefulType
username
USERPROFILE
usize
UsState
utils
vals
variable's
variant's
vers
versa
Versioning
visualstudio
Vlissides
vtable
wasn
WeatherForecast
WebSocket
whitespace
wildcard
wildcards
workflow
workspace
workspaces
Workspaces
wouldn
writeln
WriteMessage
xpression
yyyy
ZipImpl

View File

@ -0,0 +1,26 @@
digraph {
rankdir=LR;
overlap=false;
dpi=300.0;
node [shape="plaintext"];
table0[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD COLSPAN="2" SIDES="B">s1</TD></TR>
<TR><TD>name</TD><TD>value</TD></TR>
<TR><TD>ptr</TD><TD PORT="pointer"></TD></TR>
<TR><TD>len</TD><TD>5</TD></TR>
<TR><TD>capacity</TD><TD>5</TD></TR>
</TABLE>>];
table1[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD>index</TD><TD>value</TD></TR>
<TR><TD PORT="pointee">0</TD><TD>h</TD></TR>
<TR><TD>1</TD><TD>e</TD></TR>
<TR><TD>2</TD><TD>l</TD></TR>
<TR><TD>3</TD><TD>l</TD></TR>
<TR><TD>4</TD><TD>o</TD></TR>
</TABLE>>];
edge[tailclip="false"];
table0:pointer:c -> table1:pointee;
}

View File

@ -0,0 +1,35 @@
digraph {
rankdir=LR;
overlap=false;
dpi=300.0;
node [shape="plaintext"];
table0[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD COLSPAN="2" SIDES="B">s1</TD></TR>
<TR><TD>name</TD><TD>value</TD></TR>
<TR><TD>ptr</TD><TD PORT="pointer"></TD></TR>
<TR><TD>len</TD><TD>5</TD></TR>
<TR><TD>capacity</TD><TD>5</TD></TR>
</TABLE>>];
table3[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD COLSPAN="2" SIDES="B">s2</TD></TR>
<TR><TD>name</TD><TD>value</TD></TR>
<TR><TD>ptr</TD><TD PORT="pointer"></TD></TR>
<TR><TD>len</TD><TD>5</TD></TR>
<TR><TD>capacity</TD><TD>5</TD></TR>
</TABLE>>];
table1[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD>index</TD><TD>value</TD></TR>
<TR><TD PORT="pointee">0</TD><TD>h</TD></TR>
<TR><TD>1</TD><TD>e</TD></TR>
<TR><TD>2</TD><TD>l</TD></TR>
<TR><TD>3</TD><TD>l</TD></TR>
<TR><TD>4</TD><TD>o</TD></TR>
</TABLE>>];
edge[tailclip="false"];
table0:pointer:c -> table1:pointee;
table3:pointer:c -> table1:pointee;
}

View File

@ -0,0 +1,44 @@
digraph {
rankdir=LR;
overlap=false;
dpi=300.0;
node [shape="plaintext"];
table0[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD COLSPAN="2" SIDES="B">s2</TD></TR>
<TR><TD>name</TD><TD>value</TD></TR>
<TR><TD>ptr</TD><TD PORT="pointer"></TD></TR>
<TR><TD>len</TD><TD>5</TD></TR>
<TR><TD>capacity</TD><TD>5</TD></TR>
</TABLE>>];
table1[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD>index</TD><TD>value</TD></TR>
<TR><TD PORT="pointee">0</TD><TD>h</TD></TR>
<TR><TD>1</TD><TD>e</TD></TR>
<TR><TD>2</TD><TD>l</TD></TR>
<TR><TD>3</TD><TD>l</TD></TR>
<TR><TD>4</TD><TD>o</TD></TR>
</TABLE>>];
table3[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD COLSPAN="2" SIDES="B">s1</TD></TR>
<TR><TD>name</TD><TD>value</TD></TR>
<TR><TD>ptr</TD><TD PORT="pointer"></TD></TR>
<TR><TD>len</TD><TD>5</TD></TR>
<TR><TD>capacity</TD><TD>5</TD></TR>
</TABLE>>];
table4[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD>index</TD><TD>value</TD></TR>
<TR><TD PORT="pointee">0</TD><TD>h</TD></TR>
<TR><TD>1</TD><TD>e</TD></TR>
<TR><TD>2</TD><TD>l</TD></TR>
<TR><TD>3</TD><TD>l</TD></TR>
<TR><TD>4</TD><TD>o</TD></TR>
</TABLE>>];
edge[tailclip="false"];
table0:pointer:c -> table1:pointee;
table3:pointer:c -> table4:pointee;
}

View File

@ -0,0 +1,35 @@
digraph {
rankdir=LR;
overlap=false;
dpi=300.0;
node [shape="plaintext"];
table0[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" BGCOLOR="gray">
<TR><TD COLSPAN="2" SIDES="B">s1</TD></TR>
<TR><TD>name</TD><TD>value</TD></TR>
<TR><TD>ptr</TD><TD PORT="pointer"></TD></TR>
<TR><TD>len</TD><TD>5</TD></TR>
<TR><TD>capacity</TD><TD>5</TD></TR>
</TABLE>>];
table3[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD COLSPAN="2" SIDES="B">s2</TD></TR>
<TR><TD>name</TD><TD>value</TD></TR>
<TR><TD>ptr</TD><TD PORT="pointer"></TD></TR>
<TR><TD>len</TD><TD>5</TD></TR>
<TR><TD>capacity</TD><TD>5</TD></TR>
</TABLE>>];
table1[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD>index</TD><TD>value</TD></TR>
<TR><TD PORT="pointee">0</TD><TD>h</TD></TR>
<TR><TD>1</TD><TD>e</TD></TR>
<TR><TD>2</TD><TD>l</TD></TR>
<TR><TD>3</TD><TD>l</TD></TR>
<TR><TD>4</TD><TD>o</TD></TR>
</TABLE>>];
edge[tailclip="false"];
table0:pointer:c -> table1:pointee;
table3:pointer:c -> table1:pointee;
}

View File

@ -0,0 +1,32 @@
digraph {
rankdir=LR;
overlap=false;
dpi=300.0;
node [shape="plaintext"];
table0[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD COLSPAN="2" SIDES="B">s</TD></TR>
<TR><TD>name</TD><TD>value</TD></TR>
<TR><TD>ptr</TD><TD PORT="borrower"></TD></TR>
</TABLE>>];
table1[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD COLSPAN="2" SIDES="B">s1</TD></TR>
<TR><TD>name</TD><TD>value</TD></TR>
<TR><TD PORT="borrowee">ptr</TD><TD PORT="pointer"></TD></TR>
<TR><TD>len</TD><TD>5</TD></TR>
<TR><TD>capacity</TD><TD>5</TD></TR>
</TABLE>>];
table2[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD>index</TD><TD>value</TD></TR>
<TR><TD PORT="pointee">0</TD><TD>h</TD></TR>
<TR><TD>1</TD><TD>e</TD></TR>
<TR><TD>2</TD><TD>l</TD></TR>
<TR><TD>3</TD><TD>l</TD></TR>
<TR><TD>4</TD><TD>o</TD></TR>
</TABLE>>];
edge[tailclip="false"];
table1:pointer:c -> table2:pointee;
table0:borrower:c -> table1:borrowee;
}

View File

@ -0,0 +1,41 @@
digraph {
rankdir=LR;
overlap=false;
dpi=300.0;
node [shape="plaintext"];
table0[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD COLSPAN="2" SIDES="B">world</TD></TR>
<TR><TD>name</TD><TD>value</TD></TR>
<TR><TD>ptr</TD><TD PORT="pointer2"></TD></TR>
<TR><TD>len</TD><TD>5</TD></TR>
</TABLE>>];
table3[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD COLSPAN="2" SIDES="B">s</TD></TR>
<TR><TD>name</TD><TD>value</TD></TR>
<TR><TD>ptr</TD><TD PORT="pointer"></TD></TR>
<TR><TD>len</TD><TD>11</TD></TR>
<TR><TD>capacity</TD><TD>11</TD></TR>
</TABLE>>];
table4[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD>index</TD><TD>value</TD></TR>
<TR><TD PORT="pointee">0</TD><TD>h</TD></TR>
<TR><TD>1</TD><TD>e</TD></TR>
<TR><TD>2</TD><TD>l</TD></TR>
<TR><TD>3</TD><TD>l</TD></TR>
<TR><TD>4</TD><TD>o</TD></TR>
<TR><TD>5</TD><TD> </TD></TR>
<TR><TD PORT="pointee2">6</TD><TD>w</TD></TR>
<TR><TD>7</TD><TD>o</TD></TR>
<TR><TD>8</TD><TD>r</TD></TR>
<TR><TD>9</TD><TD>l</TD></TR>
<TR><TD>10</TD><TD>d</TD></TR>
</TABLE>>];
edge[tailclip="false"];
table0:pointer2:c -> table4:pointee2;
table3:pointer:c -> table4:pointee;
}

View File

@ -0,0 +1,24 @@
digraph {
rankdir=LR;
overlap=false;
dpi=300.0;
node [shape="plaintext"];
table0[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD COLSPAN="2" SIDES="B">Cons</TD></TR>
<TR><TD>i32</TD><TD><TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD COLSPAN="2" SIDES="B">Cons</TD></TR>
<TR><TD>i32</TD><TD><TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD COLSPAN="2" SIDES="B">Cons</TD></TR>
<TR><TD>i32</TD><TD><TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD COLSPAN="2" SIDES="B">Cons</TD></TR>
<TR><TD>i32</TD><TD><TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD COLSPAN="2" SIDES="B">Cons</TD></TR>
<TR><TD>i32</TD><TD>∞</TD></TR>
</TABLE></TD></TR>
</TABLE></TD></TR>
</TABLE></TD></TR>
</TABLE></TD></TR>
</TABLE>>];
}

View File

@ -0,0 +1,18 @@
digraph {
rankdir=LR;
overlap=false;
dpi=300.0;
node [shape="plaintext"];
table0[label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD COLSPAN="2" SIDES="B">Cons</TD></TR>
<TR><TD>i32</TD><TD>
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD SIDES="B">Box</TD></TR>
<TR><TD>usize</TD></TR>
</TABLE>
</TD></TR>
</TABLE>>];
}

View File

@ -0,0 +1,51 @@
digraph {
rankdir=LR;
overlap=false;
dpi=300.0;
node [shape="plaintext"];
table4[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD SIDES="B">b</TD><TD SIDES="B" PORT="ptr4"></TD></TR>
</TABLE>>];
table5[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD PORT="pte4">3</TD><TD PORT="ptr5"> </TD></TR>
</TABLE>>];
table0[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD SIDES="B">a</TD><TD SIDES="B" PORT="ptr0"></TD></TR>
</TABLE>>];
table1[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD PORT="pte0">5</TD><TD PORT="ptr1"> </TD></TR>
</TABLE>>];
table2[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD PORT="pte1">10</TD><TD PORT="ptr2"> </TD></TR>
</TABLE>>];
table3[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD PORT="pte2">Nil</TD></TR>
</TABLE>>];
table6[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD SIDES="B">c</TD><TD SIDES="B" PORT="ptr6"></TD></TR>
</TABLE>>];
table7[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD PORT="pte6">4</TD><TD PORT="ptr7"> </TD></TR>
</TABLE>>];
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;
}

View File

@ -0,0 +1,101 @@
#!/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 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
aspell --version
# Checks project markdown files for spell errors
# Notes:
# This script needs dictionary file ($dict_filename) with project-specific
# valid words. If this file is missing, first invocation of a script generates
# a file of words considered typos at the moment. User should remove real typos
# from this file and leave only valid words. When script generates false
# positive after source modification, new valid word should be added
# to dictionary file.
# Default mode of this script is interactive. Each source file is scanned for
# typos. aspell opens window, suggesting fixes for each found typo. Original
# files with errors will be backed up to files with format "filename.md.bak".
# When running in CI, this script should be run in "list" mode (pass "list"
# as first argument). In this mode script scans all files and reports found
# errors. Exit code in this case depends on scan result:
# 1 if any errors found,
# 0 if all is clear.
# Script skips words with length less than or equal to 3. This helps to avoid
# some false positives.
# We can consider skipping source code in markdown files (```code```) to reduce
# rate of false positives, but then we lose ability to detect typos in code
# comments/strings etc.
shopt -s nullglob
dict_filename=./dictionary.txt
markdown_sources=(./src/*.md)
mode="check"
# aspell repeatedly modifies personal dictionary for some purpose,
# so we should use a copy of our dictionary
dict_path="/tmp/$dict_filename"
if [[ "$1" == "list" ]]; then
mode="list"
fi
if [[ ! -f "$dict_filename" ]]; then
# Pre-check mode: generates dictionary of words aspell consider typos.
# After user validates that this file contains only valid words, we can
# look for typos using this dictionary and some default aspell dictionary.
echo "Scanning files to generate dictionary file '$dict_filename'."
echo "Please check that it doesn't contain any misspellings."
echo "personal_ws-1.1 en 0 utf-8" > "$dict_filename"
cat "${markdown_sources[@]}" | aspell --ignore 3 list | sort -u >> "$dict_filename"
elif [[ "$mode" == "list" ]]; then
# List (default) mode: scan all files, report errors
declare -i retval=0
cp "$dict_filename" "$dict_path"
if [ ! -f $dict_path ]; then
retval=1
exit "$retval"
fi
for fname in "${markdown_sources[@]}"; do
command=$(aspell --ignore 3 --personal="$dict_path" "$mode" < "$fname")
if [[ -n "$command" ]]; then
for error in $command; do
# FIXME: Find more correct way to get line number
# (ideally from aspell). Now it can make some false positives,
# because it is just a grep
grep --with-filename --line-number --color=always "$error" "$fname"
done
retval=1
fi
done
exit "$retval"
elif [[ "$mode" == "check" ]]; then
# Interactive mode: fix typos
cp "$dict_filename" "$dict_path"
if [ ! -f $dict_path ]; then
retval=1
exit "$retval"
fi
for fname in "${markdown_sources[@]}"; do
aspell --ignore 3 --dont-backup --personal="$dict_path" "$mode" "$fname"
done
fi

View File

@ -0,0 +1,132 @@
# The Rust Programming Language
[Foreword](foreword.md)
[Introduction](ch00-00-introduction.md)
## Getting started
- [Getting Started](ch01-00-getting-started.md)
- [Installation](ch01-01-installation.md)
- [Hello, World!](ch01-02-hello-world.md)
- [Hello, Cargo!](ch01-03-hello-cargo.md)
- [Programming a Guessing Game](ch02-00-guessing-game-tutorial.md)
- [Common Programming Concepts](ch03-00-common-programming-concepts.md)
- [Variables and Mutability](ch03-01-variables-and-mutability.md)
- [Data Types](ch03-02-data-types.md)
- [How Functions Work](ch03-03-how-functions-work.md)
- [Comments](ch03-04-comments.md)
- [Control Flow](ch03-05-control-flow.md)
- [Understanding Ownership](ch04-00-understanding-ownership.md)
- [What is Ownership?](ch04-01-what-is-ownership.md)
- [References & Borrowing](ch04-02-references-and-borrowing.md)
- [Slices](ch04-03-slices.md)
- [Using Structs to Structure Related Data](ch05-00-structs.md)
- [Defining and Instantiating Structs](ch05-01-defining-structs.md)
- [An Example Program Using Structs](ch05-02-example-structs.md)
- [Method Syntax](ch05-03-method-syntax.md)
- [Enums and Pattern Matching](ch06-00-enums.md)
- [Defining an Enum](ch06-01-defining-an-enum.md)
- [The `match` Control Flow Operator](ch06-02-match.md)
- [Concise Control Flow with `if let`](ch06-03-if-let.md)
## Basic Rust Literacy
- [Modules](ch07-00-modules.md)
- [`mod` and the Filesystem](ch07-01-mod-and-the-filesystem.md)
- [Controlling Visibility with `pub`](ch07-02-controlling-visibility-with-pub.md)
- [Referring to Names in Different Modules](ch07-03-importing-names-with-use.md)
- [Common Collections](ch08-00-common-collections.md)
- [Vectors](ch08-01-vectors.md)
- [Strings](ch08-02-strings.md)
- [Hash Maps](ch08-03-hash-maps.md)
- [Error Handling](ch09-00-error-handling.md)
- [Unrecoverable Errors with `panic!`](ch09-01-unrecoverable-errors-with-panic.md)
- [Recoverable Errors with `Result`](ch09-02-recoverable-errors-with-result.md)
- [To `panic!` or Not To `panic!`](ch09-03-to-panic-or-not-to-panic.md)
- [Generic Types, Traits, and Lifetimes](ch10-00-generics.md)
- [Generic Data Types](ch10-01-syntax.md)
- [Traits: Defining Shared Behavior](ch10-02-traits.md)
- [Validating References with Lifetimes](ch10-03-lifetime-syntax.md)
- [Testing](ch11-00-testing.md)
- [Writing tests](ch11-01-writing-tests.md)
- [Running tests](ch11-02-running-tests.md)
- [Test Organization](ch11-03-test-organization.md)
- [An I/O Project: Building a Command Line Program](ch12-00-an-io-project.md)
- [Accepting Command Line Arguments](ch12-01-accepting-command-line-arguments.md)
- [Reading a File](ch12-02-reading-a-file.md)
- [Refactoring to Improve Modularity and Error Handling](ch12-03-improving-error-handling-and-modularity.md)
- [Developing the Librarys Functionality with Test Driven Development](ch12-04-testing-the-librarys-functionality.md)
- [Working with Environment Variables](ch12-05-working-with-environment-variables.md)
- [Writing Error Messages to Standard Error Instead of Standard Output](ch12-06-writing-to-stderr-instead-of-stdout.md)
## Thinking in Rust
- [Functional Language Features: Iterators and Closures](ch13-00-functional-features.md)
- [Closures: Anonymous Functions that Can Capture Their Environment](ch13-01-closures.md)
- [Processing a Series of Items with Iterators](ch13-02-iterators.md)
- [Improving Our I/O Project](ch13-03-improving-our-io-project.md)
- [Comparing Performance: Loops vs. Iterators](ch13-04-performance.md)
- [More about Cargo and Crates.io](ch14-00-more-about-cargo.md)
- [Customizing Builds with Release Profiles](ch14-01-release-profiles.md)
- [Publishing a Crate to Crates.io](ch14-02-publishing-to-crates-io.md)
- [Cargo Workspaces](ch14-03-cargo-workspaces.md)
- [Installing Binaries from Crates.io with `cargo install`](ch14-04-installing-binaries.md)
- [Extending Cargo with Custom Commands](ch14-05-extending-cargo.md)
- [Smart Pointers](ch15-00-smart-pointers.md)
- [`Box<T>` Points to Data on the Heap and Has a Known Size](ch15-01-box.md)
- [The `Deref` Trait Allows Access to the Data Through a Reference](ch15-02-deref.md)
- [The `Drop` Trait Runs Code on Cleanup](ch15-03-drop.md)
- [`Rc<T>`, the Reference Counted Smart Pointer](ch15-04-rc.md)
- [`RefCell<T>` and the Interior Mutability Pattern](ch15-05-interior-mutability.md)
- [Creating Reference Cycles and Leaking Memory is Safe](ch15-06-reference-cycles.md)
- [Fearless Concurrency](ch16-00-concurrency.md)
- [Threads](ch16-01-threads.md)
- [Message Passing](ch16-02-message-passing.md)
- [Shared State](ch16-03-shared-state.md)
- [Extensible Concurrency: `Sync` and `Send`](ch16-04-extensible-concurrency-sync-and-send.md)
- [Object Oriented Programming Features of Rust](ch17-00-oop.md)
- [Characteristics of Object-Oriented Languages](ch17-01-what-is-oo.md)
- [Using Trait Objects that Allow for Values of Different Types](ch17-02-trait-objects.md)
- [Implementing an Object-Oriented Design Pattern](ch17-03-oo-design-patterns.md)
## Advanced Topics
- [Patterns Match the Structure of Values](ch18-00-patterns.md)
- [All the Places Patterns May be Used](ch18-01-all-the-places-for-patterns.md)
- [Refutability: Whether a Pattern Might Fail to Match](ch18-02-refutability.md)
- [All the Pattern Syntax](ch18-03-pattern-syntax.md)
- [Advanced Features](ch19-00-advanced-features.md)
- [Unsafe Rust](ch19-01-unsafe-rust.md)
- [Advanced Lifetimes](ch19-02-advanced-lifetimes.md)
- [Advanced Traits](ch19-03-advanced-traits.md)
- [Advanced Types](ch19-04-advanced-types.md)
- [Advanced Functions & Closures](ch19-05-advanced-functions-and-closures.md)
- [Final Project: Building a Multithreaded Web Server](ch20-00-final-project-a-web-server.md)
- [A Single Threaded Web Server](ch20-01-single-threaded.md)
- [Turning our Single Threaded Server into a Multithreaded Server](ch20-02-multithreaded.md)
- [Graceful Shutdown and Cleanup](ch20-03-graceful-shutdown-and-cleanup.md)
- [Appendix](appendix-00.md)
- [A - Keywords](appendix-01-keywords.md)
- [B - Operators and Symbols](appendix-02-operators.md)
- [C - Derivable Traits](appendix-03-derivable-traits.md)
- [D - Macros](appendix-04-macros.md)
- [E - Translations](appendix-05-translation.md)
- [F - Newest Features](appendix-06-newest-features.md)
- [G - How Rust is Made and “Nightly Rust”](appendix-07-nightly-rust.md)

View File

@ -0,0 +1,4 @@
# Appendix
The following sections contain reference material you may find useful in your
Rust journey.

View File

@ -0,0 +1,80 @@
## Appendix A: Keywords
The following is a list of keywords that are reserved for current or future use
by the Rust language. As such, these may not be used as identifiers, such as
names of functions, variables, parameters, struct fields, modules, crates,
constants, macros, static values, attributes, types, traits, or lifetimes.
### Keywords Currently in Use
* `as` - perform primitive casting, disambiguate the specific trait
containing an item, or rename items in `use` and `extern crate` statements
* `break` - exit a loop immediately
* `const` - define constant items or constant raw pointers
* `continue` - continue to the next loop iteration
* `crate` - link an external crate or a macro variable representing the crate
in which the macro is defined
* `else` - fallback for `if` and `if let` control flow constructs
* `enum` - define an enumeration
* `extern` - link an external crate, function, or variable
* `false` - Boolean false literal
* `fn` - define a function or the function pointer type
* `for` - loop over items from an iterator, implement a trait, or specify a
higher-ranked lifetime
* `if` - branch based on the result of a conditional expression
* `impl` - implement inherent or trait functionality
* `in` - part of `for` loop syntax
* `let` - bind a variable
* `loop` - loop unconditionally
* `match` - match a value to patterns
* `mod` - define a module
* `move` - make a closure take ownership of all its captures
* `mut` - denote mutability in references, raw pointers, or pattern bindings
* `pub` - denote public visibility in struct fields, `impl` blocks, or modules
* `ref` - bind by reference
* `return` - return from function
* `Self` - a type alias for the type implementing a trait
* `self` - method subject or current module
* `static` - global variable or lifetime lasting the entire program execution
* `struct` - define a structure
* `super` - parent module of the current module
* `trait` - define a trait
* `true` - Boolean true literal
* `type` - define a type alias or associated type
* `unsafe` - denote unsafe code, functions, traits, or implementations
* `use` - import symbols into scope
* `where` - denote clauses that constrain a type
* `while` - loop conditionally based on the result of an expression
<!-- we should make sure the definitions for each keyword are consistently
phrased, so for example for enum we say "defining an enumeration" but for fn we
passively call it a "function definition" -- perhaps a good medium would be
"define an enumeration" and "define a function"? Can you go through and make
those consistent? I've attempted it for a few, but am wary of changing meaning.
Also, you may decide to go the passive definition route, which is fine by me,
as long as it's consistent-->
<!-- I've tried, I'm not sure how to be active for keywords that are nouns
though. Please let me know if any still seem inconsistent /Carol -->
### Keywords Reserved for Future Use
These keywords do not have any functionality, but are reserved by Rust for
potential future use.
* `abstract`
* `alignof`
* `become`
* `box`
* `do`
* `final`
* `macro`
* `offsetof`
* `override`
* `priv`
* `proc`
* `pure`
* `sizeof`
* `typeof`
* `unsized`
* `virtual`
* `yield`

View File

@ -0,0 +1,172 @@
## Appendix B: Operators and Symbols
<!-- We try not to stack headings even in the appendix, can you add some intro
text about what this appendix contains? Quick example below -->
<!-- Done! /Carol -->
This appendix is a glossary of Rusts syntax, including operators and other
symbols that appear by themselves or in the context of paths, generics, trait
bounds, macros, attributes, comments, tuples, and brackets.
### Operators
The following lists the operators in Rust, an example of how the operator would
appear in context, a short explanation, and whether that operator is
overloadable. If an operator is overloadable, the relevant trait to use to
overload that operator is listed.
<!-- PROD: I'm not sure how to handle this, would it be too big for a table? I
think some structure with aligned columns would make it a great reference -->
* `!` (`ident!(…)`, `ident!{…}`, `ident![…]`): denotes macro expansion.
* `!` (`!expr`): bitwise or logical complement. Overloadable (`Not`).
* `!=` (`var != expr`): nonequality comparison. Overloadable (`PartialEq`).
* `%` (`expr % expr`): arithmetic remainder. Overloadable (`Rem`).
* `%=` (`var %= expr`): arithmetic remainder and assignment. Overloadable (`RemAssign`).
* `&` (`&expr`, `&mut expr`): borrow.
* `&` (`&type`, `&mut type`, `&'a type`, `&'a mut type`): borrowed pointer type.
* `&` (`expr & expr`): bitwise AND. Overloadable (`BitAnd`).
* `&=` (`var &= expr`): bitwise AND and assignment. Overloadable (`BitAndAssign`).
* `&&` (`expr && expr`): logical AND.
* `*` (`expr * expr`): arithmetic multiplication. Overloadable (`Mul`).
* `*` (`*expr`): dereference.
* `*` (`*const type`, `*mut type`): raw pointer.
* `*=` (`var *= expr`): arithmetic multiplication and assignment. Overloadable (`MulAssign`).
* `+` (`trait + trait`, `'a + trait`): compound type constraint.
* `+` (`expr + expr`): arithmetic addition. Overloadable (`Add`).
* `+=` (`var += expr`): arithmetic addition and assignment. Overloadable (`AddAssign`).
* `,`: argument and element separator.
* `-` (`- expr`): arithmetic negation. Overloadable (`Neg`).
* `-` (`expr - expr`): arithmetic subtraction. Overloadable (`Sub`).
* `-=` (`var -= expr`): arithmetic subtraction and assignment. Overloadable (`SubAssign`).
* `->` (`fn(…) -> type`, `|…| -> type`): function and closure return type.
* `.` (`expr.ident`): member access.
* `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal.
* `..` (`..expr`): struct literal update syntax.
* `..` (`variant(x, ..)`, `struct_type { x, .. }`): “and the rest” pattern binding.
* `...` (`expr...expr`) *in a pattern*: inclusive range pattern.
* `/` (`expr / expr`): arithmetic division. Overloadable (`Div`).
* `/=` (`var /= expr`): arithmetic division and assignment. Overloadable (`DivAssign`).
* `:` (`pat: type`, `ident: type`): constraints.
* `:` (`ident: expr`): struct field initializer.
* `:` (`'a: loop {…}`): loop label.
* `;`: statement and item terminator.
* `;` (`[…; len]`): part of fixed-size array syntax
* `<<` (`expr << expr`): left-shift. Overloadable (`Shl`).
* `<<=` (`var <<= expr`): left-shift and assignment. Overloadable (`ShlAssign`).
* `<` (`expr < expr`): less-than comparison. Overloadable (`PartialOrd`).
* `<=` (`expr <= expr`): less-than or equal-to comparison. Overloadable (`PartialOrd`).
* `=` (`var = expr`, `ident = type`): assignment/equivalence.
* `==` (`expr == expr`): equality comparison. Overloadable (`PartialEq`).
* `=>` (`pat => expr`): part of match arm syntax.
* `>` (`expr > expr`): greater-than comparison. Overloadable (`PartialOrd`).
* `>=` (`expr >= expr`): greater-than or equal-to comparison. Overloadable (`PartialOrd`).
* `>>` (`expr >> expr`): right-shift. Overloadable (`Shr`).
* `>>=` (`var >>= expr`): right-shift and assignment. Overloadable (`ShrAssign`).
* `@` (`ident @ pat`): pattern binding.
* `^` (`expr ^ expr`): bitwise exclusive OR. Overloadable (`BitXor`).
* `^=` (`var ^= expr`): bitwise exclusive OR and assignment. Overloadable (`BitXorAssign`).
* `|` (`pat | pat`): pattern alternatives.
* `|` (`|…| expr`): closures.
* `|` (`expr | expr`): bitwise OR. Overloadable (`BitOr`).
* `|=` (`var |= expr`): bitwise OR and assignment. Overloadable (`BitOrAssign`).
* `||` (`expr || expr`): logical OR.
* `_`: “ignored” pattern binding. Also used to make integer-literals readable.
* `?` (`expr?`): Error propagation.
### Non-operator Symbols
<!-- And maybe a quick explanation of what you mean by non-operator
symbols/what counts as a non-operator symbol? -->
<!-- I've tried but it's hard to explain, it's the kind of thing you know when
you see it? /Carol -->
The following lists all non-letters that dont function as operators; that is,
they dont behave like a function or method call.
#### Standalone Syntax
* `'ident`: named lifetime or loop label
* `…u8`, `…i32`, `…f64`, `…usize`, *etc.*: numeric literal of specific type.
* `"…"`: string literal.
* `r"…"`, `r#"…"#`, `r##"…"##`, *etc.*: raw string literal, escape characters are not processed.
* `b"…"`: byte string literal, constructs a `[u8]` instead of a string.
* `br"…"`, `br#"…"#`, `br##"…"##`, *etc.*: raw byte string literal, combination of raw and byte string literal.
* `'…'`: character literal.
* `b'…'`: ASCII byte literal.
* `|…| expr`: closure.
* `!`: always empty bottom type for diverging functions.
#### Path-related Syntax
* `ident::ident`: namespace path.
* `::path`: path relative to the crate root (*i.e.* an explicitly absolute path).
* `self::path`: path relative to the current module (*i.e.* an explicitly relative path).
* `super::path`: path relative to the parent of the current module.
* `type::ident`, `<type as trait>::ident`: associated constants, functions, and types.
* `<type>::…`: associated item for a type which cannot be directly named (*e.g.* `<&T>::…`, `<[T]>::…`, *etc.*).
* `trait::method(…)`: disambiguating a method call by naming the trait which defines it.
* `type::method(…)`: disambiguating a method call by naming the type for which its defined.
* `<type as trait>::method(…)`: disambiguating a method call by naming the trait *and* type.
#### Generics
* `path<…>` (*e.g.* `Vec<u8>`): specifies parameters to generic type *in a type*.
* `path::<…>`, `method::<…>` (*e.g.* `"42".parse::<i32>()`): specifies parameters to generic type, function, or method *in an expression*. Often referred to as *turbofish*.
* `fn ident<…> …`: define generic function.
* `struct ident<…> …`: define generic structure.
* `enum ident<…> …`: define generic enumeration.
* `impl<…> …`: define generic implementation.
* `for<…> type`: higher-ranked lifetime bounds.
* `type<ident=type>` (*e.g.* `Iterator<Item=T>`): a generic type where one or more associated types have specific assignments.
#### Trait Bound Constraints
* `T: U`: generic parameter `T` constrained to types that implement `U`.
* `T: 'a`: generic type `T` must outlive lifetime `'a`. When we say that a type outlives the lifetime, we mean that it cannot transitively contain any references with lifetimes shorter than `'a`.
* `T : 'static`: The generic type `T` contains no borrowed references other than `'static` ones.
* `'b: 'a`: generic lifetime `'b` must outlive lifetime `'a`.
* `T: ?Sized`: allow generic type parameter to be a dynamically-sized type.
* `'a + trait`, `trait + trait`: compound type constraint.
#### Macros and Attributes
* `#[meta]`: outer attribute.
* `#![meta]`: inner attribute.
* `$ident`: macro substitution.
* `$ident:kind`: macro capture.
* `$(…)…`: macro repetition.
#### Comments
* `//`: line comment.
* `//!`: inner line doc comment.
* `///`: outer line doc comment.
* `/*…*/`: block comment.
* `/*!…*/`: inner block doc comment.
* `/**…*/`: outer block doc comment.
#### Tuples
* `()`: empty tuple (*a.k.a.* unit), both literal and type.
* `(expr)`: parenthesized expression.
* `(expr,)`: single-element tuple expression.
* `(type,)`: single-element tuple type.
* `(expr, …)`: tuple expression.
* `(type, …)`: tuple type.
* `expr(expr, …)`: function call expression. Also used to initialize tuple `struct`s and tuple `enum` variants.
* `ident!(…)`, `ident!{…}`, `ident![…]`: macro invocation.
* `expr.0`, `expr.1`, …: tuple indexing.
#### Curly Brackets
* `{…}`: block expression.
* `Type {…}`: `struct` literal.
#### Square Brackets
* `[…]`: array literal.
* `[expr; len]`: array literal containing `len` copies of `expr`.
* `[type; len]`: array type containing `len` instances of `type`.
* `expr[expr]`: collection indexing. Overloadable (`Index`, `IndexMut`).
* `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]`: collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, `RangeFull` as the “index”.

View File

@ -0,0 +1,230 @@
## C - Derivable Traits
In various places in the book, weve discussed the `derive` attribute
that you can apply to a struct or enum definition.
<!-- Above -- I wasn't clear throughout whether the derive attribute is
something passively applied to structs and enums by Rust, or something the
reader applies. I've experimented with making the tone more active, but may
have misinterpreted -- can you make it clear here? Should this be "we've
discussed the `derive` attribute you can apply to a struct or enum"? -->
<!-- Rust never edits your source code file for you. I'm curious to know what
parts of the book have given you that impression... I've tried to clarify here
but now I'm worried about other places in the book... /Carol -->
<!-- Below -- Can you lay out what it is we're showing them about derivable
traits in this appendix, just showing them some common ones and how to use
them? -->
<!-- No, we're showing *all* of the derivable traits provided by the standard
library. I guess explaining what we mean by "derivable" was too much of a
tangent for the beginning of this section? I'm not sure where that would fit
instead, so I took it out. So now the text that we had under the "standard
library traits that can be derived" section is here where it seems like you
were expecting it to be /Carol -->
The `derive` attribute generates code that will implement a trait with its own
default implementation, on the type you have annotated with the `derive`
syntax. In this appendix, we provide a reference of all of the traits in the
standard library that can be used with `derive`. Each section covers:
- What operators and methods deriving this trait will enable
- What the implementation of the trait provided by `derive` does
- What implementing the trait signifies about the type
- The conditions in which youre allowed or not allowed to implement the trait
- Examples of operations that require the trait
If you want different behavior than that provided by the `derive` attribute,
consult the standard library documentation for each trait for details of how to
manually implement them.
<!-- Liz: I've incorporated the small sections that were after the list of
traits here and then moved the section headings out a level, what do you think?
/Carol -->
The rest of the traits defined in the standard library cant be implemented on
your types using `derive`. These traits dont have sensible default behavior,
so its up to you to implement them in the way that makes sense for what youre
trying to accomplish.
An example of a trait that cant be derived is `Display`, which handles
formatting for end users. You should always put thought into the appropriate
way to display a type to an end user: what parts of the type should an end user
be allowed to see? What parts would they find relevant? What format of the data
would be most relevant to them? The Rust compiler doesnt have this insight and
so cant provide appropriate default behavior for you.
The list of derivable traits provided in this appendix is not comprehensive:
libraries can implement `derive` for their own traits! In this way, the list of
traits you can use `derive` with is truly open-ended. Implementing `derive`
involves using a procedural macro, which is covered in Appendix D, “Macros.”
### `Debug` for Programmer Output
The `Debug` trait enables debug formatting in format strings, indicated by
adding `:?` within `{}` placeholders.
The `Debug` trait allows you to print instances of a type for debugging
purposes, so you and other programmers using your type can inspect an instance
at a particular point in a programs execution.
`Debug` is required, for example, in use of the `assert_eq!` macro, which
prints the values of instances given as arguments if the equality assertion
fails so programmers can see why the two instances werent equal.
### `PartialEq` and `Eq` for Equality Comparisons
<!-- I've tried to phrase these definitions in a more active way, it seems like
we're saying using these traits gives us this capabilities --- apologies if
I've misunderstood, feel free to change the phrasing back to the "signifies
that..." version -->
<!-- More active is fine. I feel like it lost a tiny bit of meaning-- not only
can we use these capabilities on our own types, but other programmers using our
types can use these capabilities too. I've tried to reinsert that sentiment
occasionally. /Carol -->
The `PartialEq` trait allows you to compare instances of a type to check for
equality, and enables use of the `==` and `!=` operators.
Deriving `PartialEq` implements the `eq` method. When `PartialEq` is derived on
structs, two instances are equal only if *all* fields are equal, and not equal
if any fields are not equal. When derived on enums, each variant is equal to
itself and not equal to the other variants.
`PartialEq` is required, for example, with the use of the `assert_eq!` macro,
which needs to be able to compare two instances of a type for equality.
The `Eq` trait has no methods. Its purpose is to signal that for every value of
the annotated type, the value is equal to itself. The `Eq` trait can only be
applied to types that also implement `PartialEq`, though not all types that
implement `PartialEq` can implement `Eq`. One example of this is floating point
number types: the implementation of floating point numbers says that two
instances of the not-a-number value, `NaN`, are not equal to each other.
An example of when `Eq` is required is for keys in a `HashMap` so that the
`HashMap` can tell whether two keys are the same.
### `PartialOrd` and `Ord` for Ordering Comparisons
The `PartialOrd` trait allows you to compare instances of a type for sorting
purposes. A type that implements `PartialOrd` may be used with the `<`, `>`,
`<=`, and `>=` operators. The `PartialOrd` trait can only be applied to types
that also implement `PartialEq`.
Deriving `PartialOrd` implements the `partial_cmp` method, which returns an
`Option<Ordering>` that will be `None` when the values given do not produce an
ordering. An example of a value that doesnt produce an ordering, even though
most values of that type can be compared, is the not-a-number (`NaN`) floating
point value. Calling `partial_cmp` with any floating point number and the `NaN`
floating point value will return `None`.
<!-- Above -- you mean when the values cannot be ordered, for example if they
are of types that can't be compared? -->
<!-- No, if they're *types* that can't be compared, then the PartialOrd trait
doesn't apply at all. I've tried to clarify and added an example /Carol-->
When derived on structs, `PartialOrd` compares two instances by comparing the
value in each field in the order in which the fields appear in the struct
definition. When derived on enums, variants of the enum declared earlier in the
enum definition are considered greater than the variants listed later.
`PartialOrd` is required, for example, for the `gen_range` method from the
`rand` crate that generates a random value in the range specified by a low
value and a high value.
The `Ord` trait allows you to know that for any two values of the annotated
type, a valid ordering will exist. The `Ord` trait implements the `cmp` method,
which returns an `Ordering` rather than an `Option<Ordering>` because a valid
ordering will always be possible. The `Ord` trait can only be applied to types
that also implement `PartialOrd` and `Eq` (and `Eq` requires `PartialEq`). When
derived on structs and enums, `cmp` behaves the same way as the derived
implementation for `partial_cmp` does with `PartialOrd`.
An example of when `Ord` is required is when storing values in a `BTreeSet<T>`,
a data structure that stores data based on the sort order of the values.
### `Clone` and `Copy` for Duplicating Values
<!-- Below -- I wasn't clear on the arbitrary code section of this explanation.
Are we saying using Clone (as opposed to copy) risks bringing it arbitrary
code? Why use Clone over copy? (I think we might have covered this in an
earlier chapter, so feel free to cross ref there too if that's an easier
explanation) -->
<!-- Yes, we covered this in chapter 4 and I've added a cross reference. /Carol
-->
The `Clone` trait allows you to explicitly create a deep copy of a value, and
the duplication process might involve running arbitrary code and copying heap
data. See the “Ways Variables and Data Interact: Clone” section in Chapter 4
for more information on `Clone`.
Deriving `Clone` implements the `clone` method which, when implemented for the
whole type, calls `clone` on each of the parts of the type. This means all of
the fields or values in the type must also implement `Clone` to derive `Clone`.
An example of when `Clone` is required is when calling the `to_vec` method on a
slice. The slice doesnt own the type instances it contains, but the vector
returned from `to_vec` will need to own its instances, so `to_vec` calls
`clone` on each item. Thus, the type stored in the slice must implement `Clone`.
The `Copy` trait allows you to duplicate a value by only copying bits stored on
the stack; no arbitrary code is necessary. See the “Stack-Only Data: Copy”
section in Chapter 4 for more information on `Copy`.
<!-- I'm not clear on why the clone trait uses arbitrary code but copy doesn't
-- is this important to make clear? -->
<!-- We discussed this in chapter 4; I've added a cross ref. /Carol -->
The `Copy` trait does not define any methods to prevent programmers from
overloading those methods violating the assumption that no arbitrary code is
being run. That way, all programmers can assume that copying a value will be
very fast.
<!-- above -- I couldn't follow this either, what does that mean practically
for the programmer? What does overloading methods that violate the assumption
mean? -->
<!-- I added a sentence at the end of the paragraph, does that clear it up?
/Carol -->
You can derive `Copy` on any type whose parts all implement `Copy`. The `Copy`
trait can only be applied to types that also implement `Clone`, as a type that
implements `Copy` has a trivial implementation of `Clone`, doing the same thing
as `Copy`.
`Copy` is rarely required; types implement `Copy` have optimizations available
mean you dont have to call `clone`, making the code more concise.
<!-- By "nicer" do you mean more efficient and understandable? -->
<!-- concise, I've changed /Carol -->
Everything possible with `Copy` can also be accomplished with `Clone`, but the
code might be slower or have to use `clone` in places.
### `Hash` for Mapping a Value to a Value of Fixed Size
The `Hash` trait allows you to take an instance of a type of arbitrary size and
map that instance to a value of fixed size, using a hash function. Deriving
`Hash` implements the `hash` method. The derived implementation of the `hash`
method combines the result of calling `hash` on each of the parts of the type,
meaning all fields or values must also implement `Hash` to derive `Hash`.
An example of when `Hash` is required is in storing keys in a `HashMap`, in
order to store data efficiently.
### `Default` for Default Values
The `Default` trait allows you to create a default value for a type. Deriving
`Default` implements the `default` method. The derived implementation of the
`default` method calls the `default` method on each part of the type, meaning
all fields or values in the type must also implement `Default` to derive
`Default.`
`Default::default` is commonly used in combination with the struct update
syntax discussed in the “Creating Instances From Other Instances With Struct
Update Syntax” section in Chapter 5. You can customize a few fields of a struct
and then set and use a default value for the rest of the fields by using
`..Default::default()`.
`Default` is required when, for example, you use the `unwrap_or_default` method
on `Option<T>` instances. If the `Option<T>` is `None`, the `unwrap_or_default`
method will return the result of `Default::default` for the type `T` stored in
the `Option<T>`.

View File

@ -0,0 +1,504 @@
## Appendix D: Macros
Weve used macros like `println!` throughout this book, but havent fully
explored what a macro is and how it works. This appendix will explain:
- What macros are and how they differ from functions
- How to define a declarative macro to do metaprogramming
- How to define a procedural macro to create custom `derive` traits
Were covering the details of macros in an appendix because theyre still
evolving in Rust. Macros have changed and, in the near future, will change at a
quicker rate than the rest of the language and standard library since Rust 1.0,
so this section is more likely to date than the rest of the book. The code
shown here will still continue to work with future versions, due to Rusts
stability guarantees, but there may be additional capabilities or easier ways
to write macros that werent available at the time of this publication. Bear
that in mind if you try to implement anything from this appendix.
### The Difference Between Macros and Functions
Fundamentally, macros are a way of writing code that writes other code, known
as *metaprogramming*. In Appendix C, we discussed the `derive` attribute, which
generates an implementation of various traits for you. Weve also used the
`println!` and `vec!` macros throughout the book. All of these macros *expand*
to produce more code than the code youve written yourself.
Metaprogramming is useful for reducing the amount of code you have to write and
maintain, which is also one of the roles of functions. However, macros have
some additional powers that functions dont have.
A function signature has to declare the number and type of parameters the
function has. Macros, on the other hand, can take a variable number of
parameters: we can call `println!("hello")` with one argument, or
`println!("hello {}", name)` with two arguments. Also, macros are expanded
before the compiler interprets the meaning of the code, so a macro can, for
example, implement a trait on a given type. A function cant, because it gets
called at runtime and a trait needs to be implemented at compile time.
The downside to implementing a macro over a function is that macro definitions
are more complex than function definitions because youre writing Rust code
that writes Rust code. Due to this indirection, macro definitions are generally
more difficult to read, understand, and maintain than function definitions.
Another difference between macros and functions is that macro definitions
arent namespaced within modules like function definitions are. In order to
prevent unexpected name clashes when using external crates, you have to
explicitly bring the macros into the scope of your project at the same time as
bringing the external crate into scope, using the `#[macro_use]` annotation.
The following example would bring all the macros defined in the `serde` crate
into the scope of the current crate:
```rust,ignore
#[macro_use]
extern crate serde;
```
If `extern crate` was able to bring macros into scope by default without this
explicit annotation, you would be prevented from using two crates that happened
to define macros with the same name. In practice this conflict doesnt come up
much, but the more crates you use, the more likely it is.
One last important difference between macros and functions: macros must be
defined or brought into scope *before* theyre called in a file, whereas
functions can be defined anywhere and called anywhere.
### Declarative Macros with `macro_rules!` for General Metaprogramming
The most widely used form of macros in Rust are *declarative macros*. These are
also sometimes referred to as *macros by example*, *`macro_rules!` macros*, or
just plain *macros*. At their core, declarative macros allow you to write
something similar to a Rust `match` expression. As discussed in Chapter 6,
`match` expressions are control structures that take an expression, compare the
resulting value of the expression to patterns, and then run the code associated
with the matching pattern. Macros also compare a value to patterns that have
code associated with them, but in this case the value is the literal Rust
source code passed to the macro, the patterns are compared with the structure
of that source code, and the code associated with each pattern is the code that
replaces the code passed to the macro. This all happens during compilation.
To define a macro, you use the `macro_rules!` construct. Lets explore how to
use `macro_rules!` by taking a look at how the `vec!` macro is defined. Chapter
8 covered how we can use the `vec!` macro to create a new vector with
particular values. For example, this macro creates a new vector with three
integers inside:
```rust
let v: Vec<u32> = vec![1, 2, 3];
```
We could also use the `vec!` macro to make a vector of two integers or a vector
of five string slices---we wouldnt be able to use a function to do the same
because we wouldnt know the number or type of values up front.
Lets take a look at a slightly simplified definition of the `vec!` macro in
Listing AD-1:
```rust
#[macro_export]
macro_rules! vec {
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
```
Listing AD-1: A simplified version of the `vec!` macro definition
> Note: the actual definition of the `vec!` macro in the standard library
> includes code to pre-allocate the correct amount of memory up-front. That
> code is an optimization that weve chosen not to include here to make the
> example simpler.
The `#[macro_export]` annotation indicates that this macro should be made
available whenever the crate in which were defining the macro is imported.
Without this annotation, even if someone depending on this crate uses the
`#[macro_use]` annotation, the macro would not be brought into scope.
We then start the macro definition with `macro_rules!` and the name of the
macro were defining *without* the exclamation mark. The name---in this case
`vec`---is followed by curly brackets denoting the body of the macro definition.
The structure in the `vec!` body is similar to the structure of a `match`
expression. Here we have one arm with the pattern `( $( $x:expr ),* )`,
followed by `=>` and the block of code associated with this pattern. If the
pattern matches, the associated block of code will be emitted. Given that this
is the only pattern in this macro, theres only one valid way to match; any
other will be an error. More complex macros will have more than one arm.
Valid pattern syntax in macro definitions is different than the pattern syntax
covered in Chapter 18 because macro patterns are matched against Rust code
structure rather than values. Lets walk through what the pieces of the pattern
in Listing AD-1 mean; for the full macro pattern syntax, see [the reference].
[the reference]: ../../reference/macros.html
First, a set of parentheses encompasses the whole pattern. Next comes a dollar
sign (`$`) followed by a set of parentheses, which captures values that match
the pattern within the parentheses for use in the replacement code. Within
`$()` is `$x:expr`, which matches any Rust expression and gives the expression
the name `$x`.
The comma following `$()` indicates that a literal comma separator character
could optionally appear after the code that matches the code captured in `$()`.
The `*` following the comma specifies that the pattern matches zero or more of
whatever precedes the `*`.
When we call this macro with `vec![1, 2, 3];`, the `$x` pattern matches three
times with the three expressions `1`, `2`, and `3`.
Now lets look at the pattern in the body of the code associated with this arm:
The `temp_vec.push()` code within the `$()*` part is generated for each part
that matches `$()` in the pattern, zero or more times depending on how many
times the pattern matches. The `$x` is replaced with each expression matched.
When we call this macro with `vec![1, 2, 3];`, the code generated that replaces
this macro call will be:
<!-- Above What about temp_vec.push, do you want to quickly mention that? Or do
you mean "The `$()*` part and the content of the parentheses is generated for
each part that matches `$()` in the pattern"-->
<!-- The latter, I've tried to clarify /Carol -->
```rust,ignore
let mut temp_vec = Vec::new();
temp_vec.push(1);
temp_vec.push(2);
temp_vec.push(3);
temp_vec
```
Weve defined a macro that can take any number of arguments of any type and can
generate code to create a vector containing the specified elements.
Given that most Rust programmers will *use* macros more than *write* macros,
thats all well discuss about `macro_rules!` in this book. To learn more about
how to write macros, consult the online documentation or other resources such
as [The Little Book of Rust Macros][tlborm].
[tlborm]: https://danielkeep.github.io/tlborm/book/index.html
### Procedural Macros for Custom `derive`
The second form of macros is called *procedural macros* because theyre more
like functions (which are a type of procedure). Procedural macros accept some
Rust code as an input, operate on that code, and produce some Rust code as an
output, rather than matching against patterns and replacing the code with other
code as declarative macros do. At the time of writing, you can only really
define procedural macros to allow your traits to be implemented on a type by
specifying the trait name in a `derive` annotation.
Were going to create a crate named `hello_macro` that defines a trait named
`HelloMacro` with one associated function named `hello_macro`. Rather than
making users of our crate implement the `HelloMacro` trait for each of their
types, well provide a procedural macro so users can annotate their type with
`#[derive(HelloMacro)]` to get a default implementation of the `hello_macro`
function. The default implementation will print `Hello, Macro! My name is
TypeName!` where `TypeName` is the name of the type on which this trait has
been defined.
In other words, were going to write a crate that enables another programmer to
write code like Listing AD-2 using our crate:
<span class="filename">Filename: src/main.rs</span>
```rust,ignore
extern crate hello_macro;
#[macro_use]
extern crate hello_macro_derive;
use hello_macro::HelloMacro;
#[derive(HelloMacro)]
struct Pancakes;
fn main() {
Pancakes::hello_macro();
}
```
<span class="caption">Listing AD-2: The code a user of our crate will be able
to write with use of our procedural macro</span>
This code will print `Hello, Macro! My name is Pancakes!` when were done. Lets
get started! First we need to make a new library crate:
```text
$ cargo new hello_macro --lib
```
Now well define the `HelloMacro` trait and its associated function:
<span class="filename">Filename: src/lib.rs</span>
```rust
pub trait HelloMacro {
fn hello_macro();
}
```
We have a trait and its function. At this point, a user of our crate would be
able to implement the trait themselves to achieve the desired functionality,
like so:
```rust,ignore
extern crate hello_macro;
use hello_macro::HelloMacro;
struct Pancakes;
impl HelloMacro for Pancakes {
fn hello_macro() {
println!("Hello, Macro! My name is Pancakes!");
}
}
fn main() {
Pancakes::hello_macro();
}
```
However, they would need to write out the implementation block for each type
they wanted to use with `hello_macro`; wed like to save them this work.
Additionally, we cant yet provide a default implementation for the
`hello_macro` function that will print out the name of the type the trait is
implemented on: Rust doesnt have reflection capabilities, so cant look up the
types name at runtime. We need a macro to generate code at compile time.
<!--Defining Procedural Macros Requires a Separate Crate--> <!-- Since this is
a lone subheading, okay to merge with the general procedural macros section? -->
<!-- Sure /Carol -->
The next step is to define the procedural macro. At the time of writing,
procedural macros need to be in their own crate. Eventually, this restriction
may be lifted. The convention for structuring crates and macro crates is as
such: for a crate named `foo`, a custom derive procedural macro crate is called
`foo-derive`. Lets start a new crate called `hello_macro_derive` inside our
`hello_macro` project:
```text
$ cargo new hello_macro_derive --lib
```
Our two crates are tightly related, so we create the procedural macro crate
within the directory of our `hello_macro` crate. If we change the trait
definition in `hello_macro`, well have to change the implementation of the
procedural macro in `hello_macro_derive` as well. The two crates will need to
be published separately, though, and programmers using these crates will need
to add both as dependencies and bring them both into scope. We could instead
have the `hello_macro` crate use `hello_macro_derive` as a dependency and
re-export the procedural macro code, but the way weve structured the project
makes it possible for programmers to use `hello_macro` even if they dont want
the `derive` functionality.
We need to declare the `hello_macro_derive` crate as a procedural macro crate.
Well also need functionality from the `syn` and `quote` crates, as well see
in a moment, so we need to add them as dependencies. Add the following to the
*Cargo.toml* file for `hello_macro_derive`:
<span class="filename">Filename: hello_macro_derive/Cargo.toml</span>
```toml
[lib]
proc-macro = true
[dependencies]
syn = "0.11.11"
quote = "0.3.15"
```
To start defining the procedural macro, place the code from Listing AD-3 in
your *src/lib.rs* for the `hello_macro_derive` crate. Note that this wont
compile until we add a definition for the `impl_hello_macro` function.
Note the way weve split the functions in AD-3; this will be the same for
almost every procedural macro crate you see or create, as it makes writing a
procedural macro more convenient. What you choose to do in the place where the
`impl_hello_macro` function is called will be different depending on the
purpose of your procedural macro.
<span class="filename">Filename: hello_macro_derive/src/lib.rs</span>
```rust,ignore
extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
use proc_macro::TokenStream;
#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
// Construct a string representation of the type definition
let s = input.to_string();
// Parse the string representation
let ast = syn::parse_derive_input(&s).unwrap();
// Build the impl
let gen = impl_hello_macro(&ast);
// Return the generated impl
gen.parse().unwrap()
}
```
<span class="caption">Listing AD-3: Code that most procedural macro crates will
need to have for processing Rust code</span>
We have introduced three new crates: `proc_macro`, [`syn`], and [`quote`]. The
`proc_macro` crate comes with Rust, so we didnt need to add that to the
dependencies in *Cargo.toml*. The `proc_macro` crate allows us to convert Rust
code into a string containing that Rust code. The `syn` crate parses Rust code
from a string into a data structure that we can perform operations on. The
`quote` crate takes `syn` data structures and turns them back into Rust code.
These crates make it much simpler to parse any sort of Rust code we might want
to handle: writing a full parser for Rust code is no simple task.
[`syn`]: https://crates.io/crates/syn
[`quote`]: https://crates.io/crates/quote
The `hello_macro_derive` function will get called when a user of our library
specifies `#[derive(HelloMacro)]` on a type, because weve annotated the
`hello_macro_derive` function here with `proc_macro_derive` and specified the
name, `HelloMacro`, which matches our trait name; thats the convention most
procedural macros follow.
This function first converts the `input` from a `TokenStream` to a `String` by
calling `to_string`. This `String` is a string representation of the Rust code
for which we are deriving `HelloMacro`. In the example in Listing AD-2, `s`
will have the `String` value `struct Pancakes;` because thats the Rust code we
added the `#[derive(HelloMacro)]` annotation to.
<!-- I'm not sure why we convert to a string then to a structure we can use,
will that be clear to the reader here? -->
<!-- This is just how procedural macros work and what you have to do, which is
why we have the next note. /Carol -->
> Note: At the time of writing, the only thing you can do with a `TokenStream`
> is convert it to a string. A richer API will exist in the future.
Now we need to be able to parse the Rust code `String` into a data structure
that we can then interpret and perform operations on. This is where `syn` comes
to play. The `parse_derive_input` function in `syn` takes a `String` and
returns a `DeriveInput` struct representing the parsed Rust code. The following
shows the relevant parts of the `DeriveInput` struct we get from parsing the
string `struct Pancakes;`:
```rust,ignore
DeriveInput {
// --snip--
ident: Ident(
"Pancakes"
),
body: Struct(
Unit
)
}
```
The fields of this struct show that the Rust code weve parsed is a unit struct
with the `ident` (identifier, meaning the name) of `Pancakes`. There are more
fields on this struct for describing all sorts of Rust code; check the [`syn`
API docs for `DeriveInput`][syn-docs] for more information.
[syn-docs]: https://docs.rs/syn/0.11.11/syn/struct.DeriveInput.html
At this point we havent defined the `impl_hello_macro` function, which is
where well build the new Rust code we want to include. Before we get to that,
the last part of this `hello_macro_derive` function is using the `parse`
function from the `quote` crate to turn the output of the `impl_hello_macro`
function back into a `TokenStream`. The returned `TokenStream` is added to the
code that users of our crate write so that when they compile their crate, they
get extra functionality we provide.
You may have noticed that were calling `unwrap` to panic if the calls to the
`parse_derive_input` or `parse` functions fail here. Panicking on errors is
necessary in procedural macro code because `proc_macro_derive` functions must
return `TokenStream` rather than `Result` in order to conform to the procedural
macro API. Weve chosen to keep this example simple by using `unwrap`; in
production code you should provide more specific error messages about what went
wrong by using `expect` or `panic!`.
Now that we have the code to turn the annotated Rust code from a `TokenStream`
into a `String` and a `DeriveInput` instance, lets generate the code
implementing the `HelloMacro` trait on the annotated type:
<span class="filename">Filename: hello_macro_derive/src/lib.rs</span>
```rust,ignore
fn impl_hello_macro(ast: &syn::DeriveInput) -> quote::Tokens {
let name = &ast.ident;
quote! {
impl HelloMacro for #name {
fn hello_macro() {
println!("Hello, Macro! My name is {}", stringify!(#name));
}
}
}
}
```
We get an `Ident` struct instance containing the name (identifier) of the
annotated type using `ast.ident`. With the code from Listing AD-2, `name` will
be `Ident("Pancakes")`.
The `quote!` macro lets us write up the Rust code that we want to return and
convert it into `quote::Tokens`. This macro also provides some really cool
templating mechanics; we can write `#name` and `quote!` will replace it with
the value in the variable named `name`. You can even do some repetition similar
to the way regular macros work. Check out [the `quote` crates
docs][quote-docs] for a thorough introduction.
[quote-docs]: https://docs.rs/quote
We want our procedural macro to generate an implementation of our `HelloMacro`
trait for the type the user annotated, which we can get by using `#name`. The
trait implementation has one function, `hello_macro`, whose body contains the
functionality we want to provide: printing `Hello, Macro! My name is` and then
the name of the annotated type.
The `stringify!` macro used here is built into Rust. It takes a Rust
expression, such as `1 + 2`, and at compile time turns the expression into a
string literal, such as `"1 + 2"`. This is different than `format!` or
`println!`, which evaluate the expression and then turn the result into a
`String`. Theres a possibility that the `#name` input might be an expression
to print out literally so we use `stringify!`. Using `stringify!` also saves an
allocation by converting `#name` to a string literal at compile time.
At this point, `cargo build` should complete successfully in both `hello_macro`
and `hello_macro_derive`. Lets hook these crates up to the code in Listing
AD-2 to see it in action! Create a new binary project in your `projects`
directory with `cargo new --bin pancakes`. We need to add both `hello_macro`
and `hello_macro_derive` as dependencies in the `pancakes` crates
*Cargo.toml*. If youve chosen to publish your versions of `hello_macro` and
`hello_macro_derive` to *https://crates.io* they would be regular dependencies;
if not, you can specify them as `path` dependencies as follows:
```toml
[dependencies]
hello_macro = { path = "../hello_macro" }
hello_macro_derive = { path = "../hello_macro/hello_macro_derive" }
```
Put the code from Listing AD-2 into *src/main.rs*, and when you run `cargo run`
it should print `Hello, Macro! My name is Pancakes!` The implementation of the
`HelloMacro` trait from the procedural macro was included without the
`pancakes` crate needing to implement it; the `#[derive(HelloMacro)]` took care
of adding the trait implementation.
### The Future of Macros
In the future, well be expanding both declarative and procedural macros. Rust
will use better declarative macro system with the `macro` keyword, and well
add more types of procedural macros, for more powerful tasks than just
`derive`. These systems are still under development at the time of publication;
please consult the online Rust documentation for the latest information.

View File

@ -0,0 +1,22 @@
## Appendix E: Translations of the Book
For resources in languages other than English. Most are still in progress; see
[the Translations label][label] to help or let us know about a new translation!
[label]: https://github.com/rust-lang/book/issues?q=is%3Aopen+is%3Aissue+label%3ATranslations
- [Português](https://github.com/rust-br/rust-book-pt-br) (BR)
- [Português](https://github.com/nunojesus/rust-book-pt-pt) (PT)
- [Tiếng việt](https://github.com/hngnaig/rust-lang-book/tree/vi-VN)
- [简体中文](http://www.broadview.com.cn/article/144), [alternate](https://github.com/KaiserY/trpl-zh-cn)
- [Українська](https://github.com/pavloslav/rust-book-uk-ua)
- [Español](https://github.com/thecodix/book)
- [Italiano](https://github.com/CodelessFuture/trpl2-it)
- [Русский](https://github.com/iDeBugger/rust-book-ru)
- [한국어](https://github.com/rinthel/rust-lang-book-ko)
- [日本語](https://github.com/hazama-yuinyan/book)
- [Français](https://github.com/quadrifoglio/rust-book-fr)
- [Polski](https://github.com/paytchoo/book-pl)
- [עברית](https://github.com/idanmel/rust-book-heb)
- [Cebuano](https://github.com/agentzero1/book)
- [Tagalog](https://github.com/josephace135/book)

View File

@ -0,0 +1,128 @@
# Appendix F - Newest Features
This appendix documents features that have been added to stable Rust since the
main part of the book was completed.
## Field init shorthand
We can initialize a data structure (struct, enum, union) with named
fields, by writing `fieldname` as a shorthand for `fieldname: fieldname`.
This allows a compact syntax for initialization, with less duplication:
```rust
#[derive(Debug)]
struct Person {
name: String,
age: u8,
}
fn main() {
let name = String::from("Peter");
let age = 27;
// Using full syntax:
let peter = Person { name: name, age: age };
let name = String::from("Portia");
let age = 27;
// Using field init shorthand:
let portia = Person { name, age };
println!("{:?}", portia);
}
```
## Returning from loops
One of the uses of a `loop` is to retry an operation you know can fail, such as
checking if a thread completed its job. However, you might need to pass the
result of that operation to the rest of your code. If you add it to the `break`
expression you use to stop the loop, it will be returned by the broken loop:
```rust
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
assert_eq!(result, 20);
}
```
## Nested groups in `use` declarations
If you have a complex module tree with many different submodules and you need
to import a few items from each one, it might be useful to group all the
imports in the same declaration to keep your code clean and avoid repeating the
base modules name.
The `use` declaration supports nesting to help you in those cases, both with
simple imports and glob ones. For example this snippets imports `bar`, `Foo`,
all the items in `baz` and `Bar`:
```rust
# #![allow(unused_imports, dead_code)]
#
# mod foo {
# pub mod bar {
# pub type Foo = ();
# }
# pub mod baz {
# pub mod quux {
# pub type Bar = ();
# }
# }
# }
#
use foo::{
bar::{self, Foo},
baz::{*, quux::Bar},
};
#
# fn main() {}
```
## Inclusive ranges
Previously, when a range (`..` or `...`) was used as an expression, it had to be
`..`, which is exclusive of the upper bound, while patterns had to use `...`,
which is inclusive of the upper bound. Now, `..=` is accepted as syntax for
inclusive ranges in both expression and range context:
```rust
fn main() {
for i in 0 ..= 10 {
match i {
0 ..= 5 => println!("{}: low", i),
6 ..= 10 => println!("{}: high", i),
_ => println!("{}: out of range", i),
}
}
}
```
The `...` syntax is still accepted in matches, but it is not accepted in
expressions. `..=` should be preferred.
## 128-bit integers
Rust 1.26.0 added 128-bit integer primitives:
- `u128`: A 128-bit unsigned integer with range [0, 2^128 - 1]
- `i128`: A 128-bit signed integer with range [-(2^127), 2^127 - 1]
These primitives are implemented efficiently via LLVM support. They are
available even on platforms that dont natively support 128-bit integers and
can be used like the other integer types.
These primitives can be very useful for algorithms that need to use very large
integers efficiently, such as certain cryptographic algorithms.

View File

@ -0,0 +1,204 @@
# Appendix G - How Rust is Made and “Nightly Rust”
This appendix is about how Rust is made and how that affects you as a Rust
developer. We mentioned that the output in this book was generated by stable
Rust 1.21.0, but any examples that compile should continue to compile in any
stable version of Rust greater than that. This section is to explain how we
ensure this is true!
### Stability Without Stagnation
As a language, Rust cares a *lot* about the stability of your code. We want
Rust to be a rock-solid foundation you can build on, and if things were
constantly changing, that would be impossible. At the same time, if we cant
experiment with new features, we may not find out important flaws until after
their release, when we can no longer change things.
Our solution to this problem is what we call “stability without stagnation”,
and our guiding principle is this: you should never have to fear upgrading to a
new version of stable Rust. Each upgrade should be painless, but should also
bring you new features, fewer bugs, and faster compile times.
### Choo, Choo! Release Channels and Riding the Trains
Rust development operates on a *train schedule*. That is, all development is
done on the `master` branch of the Rust repository. Releases follow a software
release train model, which has been used by Cisco IOS and other software
projects. There are three *release channels* for Rust:
* Nightly
* Beta
* Stable
Most Rust developers primarily use the stable channel, but those who want to
try out experimental new features may use nightly or beta.
Heres an example of how the development and release process works: lets
assume that the Rust team is working on the release of Rust 1.5. That release
happened in December of 2015, but it will provide us with realistic version
numbers. A new feature is added to Rust: a new commit lands on the `master`
branch. Each night, a new nightly version of Rust is produced. Every day is a
release day, and these releases are created by our release infrastructure
automatically. So as time passes, our releases look like this, once a night:
```text
nightly: * - - * - - *
```
Every six weeks, its time to prepare a new release! The `beta` branch of the
Rust repository branches off from the `master` branch used by nightly. Now,
there are two releases:
```text
nightly: * - - * - - *
|
beta: *
```
Most Rust users do not use beta releases actively, but test against beta in
their CI system to help Rust discover possible regressions. In the meantime,
theres still a nightly release every night:
```text
nightly: * - - * - - * - - * - - *
|
beta: *
```
Lets say a regression is found. Good thing we had some time to test the beta
release before the regression snuck into a stable release! The fix is applied
to `master`, so that nightly is fixed, and then the fix is backported to the
`beta` branch, and a new release of beta is produced:
```text
nightly: * - - * - - * - - * - - * - - *
|
beta: * - - - - - - - - *
```
Six weeks after the first beta was created, its time for a stable release! The
`stable` branch is produced from the `beta` branch:
```text
nightly: * - - * - - * - - * - - * - - * - * - *
|
beta: * - - - - - - - - *
|
stable: *
```
Hooray! Rust 1.5 is done! However, weve forgotten one thing: because the six
weeks have gone by, we also need a new beta of the *next* version of Rust, 1.6.
So after `stable` branches off of `beta`, the next version of `beta` branches
off of `nightly` again:
```text
nightly: * - - * - - * - - * - - * - - * - * - *
| |
beta: * - - - - - - - - * *
|
stable: *
```
This is called the “train model” because every six weeks, a release “leaves the
station”, but still has to take a journey through the beta channel before it
arrives as a stable release.
Rust releases every six weeks, like clockwork. If you know the date of one Rust
release, you can know the date of the next one: its six weeks later. A nice
aspect of having releases scheduled every six weeks is that the next train is
coming soon. If a feature happens to miss a particular release, theres no need
to worry: another one is happening in a short time! This helps reduce pressure
to sneak possibly unpolished features in close to the release deadline.
Thanks to this process, you can always check out the next build of Rust and
verify for yourself that its easy to upgrade to: if a beta release doesnt
work as expected, you can report it to the team and get it fixed before the
next stable release happens! Breakage in a beta release is relatively rare, but
`rustc` is still a piece of software, and bugs do exist.
### Unstable Features
Theres one more catch with this release model: unstable features. Rust uses a
technique called “feature flags” to determine what features are enabled in a
given release. If a new feature is under active development, it lands on
`master`, and therefore, in nightly, but behind a *feature flag*. If you, as a
user, wish to try out the work-in-progress feature, you can, but you must be
using a nightly release of Rust and annotate your source code with the
appropriate flag to opt in.
If youre using a beta or stable release of Rust, you cant use any feature
flags. This is the key that allows us to get practical use with new features
before we declare them stable forever. Those who wish to opt into the bleeding
edge can do so, and those who want a rock-solid experience can stick with
stable and know that their code wont break. Stability without stagnation.
This book only contains information about stable features, as in-progress
features are still changing, and surely theyll be different between when this
book was written and when they get enabled in stable builds. You can find
documentation for nightly-only features online.
### Rustup and the Role of Rust Nightly
Rustup makes it easy to change between different release channels of Rust, on a
global or per-project basis. By default, youll have stable Rust installed. To
install nightly, for example:
```text
$ rustup install nightly
```
You can see all of the *toolchains* (releases of Rust and associated
components) you have installed with `rustup` as well. Heres an example on one
of your authors computers:
```powershell
> rustup toolchain list
stable-x86_64-pc-windows-msvc (default)
beta-x86_64-pc-windows-msvc
nightly-x86_64-pc-windows-msvc
```
As you can see, the stable toolchain is the default. Most Rust users use stable
most of the time. You might want to use stable most of the time, but use
nightly on a specific project, because you care about a cutting-edge feature.
To do so, you can use `rustup override` in that projects directory to set the
nightly toolchain as the one `rustup` should use when youre in that directory:
```text
$ cd ~/projects/needs-nightly
$ rustup override set nightly
```
Now, every time you call `rustc` or `cargo` inside of
*~/projects/needs-nightly*, `rustup` will make sure that you are using nightly
Rust, rather than your default of stable Rust. This comes in handy when you
have a lot of Rust projects!
### The RFC Process and Teams
So how do you learn about these new features? Rusts development model follows
a *Request For Comments (RFC) process*. If youd like an improvement in Rust,
you can write up a proposal, called an RFC.
Anyone can write RFCs to improve Rust, and the proposals are reviewed and
discussed by the Rust team, which is comprised of many topic subteams. Theres
a full list of the teams [on Rusts
website](https://www.rust-lang.org/en-US/team.html), which includes teams for
each area of the project: language design, compiler implementation,
infrastructure, documentation, and more. The appropriate team reads the
proposal and the comments, writes some comments of their own, and eventually,
theres consensus to accept or reject the feature.
If the feature is accepted, an issue is opened on the Rust repository, and
someone can implement it. The person who implements it very well may not be the
person who proposed the feature in the first place! When the implementation is
ready, it lands on the `master` branch behind a feature gate, as we discussed
in the “Unstable Features” section.
After some time, once Rust developers who use nightly releases have been able
to try out the new feature, team members will discuss the feature, how its
worked out on nightly, and decide if it should make it into stable Rust or not.
If the decision is to move forward, the feature gate is removed, and the
feature is now considered stable! It rides the trains into a new stable release
of Rust.

View File

@ -0,0 +1,173 @@
# Introduction
Welcome to *The Rust Programming Language*, an introductory book about Rust.
The Rust programming language helps you write faster, more reliable software.
High-level ergonomics and low-level control are often at odds in programming
language design; Rust challenges that conflict. Through balancing powerful
technical capacity and a great developer experience, Rust gives you the option
to control low-level details (such as memory usage) without all the hassle
traditionally associated with such control.
## Who Rust Is For
Rust is ideal for many people for a variety of reasons. Lets look at a few of
the most important groups.
### Teams of Developers
Rust is proving to be a productive tool for collaborating among large teams of
developers with varying levels of systems programming knowledge. Low-level code
is prone to a variety of subtle bugs, which in most other languages can only be
caught through extensive testing and careful code review by experienced
developers. In Rust, the compiler plays a gatekeeper role by refusing to
compile code with these elusive bugs, including concurrency bugs. By working
alongside the compiler, the team can spend more time focusing on the programs
logic rather than chasing down bugs.
Rust also brings contemporary developer tools to the systems programming world:
* Cargo, the included dependency manager and build tool, makes adding,
compiling, and managing dependencies painless and consistent across the Rust
ecosystem.
* Rustfmt ensures a consistent coding style across developers.
* The Rust Language Server powers Integrated Development Environment (IDE)
integration for code completion and inline error messages.
By using these and other tools in the Rust ecosystem, developers can be
productive while writing systems-level code.
### Students
Rust is for students and those who are interested in learning about systems
concepts. Using Rust, many people have learned about topics like operating
systems development. The community is very welcoming and happy to answer
student questions. Through efforts such as this book, the Rust teams want to
make systems concepts more accessible to more people, especially those new to
programming.
### Companies
Hundreds of companies, large and small, use Rust in production for a variety of
tasks. Those tasks include command line tools, web services, DevOps tooling,
embedded devices, audio and video analysis and transcoding, cryptocurrencies,
bioinformatics, search engines, internet of things applications, machine
learning, and even major parts of the Firefox web browser.
### Open Source Developers
Rust is for people who want to build the Rust programming language, community,
developer tools, and libraries. Wed love to have you contribute to the Rust
language.
### People Who Value Speed and Stability
Rust is for people who crave speed and stability in a language. By speed, we
mean the speed of the programs that you can create with Rust and the speed at
which Rust lets you write them. The Rust compilers checks ensure stability
through feature additions and refactoring as opposed to brittle legacy code in
languages without these checks that developers are afraid to modify. By
striving for zero-cost abstractions, higher-level features that compile to
lower-level code as fast as code written manually, Rust endeavors to make safe
code be fast code as well.
Although weve not provided a complete list of everyone the Rust language hopes
to support, those we have mentioned are some of the biggest stakeholders.
Overall, Rusts greatest ambition is to eliminate the dichotomy of the
trade-offs that programmers have accepted for decades: safety *and*
productivity, speed *and* ergonomics. Give Rust a try, and see if its choices
work for you.
## Who This Book Is For
This book assumes that youve written code in another programming language but
doesnt make any assumptions about which one. Weve tried to make the material
broadly accessible to those from a wide variety of programming backgrounds. We
dont spend a lot of time talking about what programming *is* or how to think
about it. If youre entirely new to programming, you would be better served by
reading a book that specifically provides an introduction to programming.
## How to Use This Book
In general, this book assumes that youre reading it in sequence from front to
back. Later chapters build on concepts in earlier chapters, and earlier
chapters might not delve into details on a topic; we typically revisit the
topic in a later chapter.
Youll find two kinds of chapters in this book: concept chapters and project
chapters. In concept chapters, youll learn about an aspect of Rust. In project
chapters, well build small programs together, applying what youve learned so
far. Chapters 2, 12, and 20 are project chapters; the rest are concept chapters.
Additionally, Chapter 2 is a hands-on introduction to the Rust language. Well
cover concepts at a high level, and later chapters will provide additional
detail. If you want to get your hands dirty right away, Chapter 2 is the one
for that. At first, you might even want to skip Chapter 3, which covers Rust
features similar to other programming language features, and head straight to
Chapter 4 to learn about Rusts ownership system. However, if youre a
particularly meticulous learner who prefers to learn every detail before moving
onto the next, you might want to skip Chapter 2 and go straight to Chapter 3,
returning to Chapter 2 when youd like to work on a project applying those
details.
Chapter 5 discusses structs and methods, and Chapter 6 covers enums, `match`
expressions, and the `if let` control flow construct. Youll use structs and
enums to make custom types in Rust.
In Chapter 7, youll learn about Rusts module system and about privacy rules
for organizing your code and its public Application Programming Interface
(API). Chapter 8 discusses some common collection data structures that the
standard library provides, such as vectors, strings, and hash maps. Chapter 9
explores Rusts error handling philosophy and techniques.
Chapter 10 digs into generics, traits, and lifetimes, which give you the power
to define code that applies to multiple types. Chapter 11 is all about testing,
which is still necessary even with Rusts safety guarantees to ensure your
programs logic is correct. In Chapter 12, well build our own implementation
of a subset of functionality from the `grep` command line tool that searches
for text within files. For this, well use many of the concepts we discussed in
the previous chapters.
Chapter 13 explores closures and iterators: features of Rust that come from
functional programming languages. In Chapter 14, well examine Cargo in more
depth and talk about best practices for sharing your libraries with others.
Chapter 15 discusses smart pointers that the standard library provides and the
traits that enable their functionality.
In Chapter 16, well walk through different models of concurrent programming
and talk about how Rust helps you to program in multiple threads fearlessly.
Chapter 17 looks at how Rust idioms compare to object oriented programming
principles you might be familiar with.
Chapter 18 is a reference on patterns and pattern matching, which are powerful
ways of expressing ideas throughout Rust programs. Chapter 19 contains a
smorgasbord of advanced topics of interest, including unsafe Rust and more
about lifetimes, traits, types, functions, and closures.
In Chapter 20, well complete a project in which well implement a low-level
multithreaded web server!
Finally, some appendixes contain useful information about the language in a
more reference-like format. Appendix A covers Rusts keywords. Appendix B
covers Rusts operators and symbols. Appendix C covers derivable traits
provided by the standard library. Appendix D covers macros.
There is no wrong way to read this book: if you want to skip ahead, go for it!
You might have to jump back to earlier chapters if you experience any
confusion. But do whatever works for you.
An important part of the process of learning Rust is learning how to read the
error messages the compiler displays: these will guide you toward working code.
As such, well provide many examples of code that dont compile along with the
error message the compiler will show you in each situation. Know that if you
enter and run a random example, it may not compile! Make sure you read the
surrounding text to see whether the example youre trying to run is meant to
error. In most situations, well lead you to the correct version of any code
that doesnt compile.
## Source Code
The source files from which this book is generated can be found on
[GitHub][book].
[book]: https://github.com/rust-lang/book/tree/master/2018-edition/src

View File

@ -0,0 +1,12 @@
# Getting Started
<!-- If you want to use this paragraph in the Introduction, can you replace it
with some other introductory text for the chapter here? Maybe just lay out
what's in this chapter so they know it's important not to skip it. -->
<!-- Yep, done! /Carol -->
Lets get your Rust journey started! In this chapter, well discuss:
- Installing Rust on Linux, Mac, or Windows
- Writing a program that prints “Hello, world!”
- Using `cargo`, Rusts package manager and build system

View File

@ -0,0 +1,154 @@
## Installation
The first step to using Rust is to install it. Well download Rust through
`rustup`, a command-line tool for managing Rust versions and associated tools.
For this youll need an internet connection.
The following steps will install the latest stable version of the Rust
compiler. The examples and output shown in this book all use stable Rust
1.21.0. Rusts stability guarantees ensure that all of the examples in the book
that compile will continue to compile with newer versions of Rust. The output
may differ slightly between versions, as error messages and warnings are often
improved. In other words, any newer, stable version of Rust you will install
with these steps should work as expected with the content of this book.
<!-- PROD: Start Box -->
> #### Command Line Notation
>
> In this chapter and throughout the book well be showing some commands used
> in the terminal. Lines that should be entered in a terminal all start with
> `$`. You dont need to type in the `$` character, it is simply there to
> indicate the start of each command. Many tutorials use this convention: `$`
> for commands run as a regular user, and `#` for commands you should be
> running as an administrator. Lines that dont start with `$` are typically
> showing the output of the previous command. Additionally, PowerShell specific
> examples will use `>` rather than `$`.
<!-- PROD: End box -->
### Installing Rustup on Linux or Mac
If youre on Linux or a Mac, open a terminal and enter the following command:
```text
$ curl https://sh.rustup.rs -sSf | sh
```
This will download a script and start the installation of the `rustup` tool,
which installs the latest stable version of Rust. You may be prompted for your
password. If it all goes well, youll see this appear:
```text
Rust is installed now. Great!
```
Of course, if you distrust using `curl URL | sh` to install software, you can
download, inspect, and run the script however you like.
The installation script automatically adds Rust to your system PATH after your
next login. If you want to start using Rust right away instead of restarting
your terminal, run the following command in your shell to add Rust to your
system PATH manually:
<!-- what does this command do? Do you mean instead of logging out and logging
in, enter the following? -->
<!-- It runs a script that adds Rust to your system PATH manually. I've
clarified that yes, this is instead of logging out and back in to your
terminal. /Carol -->
```text
$ source $HOME/.cargo/env
```
Alternatively, you can add the following line to your `~/.bash_profile`:
```text
$ export PATH="$HOME/.cargo/bin:$PATH"
```
Finally, youll need a linker of some kind. Its likely you already have one
installed, but if you try to compile a Rust program and get errors telling you
that a linker could not be executed, youll need to install one. You can
install a C compiler, as that will usually come with the correct linker. Check
your platforms documentation for how to install a C compiler. Some common Rust
packages depend on C code and will need a C compiler too, so it may be worth
installing one now regardless.
### Installing Rustup on Windows
On Windows, go to [https://www.rust-lang.org/en-US/install.html][install] and
follow the instructions for installing Rust. At some point in the installation
youll receive a message telling you youll also need the C++ build tools for
Visual Studio 2013 or later. The easiest way to acquire the build tools is to
install [Build Tools for Visual Studio 2017][visualstudio], found in the Other
Tools and Frameworks section.
[install]: https://www.rust-lang.org/en-US/install.html
[visualstudio]: https://www.visualstudio.com/downloads/
The rest of this book will use commands that work in both `cmd.exe` and
PowerShell. If there are specific differences, well explain which to use.
### Custom Installations Without Rustup
If you have reasons for preferring not to use `rustup`, please see [the Rust
installation page](https://www.rust-lang.org/install.html) for other options.
### Updating and Uninstalling
Once you have Rust installed via `rustup`, updating to the latest version is
easy. From your shell, run the update script:
```text
$ rustup update
```
To uninstall Rust and `rustup`, from your shell, run the uninstall script:
```text
$ rustup self uninstall
```
### Troubleshooting
To check whether you have Rust installed correctly, open up a shell and enter:
```text
$ rustc --version
```
You should see the version number, commit hash, and commit date for the latest
stable version at the time you install in the following format:
```text
rustc x.y.z (abcabcabc yyyy-mm-dd)
```
If you see this, Rust has been installed successfully! Congrats!
If you dont and youre on Windows, check that Rust is in your `%PATH%` system
variable.
If thats all correct and Rust still isnt working, there are a number of
places you can get help. The easiest is [the #rust IRC channel on
irc.mozilla.org][irc]<!-- ignore -->, which you can access through
[Mibbit][mibbit]. Go to that address, and youll be chatting with other
Rustaceans (a silly nickname we call ourselves) who can help you out. Other
great resources include [the Users forum][users] and [Stack
Overflow][stackoverflow].
[irc]: irc://irc.mozilla.org/#rust
[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
[users]: https://users.rust-lang.org/
[stackoverflow]: http://stackoverflow.com/questions/tagged/rust
### Local Documentation
The installer also includes a copy of the documentation locally, so you can
read it offline. Run `rustup doc` to open the local documentation in your
browser.
Any time theres a type or function provided by the standard library and youre
not sure what it does or how to use it, use the API (Application Programming
Interface) documentation to find out!

View File

@ -0,0 +1,218 @@
## Hello, World!
Now that you have Rust installed, lets write your first Rust program. Its
traditional when learning a new language to write a little program to print the
text “Hello, world!” to the screen, so well do the same here!
> Note: This book assumes basic familiarity with the command line. Rust itself
> makes no specific demands about your editing, tooling, or where your code
> lives, so if you prefer an IDE (Integrated Development Environment) to the
> command line, feel free to use your favorite IDE. Many IDEs now have some
> degree of Rust support; check the IDEs documentation for details. Enabling
> great IDE support has been a recent focus of the Rust team, and progress
> has been made rapidly on that front!
### Creating a Project Directory
First, make a directory to put your Rust code in. Rust doesnt care where your
code lives, but for the exercises and projects in this book, wed suggest
making a *projects* directory in your home directory and keeping all your
projects there.
Open a terminal and enter the following commands to make a *projects* directory
and, inside that, a directory for this “Hello, world!” project:
Linux and Mac:
```text
$ mkdir ~/projects
$ cd ~/projects
$ mkdir hello_world
$ cd hello_world
```
Windows CMD:
```cmd
> mkdir "%USERPROFILE%\projects"
> cd /d "%USERPROFILE%\projects"
> mkdir hello_world
> cd hello_world
```
Windows PowerShell:
```powershell
> mkdir $env:USERPROFILE\projects
> cd $env:USERPROFILE\projects
> mkdir hello_world
> cd hello_world
```
### Writing and Running a Rust Program
Next, make a new source file and call it *main.rs*---Rust files always end with
the *.rs* extension. If youre using more than one word in your filename, use
an underscore to separate them. For example, youd use *hello_world.rs* rather
than *helloworld.rs*.
Now open the *main.rs* file you just created, and enter the code shown in
Listing 1-1:
<span class="filename">Filename: main.rs</span>
```rust
fn main() {
println!("Hello, world!");
}
```
<span class="caption">Listing 1-1: A program that prints “Hello, world!”</span>
Save the file, and go back to your terminal window. On Linux or macOS, enter
the following commands to compile and run the file:
```text
$ rustc main.rs
$ ./main
Hello, world!
```
On Windows, use `.\main.exe` instead of `./main`.
```powershell
> rustc main.rs
> .\main.exe
Hello, world!
```
Regardless of your operating system, you should see the string `Hello, world!`
print to the terminal. If you dont see this output, see the “Troubleshooting”
section earlier for ways to get help.
If you did see `Hello, world!` printed, then congratulations! Youve officially
written a Rust program. That makes you a Rust programmer! Welcome!
<!-- Any quick words of advice for if they didn't? (Disclosure: I tried
following this using Bash on windows and couldn't get it working) -->
<!-- Added a pointer to the previous troubleshooting section which also applies
here /Carol -->
### Anatomy of a Rust Program
Now, lets go over what just happened in your “Hello, world!” program in
detail. Heres the first piece of the puzzle:
```rust
fn main() {
}
```
These lines define a *function* in Rust. The `main` function is special: it is
always the first code that is run for every executable Rust program. The first
line declares a function named `main` that has no parameters and returns
nothing. If there were parameters, their names would go inside the parentheses,
`(` and `)`.
Also note that the function body is wrapped in curly brackets, `{` and `}`.
Rust requires these around all function bodies. Its considered good style to
place the opening curly bracket on the same line as the function declaration,
with one space in between.
> At the time of writing, an automatic formatter, `rustfmt`, is under
> development. If youd like to stick to a standard style across Rust projects,
> `rustfmt` is a tool that will format your code in a particular style. The
> plan is to eventually include it with the standard Rust distribution, like
> `rustc`, so depending on when you read this book, you may have it already
> installed! Check the online documentation for more details.
Inside the `main` function, we have this code:
```rust
println!("Hello, world!");
```
This line does all of the work in this little program: it prints text to the
screen. There are a number of details to notice here. The first is that Rust
style is to indent with four spaces, not a tab.
The second important detail is the `println!` call. This code is calling a Rust
*macro*. If it were calling a function instead, it would be entered as
`println` (without the `!`). Well discuss Rust macros in more detail in
Appendix D, but for now you just need to know that when you see a `!` that
means that youre calling a macro instead of a normal function.
<!-- I might suggest just cutting this next macro section -- for the sake of
the intro, we don't really need this info, and I feel like this first exercise
should be short and sweet and simple -->
<!-- I'm ok with cutting this; it's a fairly common question that some folks
have at this point, but I'm ok with those people having to do some research
online if they're curious /Carol -->
Next comes`"Hello, world!"` which is a *string*. We pass this string as an
argument to `println!` and the total effect is that the string is printed to
the screen. Easy enough!
We end the line with a semicolon `;`, which indicates that this expression is
over, and the next one is ready to begin. Most lines of Rust code end with a
`;`.
### Compiling and Running Are Separate Steps
Youve just seen how to run a newly created program, so now lets break that
process down and examine each step.
Before running a Rust program, you have to compile it using the Rust compiler
by entering the `rustc` command and passing it the name of your source file,
like this:
```text
$ rustc main.rs
```
If you come from a C or C++ background, youll notice that this is similar to
`gcc` or `clang`. After compiling successfully, Rust outputs a binary
executable.
On Linux, Mac, and PowerShell on Windows, you can see the executable by
entering the `ls` command in your shell as follows:
```text
$ ls
main main.rs
```
With CMD on Windows, youd enter:
```cmd
> dir /B %= the /B option says to only show the file names =%
main.exe
main.pdb
main.rs
```
This shows we have two files: the source code, with the *.rs* extension, and
the executable (*main.exe* on Windows, *main* everywhere else). All thats left
to do from here is run the *main* or *main.exe* file, like this:
```text
$ ./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 the executable to someone else, and they can run it even without having
Rust installed. If you give someone a `.rb`, `.py`, or `.js` file, on the other
hand, they need to have a Ruby, Python, or JavaScript implementation installed
(respectively), but you only need one command to both compile and run your
program. Everything is a tradeoff in language design.
Just compiling with `rustc` is fine for simple programs, but as your project
grows, youll want to be able to manage all of the options and make it easy to
share your code. Next, well introduce you to a tool called Cargo, which will
help you write real-world Rust programs.

View File

@ -0,0 +1,266 @@
## Hello, Cargo!
Cargo is Rusts build system and package manager. Most Rustaceans will use this
tool to manage their Rust projects because Cargo takes care of a lot of tasks
for you, such as building your code, downloading the libraries your code
depends on, and building those libraries. (We call libraries your code needs
*dependencies*.)
The simplest Rust programs, like the one weve written so far, dont have any
dependencies, so if we had built the Hello World project with Cargo, it would
only be using the part of Cargo that takes care of building your code. As you
write more complex Rust programs, youll want to add dependencies, and if you
start the project off using Cargo, that will be a lot easier to do.
As the vast majority of Rust projects use Cargo, the rest of this book will
assume that youre using Cargo too. Cargo comes installed with Rust itself, if
you used the official installers as covered in the “Installation” section. If
you installed Rust through some other means, you can check if you have Cargo
installed by entering the following into your terminal:
```text
$ cargo --version
```
If you see a version number, great! If you see an error like `command not
found`, then you should look at the documentation for your method of
installation to determine how to install Cargo separately.
### Creating a Project with Cargo
Lets create a new project using Cargo and look at how it differs from our
original Hello World project. Navigate back to your *projects* directory (or
whichever location you decided to place your code) and then on any operating
system run:
```text
$ cargo new hello_cargo --bin
$ cd hello_cargo
```
<!-- Below -- so we always have to start a cargo project with the --bin option
if we want it to be something we can execute and not just a library, is that
right? It might be worth laying that out -->
<!-- As of Rust 1.21.0 (the version we're using for the book), yes, you must
always specify `--bin`. In a version of Rust in the near future (1.25 or 1.26),
binary crates will become the default kind of crate that `cargo new` makes, so
you won't have to specify `--bin` (but you can if you want and the behavior
will be the same). We'd rather not go into any more detail than we have here
because of this change; I think "The `--bin` argument to passed to `cargo new`
makes an executable application (often just called a *binary*), as opposed to a
library." lays this out enough. /Carol -->
This creates a new binary executable called `hello_cargo`. The `--bin` argument
to passed to `cargo new` makes an executable application (often just called a
*binary*), as opposed to a library. Weve given `hello_cargo` as the name for
our project, and Cargo creates its files in a directory of the same name.
Go into the *hello_cargo* directory and list the files, and you should see that
Cargo has generated two files and one directory for us: a *Cargo.toml* and a
*src* directory with a *main.rs* file inside. It has also initialized a new git
repository, along with a *.gitignore* file.
> Note: Git is a common version control system. You can change `cargo new` to
> use a different version control system, or no version control system, by
> using the `--vcs` flag. Run `cargo new --help` to see the available options.
Open up *Cargo.toml* in your text editor of choice. It should look similar to
the code in Listing 1-2:
<span class="filename">Filename: Cargo.toml</span>
```toml
[package]
name = "hello_cargo"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
[dependencies]
```
<span class="caption">Listing 1-2: Contents of *Cargo.toml* generated by `cargo
new`</span>
This file is in the [*TOML*][toml]<!-- ignore --> (Toms Obvious, Minimal
Language) format, which is what Cargo uses as its configuration format.
[toml]: https://github.com/toml-lang/toml
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, well add other sections.
The next three lines set the configuration information Cargo needs in order to
know that it should compile your program: the name, the version, and who wrote
it. Cargo gets your name and email information from your environment, so if
thats 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
of your projects dependencies. In Rust, packages of code are referred to as
*crates*. We wont need any other crates for this project, but we will in the
first project in Chapter 2, so well use this dependencies section then.
Now open up *src/main.rs* and take a look:
<span class="filename">Filename: src/main.rs</span>
```rust
fn main() {
println!("Hello, world!");
}
```
Cargo has generated a “Hello World!” for you, just like the one we wrote in
Listing 1-1! So far, the differences between our previous project and the
project generated by Cargo are that with Cargo our code goes in the *src*
directory, and we have a *Cargo.toml* configuration file in the top directory.
Cargo expects your source files to live inside the *src* directory; the
top-level project directory is just for READMEs, license information,
configuration files, and anything else not related to your code. In this way,
using Cargo helps you keep your projects nice and tidy. Theres a place for
everything, and everything is in its place.
If you started a project that doesnt use Cargo, as we did with our project in
the *hello_world* directory, you can convert it to a project that does use
Cargo by moving the project code into the *src* directory and creating an
appropriate *Cargo.toml*.
### Building and Running a Cargo Project
Now lets look at whats different about building and running your Hello World
program through Cargo! From your project directory, build your project by
entering the following commands:
```text
$ cargo build
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs
```
This creates an executable file in *target/debug/hello_cargo* (or
*target\\debug\\hello_cargo.exe* on Windows), which you can run with this
command:
```text
$ ./target/debug/hello_cargo # or .\target\debug\hello_cargo.exe on Windows
Hello, world!
```
Bam! If all goes well, `Hello, world!` should print to the terminal once more.
Running `cargo build` for the first time also causes Cargo to create a new file
at the top level called *Cargo.lock*, which is used to keep track of the exact
versions of dependencies in your project. This project doesnt have
dependencies, so the file is a bit sparse. You wont ever need to touch this
file yourself; Cargo will manage its contents for you.
We just built a project with `cargo build` and ran it with
`./target/debug/hello_cargo`, but we can also use `cargo run` to compile and
then run all in one go:
```text
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/hello_cargo`
Hello, world!
```
Notice that this time, we didnt see the output telling us that Cargo was
compiling `hello_cargo`. Cargo figured out that the files havent changed, so
it just ran the binary. If you had modified your source code, Cargo would have
rebuilt the project before running it, and you would have seen output like this:
```text
$ cargo run
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.33 secs
Running `target/debug/hello_cargo`
Hello, world!
```
Finally, theres `cargo check`. This command will quickly check your code to
make sure that it compiles, but not bother producing an executable:
```text
$ cargo check
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
```
Why would you not want an executable? `cargo check` is often much faster than
`cargo build`, because it skips the entire step of producing the executable. If
youre checking your work throughout the process of writing the code, using
`cargo check` will speed things up! As such, many Rustaceans run `cargo check`
periodically as they write their program to make sure that it compiles, and
then run `cargo build` once theyre ready to give it a spin themselves.
So to recap, using Cargo:
- We can build a project using `cargo build` or `cargo check`
- We can build and run the project in one step with `cargo run`
- Instead of the result of the build being put in the same directory as our
code, Cargo will put it in the *target/debug* directory.
A final advantage of using Cargo is that the commands are the same no matter
what operating system youre 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 increases the compilation
time of your program. This is why there are two different profiles: one for
development when you want to be able to rebuild quickly and often, and one for
building the final program youll give to a user that wont be rebuilt
repeatedly and that will run as fast as possible. If youre 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 doesnt 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, its much easier to let Cargo coordinate
the build.
Even though the `hello_cargo` project is simple, it now uses much of the real
tooling youll use for the rest of your Rust career. In fact, to work on any
existing projects you can use the following commands to check out the code
using Git, change into the project directory, and build:
```text
$ git clone someurl.com/someproject
$ cd someproject
$ cargo build
```
If you want to look at Cargo in more detail, check out [its documentation].
[its documentation]: https://doc.rust-lang.org/cargo/
<!--Below -- I`m not sure this is the place for this conversation, it seems too
deep into the weeds for the "getting started" chapter. I know we discussed
Nightly Rust as an appendix previously, but honestly I think this is more
suited somewhere online, perhaps in the extended docs. I like the idea of
finishing the chapter here, on this practical note, and I think at this point
readers will want to get stuck in anyway and may skip this and never come back
because it's buried at the end of a chapter that's not really related to it. If
it's online somewhere separate they can come to it when they're ready. What do
you think?-->
<!-- Ok, I can see that. /Carol -->
## Summary
Youre already off to a great start on your Rust journey! In this chapter,
youve:
* Installed the latest stable version of Rust
* Written a “Hello, world!” program using both `rustc` directly and using
the conventions of `cargo`
This is a great time to build a more substantial program, to get used to
reading and writing Rust code. In the next chapter, well build a guessing game
program. If youd rather start by learning about how common programming
concepts work in Rust, see Chapter 3.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
# 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 well discuss them in the context of Rust and explain the conventions
around using these concepts.
Specifically, youll 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.
> ### Keywords
>
> The Rust language has a set of *keywords* that are reserved for use by
> the language only, much as in other languages. Keep in mind that you cannot
> use these words as names of variables or functions. Most of the keywords have
> special meanings, and youll 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.

View File

@ -0,0 +1,228 @@
## Variables and Mutability
As mentioned in Chapter 2, by default variables are immutable. This is one of
many nudges Rust gives 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. Lets explore how and why Rust
encourages you to favor immutability and why sometimes you might want to opt
out.
When a variable is immutable, once a value is bound to a name, you cant change
that value. To illustrate this, lets 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 code that wont compile just yet:
<span class="filename">Filename: src/main.rs</span>
```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:
```text
error[E0384]: cannot assign twice to 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;
| ^^^^^ cannot assign twice to 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
isnt safely doing what you want it to do yet; they do *not* mean that youre
not a good programmer! Experienced Rustaceans still get compiler errors.
The error indicates that the cause of the error is that you `cannot assign twice
to immutable variable x`, because you tried to assign a second value to the
immutable `x` variable.
Its 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, its
possible that the first part of the code wont do what it was designed to do.
The cause of this kind of bug 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 you state that a value wont change,
it really wont change. That means that when youre reading and writing code,
you dont have to keep track of how and where a value might change. Your code
is thus easier to reason through.
But mutability can be very useful. Variables are immutable only by default; as
you did in Chapter 2, you can make them mutable by adding `mut` in front of the
variable name. In addition to allowing this value to change, `mut` conveys
intent to future readers of the code by indicating that other parts of the code
will be changing this variable value.
For example, lets change *src/main.rs* to the following:
<span class="filename">Filename: src/main.rs</span>
```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 the program now, we get this:
```text
$ cargo run
Compiling variables v0.1.0 (file:///projects/variables)
Finished dev [unoptimized + debuginfo] target(s) in 0.30 secs
Running `target/debug/variables`
The value of x is: 5
The value of x is: 6
```
Were allowed to change the value that `x` binds to from `5` to `6` when `mut`
is used. In some cases, youll want to make a variable mutable because it makes
the code more convenient to write than if it had only immutable variables.
There are multiple trade-offs to consider in addition to the prevention of
bugs. For example, in cases where youre 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 think through, so 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 values that are bound to a name and are not
allowed to change, but there are a few differences between constants and
variables.
First, you arent allowed to use `mut` with constants. Constants arent just
immutable by default—theyre always immutable.
You declare constants using the `const` keyword instead of the `let` keyword,
and the type of the value *must* be annotated. Were about to cover types and
type annotations in the next section, “Data Types,” so dont worry about the
details right now. Just know that you 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 be set only to a constant expression,
not the result of a function call or any other value that could only be
computed at runtime.
Heres an example of a constant declaration where the constants name is
`MAX_POINTS` and its value is set to 100,000. (Rusts constant naming
convention is to use all uppercase with underscores between words):
```rust
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 parts 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 you saw in the “Comparing the Guess to the Secret Number” section in Chapter
2, you can declare a new variable with the same name as a previous variable,
and the new variable shadows the previous variable. Rustaceans say that the
first variable is *shadowed* by the second, which means that the second
variables value is what appears when the variable is used. We can shadow a
variable by using the same variables name and repeating the use of the `let`
keyword as follows:
<span class="filename">Filename: src/main.rs</span>
```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`, multiplying the
previous value by `2` to give `x` a final value of `12`. When we run this
program, it will output the following:
```text
$ cargo run
Compiling variables v0.1.0 (file:///projects/variables)
Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
Running `target/debug/variables`
The value of x is: 12
```
Shadowing is different than marking a variable as `mut`, because well get a
compile-time error if we accidentally try to reassign to this variable without
using the `let` keyword. By using `let`, 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 were
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, such as `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, well get a compile-time error:
```rust,ignore
let mut spaces = " ";
spaces = spaces.len();
```
The error says were not allowed to mutate a variables type:
```text
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 weve explored how variables work, lets look at more data types they
can have.

View File

@ -0,0 +1,364 @@
## Data Types
Every value in Rust is of a certain *data type*, which tells Rust what kind of
data is being specified so it knows how to work with that data. Well look at
two data type subsets: scalar and compound.
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 the “Comparing the Guess to the Secret Number” section in
Chapter 2, we must add a type annotation, like this:
```rust
let guess: u32 = "42".parse().expect("Not a number!");
```
If we dont add the type annotation here, Rust will display the following
error, which means the compiler needs more information from us to know which
type we want to use:
```text
error[E0282]: type annotations needed
--> src/main.rs:2:9
|
2 | let guess = "42".parse().expect("Not a number!");
| ^^^^^
| |
| cannot infer type for `_`
| consider giving `guess` a type
```
Youll see different type annotations for other 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 may recognize
these from other programming languages. Lets jump into how they work in Rust.
#### Integer Types
An *integer* is a number without a fractional component. We used one integer
type in Chapter 2, the `u32` type. This type declaration indicates that the
value its associated with should be an unsigned integer (signed integer types
start with `i`, instead of `u`) 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, `i16`) can be used to declare the type of an integer
value.
<span class="caption">Table 3-1: Integer Types in Rust</span>
| 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* refer to whether its 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). Its like writing numbers on paper: when
the sign matters, a number is shown with a plus sign or a minus sign; however,
when its safe to assume the number is positive, its shown with no sign.
Signed numbers are stored using twos complement representation (if youre
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 -(2<sup>n - 1</sup>) to 2<sup>n -
1</sup> - 1 inclusive, where *n* is the number of bits that variant uses. So an
`i8` can store numbers from -(2<sup>7</sup>) to 2<sup>7</sup> - 1, which equals
-128 to 127. Unsigned variants can store numbers from 0 to 2<sup>n</sup> - 1,
so a `u8` can store numbers from 0 to 2<sup>8</sup> - 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 youre on a 64-bit architecture and 32 bits
if youre 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`.
<span class="caption">Table 3-2: Integer Literals in Rust</span>
| 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 youre unsure, Rusts
defaults are generally good choices, and integer types default to `i32`: this
type is generally the fastest, even on 64-bit systems. The primary situation in
which youd 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. Rusts floating-point types are `f32` and `f64`,
which are 32 bits and 64 bits in size, respectively. The default type is `f64`
because on modern CPUs its roughly the same speed as `f32` but is capable of
more precision.
Heres an example that shows floating-point numbers in action:
<span class="filename">Filename: src/main.rs</span>
```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 basic mathematical operations youd expect for all of the
number types: addition, subtraction, multiplication, division, and remainder.
The following code shows how youd use each one in a `let` statement:
<span class="filename">Filename: src/main.rs</span>
```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:
<span class="filename">Filename: src/main.rs</span>
```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`
expression. Well cover how `if` expressions work in Rust in the “Control Flow”
section.
#### The Character Type
So far weve worked only with numbers, but Rust supports letters too. Rusts
`char` type is the languages most primitive alphabetic type, and the following
code shows one way to use it. (Note that the `char` type is specified with
single quotes, as opposed to strings, which use double quotes.)
<span class="filename">Filename: src/main.rs</span>
```rust
fn main() {
let c = 'z';
let z = '';
let heart_eyed_cat = '😻';
}
```
Rusts `char` type represents a Unicode Scalar Value, which means it can
represent a lot more than just ASCII. Accented letters; Chinese, Japanese, and
Korean characters; emoji; and zero-width spaces are all valid `char` values in
Rust. Unicode Scalar Values range from `U+0000` to `U+D7FF` and `U+E000` to
`U+10FFFF` inclusive. However, a “character” isnt 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. Well discuss this topic in detail in “Strings” in Chapter 8.
### Compound Types
*Compound types* can group multiple values into one type. Rust has two
primitive compound types: tuples and arrays.
#### The Tuple Type
A tuple is a general way of grouping together some number of other values with
a variety of types into one compound type.
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 dont have to be the same. Weve added optional
type annotations in this example:
<span class="filename">Filename: src/main.rs</span>
```rust
fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
}
```
The variable `tup` binds to the entire tuple, because 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:
<span class="filename">Filename: src/main.rs</span>
```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 access a tuple
element directly by using a period (`.`) followed by the index of the value we
want to access. For example:
<span class="filename">Filename: src/main.rs</span>
```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.
#### The Array Type
Another way to have a collection of multiple values is with an *array*. Unlike
a tuple, every element of an array must have the same type. Arrays in Rust are
different from arrays in some other languages because arrays in Rust have a
fixed length: once declared, they cannot grow or shrink in size.
In Rust, the values going into an array are written as a comma-separated list
inside square brackets:
<span class="filename">Filename: src/main.rs</span>
```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. An array isnt
as flexible as the vector type, though. A vector is a similar collection type
provided by the standard library that *is* allowed to grow or shrink in size.
If youre 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. Its 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. You can access
elements of an array using indexing, like this:
<span class="filename">Filename: src/main.rs</span>
```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 you try to access an element of an array that is past the end
of the array? Say you change the example to the following code, which will
compile but exit with an error when it runs:
<span class="filename">Filename: src/main.rs</span>
```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:
```text
$ cargo run
Compiling arrays v0.1.0 (file:///projects/arrays)
Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
Running `target/debug/arrays`
thread '<main>' 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 didnt produce any errors, but the program resulted in a
*runtime* error and didnt exit successfully. When you attempt to access an
element using indexing, Rust will check that the index youve 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 Rusts 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 Rusts error handling.

View File

@ -0,0 +1,346 @@
## Functions
Functions are pervasive in Rust code. Youve already seen one of the most
important functions in the language: the `main` function, which is the entry
point of many programs. Youve 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.
Heres a program that contains an example function definition:
<span class="filename">Filename: src/main.rs</span>
```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 brackets tell the compiler where the
function body begins and ends.
We can call any function weve 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 doesnt care where you define your functions, only that theyre
defined somewhere.
Lets 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:
```text
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
Finished dev [unoptimized + debuginfo] target(s) in 0.28 secs
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 functions signature. When a function has parameters, you
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 functions 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:
<span class="filename">Filename: src/main.rs</span>
```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:
```text
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
Finished dev [unoptimized + debuginfo] target(s) in 1.21 secs
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 brackets were in the format
string.
In function signatures, you *must* declare the type of each parameter. This is
a deliberate decision in Rusts 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:
<span class="filename">Filename: src/main.rs</span>
```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 the values in both of its parameters. Note that
function parameters dont all need to be the same type, they just happen to be
in this example.
Lets try running this code. Replace the program currently in your *functions*
projects *src/main.rs* file with the preceding example and run it using `cargo
run`:
```text
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
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, weve only covered functions without an ending expression,
but you have seen an expression as part of statements. Because Rust is an
expression-based language, this is an important distinction to understand.
Other languages dont have the same distinctions, so lets look at what
statements and expressions are and how their differences affect the bodies of
functions.
### Statements and Expressions
Weve 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. Lets look at some examples.
Creating a variable and assigning a value to it with the `let` keyword is a
statement. In Listing 3-1, `let y = 6;` is a statement:
<span class="filename">Filename: src/main.rs</span>
```rust
fn main() {
let y = 6;
}
```
<span class="caption">Listing 3-1: A `main` function declaration containing one statement</span>
Function definitions are also statements; the entire preceding example is a
statement in itself.
Statements do not return values. Therefore, you cant assign a `let` statement
to another variable, as the following code tries to do; youll get an error:
<span class="filename">Filename: src/main.rs</span>
```rust,ignore
fn main() {
let x = (let y = 6);
}
```
When you run this program, the error youll get looks like this:
```text
$ 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 isnt anything for
`x` to bind to. This is different from what happens 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
youll 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-1, the `6` in the statement `let y = 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:
<span class="filename">Filename: src/main.rs</span>
```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 `x + 1` line without a semicolon at
the end, which is unlike most of the lines youve 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 dont 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. You can return early from a function by
using the `return` keyword and specifying a value, but most functions return
the last expression implicitly. Heres an example of a function that returns a
value:
<span class="filename">Filename: src/main.rs</span>
```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. Thats a perfectly valid function in
Rust. Note that the functions return type is specified, too, as `-> i32`. Try
running this code; the output should look like this:
```text
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
Finished dev [unoptimized + debuginfo] target(s) in 0.30 secs
Running `target/debug/functions`
The value of x is: 5
```
The `5` in `five` is the functions return value, which is why the return type
is `i32`. Lets examine this in more detail. There are two important bits:
first, the line `let x = five();` shows that were 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 its an expression whose value we want to return.
Lets look at another example:
<span class="filename">Filename: src/main.rs</span>
```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`. But if we place a
semicolon at the end of the line containing `x + 1`, changing it from an
expression to a statement, well get an error.
<span class="filename">Filename: src/main.rs</span>
```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:
```text
error[E0308]: mismatched types
--> src/main.rs:7:28
|
7 | fn plus_one(x: i32) -> i32 {
| ____________________________^
8 | | x + 1;
| | - help: consider removing this semicolon
9 | | }
| |_^ expected i32, found ()
|
= note: expected type `i32`
found type `()`
```
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 dont 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.

View File

@ -0,0 +1,47 @@
## 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.
Heres 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, youll need to include
`//` on each line, like this:
```rust
// So were doing something complicated here, long enough that we need
// multiple lines of comments to do it! Whew! Hopefully, this comment will
// explain whats going on.
```
Comments can also be placed at the end of lines containing code:
<span class="filename">Filename: src/main.rs</span>
```rust
fn main() {
let lucky_number = 7; // Im feeling lucky today.
}
```
But youll more often see them used in this format, with the comment on a
separate line above the code its annotating:
<span class="filename">Filename: src/main.rs</span>
```rust
fn main() {
// Im feeling lucky today.
let lucky_number = 7;
}
```
Rust also has another kind of comment, documentation comments, which well
discuss in Chapter 14.

View File

@ -0,0 +1,462 @@
## Control Flow
Deciding whether or not to run some code depending on if a condition is true
and 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 you to branch your code depending on conditions. You
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:
<span class="filename">Filename: src/main.rs</span>
```rust
fn main() {
let number = 3;
if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}
```
<!-- NEXT PARAGRAPH WRAPPED WEIRD INTENTIONALLY SEE #199 -->
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
brackets. 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 dont 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:
```text
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
Running `target/debug/branches`
condition was true
```
Lets 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:
```text
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
Running `target/debug/branches`
condition was false
```
Its also worth noting that the condition in this code *must* be a `bool`. If
the condition isnt a `bool`, well get an error. For example:
<span class="filename">Filename: src/main.rs</span>
```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:
```text
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. Unlike
languages such as Ruby and JavaScript, Rust will not automatically try to
convert non-Boolean types to a Boolean. 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:
<span class="filename">Filename: src/main.rs</span>
```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`.
#### Handling Multiple Conditions with `else if`
You can have multiple conditions by combining `if` and `else` in an `else if`
expression. For example:
<span class="filename">Filename: src/main.rs</span>
```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:
```text
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
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 dont 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.
Thats because Rust only executes the block for the first true condition, and
once it finds one, it doesnt 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, as in Listing 3-2:
<span class="filename">Filename: src/main.rs</span>
```rust
fn main() {
let condition = true;
let number = if condition {
5
} else {
6
};
println!("The value of number is: {}", number);
}
```
<span class="caption">Listing 3-2: Assigning the result of an `if` expression
to a variable</span>
The `number` variable will be bound to a value based on the outcome of the `if`
expression. Run this code to see what happens:
```text
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Finished dev [unoptimized + debuginfo] target(s) in 0.30 secs
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-2, the results of both the `if` arm and the `else`
arm were `i32` integers. If the types are mismatched, as in the following
example, well get an error:
<span class="filename">Filename: src/main.rs</span>
```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, well 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:
```text
error[E0308]: if and else have incompatible types
--> src/main.rs:4:18
|
4 | let number = if condition {
| __________________^
5 | | 5
6 | | } else {
7 | | "six"
8 | | };
| |_____^ expected integral variable, found &str
|
= note: expected type `{integer}`
found type `&str`
```
The expression in the `if` block evaluates to an integer, and the expression in
the `else` block evaluates to a string. This wont 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 wouldnt 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
Its 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, lets make a new project called *loops*.
Rust has three kinds of loops: `loop`, `while`, and `for`. Lets 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:
<span class="filename">Filename: src/main.rs</span>
```rust,ignore
fn main() {
loop {
println!("again!");
}
}
```
When we run this program, well see `again!` printed over and over continuously
until we stop the program manually. Most terminals support a keyboard shortcut,
<span class="keystroke">ctrl-c</span>, to halt a program that is stuck in a
continual loop. Give it a try:
```text
$ cargo run
Compiling loops v0.1.0 (file:///projects/loops)
Finished dev [unoptimized + debuginfo] target(s) in 0.29 secs
Running `target/debug/loops`
again!
again!
again!
again!
^Cagain!
```
The symbol `^C` represents where you pressed <span class="keystroke">ctrl-c
</span>. 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`
Its 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, the
program calls `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 youd like.
However, this pattern is so common that Rust has a built-in language construct
for it, called a `while` loop. Listing 3-3 uses `while`: the program loops
three times, counting down each time, and then, after the loop, it prints
another message and exits.
<span class="filename">Filename: src/main.rs</span>
```rust
fn main() {
let mut number = 3;
while number != 0 {
println!("{}!", number);
number = number - 1;
}
println!("LIFTOFF!!!");
}
```
<span class="caption">Listing 3-3: Using a `while` loop to run code while a
condition holds true</span>
This construct eliminates a lot of nesting that would be necessary if you used
`loop`, `if`, `else`, and `break`, and its 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, lets look at Listing 3-4:
<span class="filename">Filename: src/main.rs</span>
```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;
}
}
```
<span class="caption">Listing 3-4: Looping through each element of a collection
using a `while` loop</span>
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 every element
in the array:
```text
$ cargo run
Compiling loops v0.1.0 (file:///projects/loops)
Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
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. Its 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 concise alternative, you can use a `for` loop and execute some code
for each item in a collection. A `for` loop looks like this code in Listing 3-5:
<span class="filename">Filename: src/main.rs</span>
```rust
fn main() {
let a = [10, 20, 30, 40, 50];
for element in a.iter() {
println!("the value is: {}", element);
}
}
```
<span class="caption">Listing 3-5: Looping through each element of a collection
using a `for` loop</span>
When we run this code, well see the same output as in Listing 3-4. More
importantly, weve 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-4, 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 wouldnt 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-3, 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.
Heres what the countdown would look like using a `for` loop and another method
weve not yet talked about, `rev`, to reverse the range:
<span class="filename">Filename: src/main.rs</span>
```rust
fn main() {
for number in (1..4).rev() {
println!("{}!", number);
}
println!("LIFTOFF!!!");
}
```
This code is a bit nicer, isnt it?
## Summary
You made it! That was a sizable chapter: you learned about variables, scalar
and compound data types, functions, comments, `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 youre ready to move on, well talk about a concept in Rust that *doesnt*
commonly exist in other programming languages: ownership.

View File

@ -0,0 +1,7 @@
# Understanding Ownership
Ownership is Rusts most unique feature, and it enables Rust to make memory
safety guarantees without needing a garbage collector. Therefore, its
important to understand how ownership works in Rust. In this chapter, well
talk about ownership as well as several related features: borrowing, slices,
and how Rust lays data out in memory.

View File

@ -0,0 +1,552 @@
## What Is Ownership?
Rusts 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 computers 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. None of the ownership features slow down your program while its
running.
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 youll be able to naturally
develop code that is safe and efficient. Keep at it!
When you understand ownership, youll have a solid foundation for understanding
the features that make Rust unique. In this chapter, youll learn ownership by
working through some examples that focus on a very common data structure:
strings.
> ### The Stack and the Heap
>
> In many programming languages, you dont 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 you have to make certain decisions. Parts of ownership will
> be described 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 wouldnt 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.
>
> Data with a size unknown at compile time or a size that might change can be
> stored on the heap instead. The heap is less organized: when you put data on
> the heap, you 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 a *pointer*, which is the address of that location. This
> process is called *allocating on the heap*, sometimes abbreviated as just
> “allocating.” Pushing values onto the stack is not considered allocating.
> Because the pointer is a known, fixed size, you can store the pointer on the
> stack, but when you want the actual data, you 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
> youve been seated to find you.
>
> Accessing data in the heap is slower than accessing data on the stack because
> you 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. Its 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 thats 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 your code calls a function, the values passed into the function
> (including, potentially, pointers to data on the heap) and the functions
> 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 you dont run out of space are all problems that ownership
> addresses. Once you understand ownership, you wont 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.
### Ownership Rules
First, lets take a look at the ownership rules. Keep these rules in mind as we
work through the examples that illustrate them:
> 1. Each value in Rust has a variable thats 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
Weve walked through an example of a Rust program already in Chapter 2. Now
that were past basic syntax, we wont include all the `fn main() {` code in
examples, so if youre following along, youll 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, well look at the *scope* of some variables. A
scope is the range within a program for which an item is valid. Lets 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 its 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, its 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
```
<span class="caption">Listing 4-1: A variable and the scope in which it is
valid</span>
In other words, there are two important points in time here:
* When `s` comes *into scope*, it is valid.
* It remains valid until it goes *out of scope*.
At this point, the relationship between scopes and when variables are valid is
similar to that in other programming languages. Now well 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 the “Data Types” section of Chapter 3. The types
covered previously are all 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.
Well 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. Well discuss `String` in
more depth in Chapter 8.
Weve already seen string literals, where a string value is hardcoded into our
program. String literals are convenient, but they arent suitable for every
situation in which we may want to use text. One reason is that theyre
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`. Well discuss this syntax more in the “Method
Syntax” section of Chapter 5 and when we talk about namespacing with modules in
“Module Definitions” 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, whats 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. This is why string
literals are fast and efficient. But these properties only come from the string
literals immutability. Unfortunately, we cant 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:
* The memory must be requested from the operating system at runtime.
* We need a way of returning this memory to the operating system when were
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 isnt being used anymore,
and we dont need to think about it. Without a GC, its our 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, well waste memory. If we do it
too early, well have an invalid variable. If we do it twice, thats 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. Heres 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 its 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 items
> lifetime is sometimes called *Resource Acquisition Is Initialization (RAII)*.
> The `drop` function in Rust will be familiar to you if youve 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
weve allocated on the heap. Lets 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.
Lets look at an example using an integer in Listing 4-2:
```rust
let x = 5;
let y = x;
```
<span class="caption">Listing 4-2: Assigning the integer value of variable `x`
to `y`</span>
We can probably guess what this is doing: “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 lets 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 isnt quite what happens.
Take a look at Figure 4-1 to see what is happening to `String` under the
covers. 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.
<img alt="String in memory" src="img/trpl04-01.svg" class="center" style="width: 50%;" />
<span class="caption">Figure 4-1: Representation in memory of a `String`
holding the value `"hello"` bound to `s1`</span>
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, its 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-2.
<img alt="s1 and s2 pointing to the same value" src="img/trpl04-02.svg" class="center" style="width: 50%;" />
<span class="caption">Figure 4-2: Representation in memory of the variable `s2`
that has a copy of the pointer, length, and capacity of `s1`</span>
The representation does *not* look like Figure 4-3, 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 be very expensive in terms of runtime performance if
the data on the heap were large.
<img alt="s1 and s2 to two places" src="img/trpl04-03.svg" class="center" style="width: 50%;" />
<span class="caption">Figure 4-3: Another possibility for what `s2 = s1` might
do if Rust copied the heap data as well</span>
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-2 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, theres 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 doesnt need to free
anything when `s1` goes out of scope. Check out what happens when you try to
use `s1` after `s2` is created; it wont work:
```rust,ignore
let s1 = String::from("hello");
let s2 = s1;
println!("{}, world!", s1);
```
Youll get an error like this because Rust prevents you from using the
invalidated reference:
```text
error[E0382]: use of moved value: `s1`
--> src/main.rs:5:28
|
3 | let s2 = s1;
| -- value moved here
4 |
5 | println!("{}, world!", s1);
| ^^ value used here after move
|
= note: move occurs because `s1` has type `std::string::String`, which does
not implement the `Copy` trait
```
If youve 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 making a shallow copy. But
because Rust also invalidates the first variable, instead of being called a
shallow copy, its 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-4.
<img alt="s1 moved to s2" src="img/trpl04-04.svg" class="center" style="width: 50%;" />
<span class="caption">Figure 4-4: Representation in memory after `s1` has been
invalidated</span>
That solves our problem! With only `s2` valid, when it goes out of scope, it
alone will free the memory, and were done.
In addition, theres a design choice thats 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`. Well discuss method
syntax in Chapter 5, but because methods are a common feature in many
programming languages, youve probably seen them before.
Heres 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 explicitly produces the behavior shown in Figure 4-3,
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. Its a visual indicator that something
different is going on.
#### Stack-Only Data: Copy
Theres another wrinkle we havent 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 dont have a call to
`clone`, but `x` is still valid and wasnt moved into `y`.
The reason is that types such as 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 theres no reason we would want to prevent `x` from being
valid after we create the variable `y`. In other words, theres no difference
between deep and shallow copying here, so calling `clone` wouldnt do anything
different 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 (well talk more about traits
in Chapter 10). If a type has the `Copy` trait, an older variable is still
usable after assignment. Rust wont let us annotate a type with the `Copy`
trait if the type, or any of its parts, has implemented the `Drop` 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, well get a compile time error. To
learn about how to add the `Copy` annotation to your type, see “Derivable
Traits” in Appendix C.
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, such as `u32`.
* The Boolean type, `bool`, with values `true` and `false`.
* All the floating point types, such as `f64`.
* The character type, `char`.
* Tuples, but only if they contain types that are also `Copy`. For example,
`(i32, i32)` is `Copy`, but `(i32, String)` is not.
### Ownership and Functions
The semantics for passing a value to a function are similar to those for
assigning a value to a variable. Passing a variable to a function will move or
copy, just as assignment does. Listing 4-3 has an example with some annotations
showing where variables go into and out of scope:
<span class="filename">Filename: src/main.rs</span>
```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 its okay to still
// use x afterward
} // Here, x goes out of scope, then s. But because 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.
```
<span class="caption">Listing 4-3: Functions with ownership and scope
annotated</span>
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. Listing 4-4 is an example with
similar annotations to those in Listing 4-3:
<span class="filename">Filename: src/main.rs</span>
```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
}
```
<span class="caption">Listing 4-4: Transferring ownership of return
values</span>
The ownership of a variable follows the same pattern every time: assigning a
value to another variable moves it. When a variable that includes data on the
heap goes out of scope, the value will be cleaned up by `drop` unless the data
has been moved to be owned by another variable.
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?
Its 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.
Its possible to return multiple values using a tuple, as shown in Listing 4-5:
<span class="filename">Filename: src/main.rs</span>
```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)
}
```
<span class="caption">Listing 4-5: Returning ownership of parameters</span>
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, called
*references*.

View File

@ -0,0 +1,322 @@
## References and Borrowing
The issue with the tuple code in Listing 4-5 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 has a
reference to an object as a parameter instead of taking ownership of the
value:
<span class="filename">Filename: src/main.rs</span>
```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-5 shows a diagram.
<img alt="&String s pointing at String s1" src="img/trpl04-05.svg" class="center" />
<span class="caption">Figure 4-5: A diagram of `&String s` pointing at `String
s1`</span>
> Note: The opposite of referencing by using `&` is *dereferencing*, which is
> accomplished with the dereference operator, `*`. Well see some uses of the
> dereference operator in Chapter 8 and discuss details of dereferencing in
> Chapter 15.
Lets take a closer look at the function call here:
```rust
# fn calculate_length(s: &String) -> usize {
# s.len()
# }
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 the type of
the parameter `s` is a reference. Lets 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
parameters scope, but we dont drop what the reference points to when it goes
out of scope because we dont have ownership. When functions have references as
parameters instead of the actual values, we wont need to return the values in
order to give back ownership, because we never had ownership.
We call having references as function parameters *borrowing*. As in real life,
if a person owns something, you can borrow it from them. When youre done, you
have to give it back.
So what happens if we try to modify something were borrowing? Try the code in
Listing 4-6. Spoiler alert: it doesnt work!
<span class="filename">Filename: src/main.rs</span>
```rust,ignore
fn main() {
let s = String::from("hello");
change(&s);
}
fn change(some_string: &String) {
some_string.push_str(", world");
}
```
<span class="caption">Listing 4-6: Attempting to modify a borrowed value</span>
Heres the error:
```text
error[E0596]: cannot borrow immutable borrowed content `*some_string` as mutable
--> error.rs:8:5
|
7 | fn change(some_string: &String) {
| ------- use `&mut String` here to make mutable
8 | some_string.push_str(", world");
| ^^^^^^^^^^^ cannot borrow as mutable
```
Just as variables are immutable by default, so are references. Were not
allowed to modify something we have a reference to.
### Mutable References
We can fix the error in the code from Listing 4-6 with just a small tweak:
<span class="filename">Filename: src/main.rs</span>
```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:
<span class="filename">Filename: src/main.rs</span>
```rust,ignore
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
```
Heres 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. Its
something that new Rustaceans struggle with, because most languages let you
mutate whenever youd like.
The benefit of having this restriction is that Rust can prevent data races at
compile time. A *data race* is similar to a race condition and happens when
these three behaviors occur:
* Two or more pointers access the same data at the same time.
* At least one of the pointers is being used to write to the data.
* Theres no mechanism being used to synchronize access to the data.
Data races cause undefined behavior and can be difficult to diagnose and fix
when youre trying to track them down at runtime; Rust prevents this problem
from happening because it wont 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
```
Heres 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 dont 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 elses reading of
the data.
Even though these errors may be frustrating at times, remember that its the
Rust compiler pointing out a potential bug early (at compile time rather than
at runtime) and showing you exactly where the problem is. Then you dont have
to track down why your data isnt what you thought it was.
### Dangling References
In languages with pointers, its 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 you 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.
Lets try to create a dangling reference, which Rust will prevent with a
compile-time error:
<span class="filename">Filename: src/main.rs</span>
```rust,ignore
fn main() {
let reference_to_nothing = dangle();
}
fn dangle() -> &String {
let s = String::from("hello");
&s
}
```
Heres the error:
```text
error[E0106]: missing lifetime specifier
--> dangle.rs:5:16
|
5 | fn dangle() -> &String {
| ^ expected lifetime parameter
|
= 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
```
This error message refers to a feature we havent covered yet: *lifetimes*.
Well 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:
```text
this function's return type contains a borrowed value, but there is no value
for it to be borrowed from.
```
Lets take a closer look at exactly whats 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` Thats no good! Rust
wont let us do this.
The solution 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
Lets recap what weve discussed about references:
* At any given time, you can have *either* (but not both of) one mutable
reference or any number of immutable references.
* References must always be valid.
Next, well look at a different kind of reference: slices.

View File

@ -0,0 +1,386 @@
## The Slice Type
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.
Heres a small programming problem: write a function that takes a string and
returns the first word it finds in that string. If the function doesnt find a
space in the string, the whole string must be one word, so the entire string
should be returned.
Lets think about the signature of this function:
```rust,ignore
fn first_word(s: &String) -> ?
```
This function, `first_word`, has a `&String` as a parameter. We dont want
ownership, so this is fine. But what should we return? We dont really have a
way to talk about *part* of a string. However, we could return the index of the
end of the word. Lets try that, as shown in Listing 4-7:
<span class="filename">Filename: src/main.rs</span>
```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()
}
```
<span class="caption">Listing 4-7: The `first_word` function that returns a
byte index value into the `String` parameter</span>
Because we need to go through the `String` element by element and check whether
a value is a space, well convert our `String` to an array of bytes using the
`as_bytes` method:
```rust,ignore
let bytes = s.as_bytes();
```
Next, we create an iterator over the array of bytes using the `iter` method:
```rust,ignore
for (i, &item) in bytes.iter().enumerate() {
```
Well discuss iterators in more detail in Chapter 13. For now, know that `iter`
is a method that returns each element in a collection and that `enumerate`
wraps the result of `iter` and returns each element as part of a tuple instead.
The first element of the tuple returned from `enumerate` 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 `enumerate` method returns a tuple, we can use patterns to
destructure that tuple, just like everywhere else in Rust. So in the `for`
loop, we specify a pattern that has `i` for the index in the tuple and `&item`
for the single byte in the tuple. Because we get a reference to the element
from `.iter().enumerate()`, we use `&` in the pattern.
Inside the `for` loop, 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()`:
```rust,ignore
if item == b' ' {
return i;
}
}
s.len()
```
We now have a way to find out the index of the end of the first word in the
string, but theres a problem. Were returning a `usize` on its own, but its
only a meaningful number in the context of the `&String`. In other words,
because its a separate value from the `String`, theres no guarantee that it
will still be valid in the future. Consider the program in Listing 4-8 that
uses the `first_word` function from Listing 4-7:
<span class="filename">Filename: src/main.rs</span>
```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()
# }
#
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!
}
```
<span class="caption">Listing 4-8: Storing the result from calling the
`first_word` function and then changing the `String` contents</span>
This program compiles without any errors and would also do so if we used `word`
after calling `s.clear()`. Because `word` isnt connected to the state of `s`
at all, `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 were tracking a starting *and* an ending index, and we have even more
values that were calculated from data in a particular state but arent 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 it 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`, its a reference
to a portion of the `String`. The `start..end` syntax is a range that begins at
`start` and continues up to, but not including, `end`.
We can create slices using a range within brackets by specifying
`[starting_index..ending_index]`, where `starting_index` is the first position
in the slice and `ending_index` is one more than the last position in the
slice. Internally, the slice data structure stores the starting position and
the length of the slice, which corresponds to `ending_index` minus
`starting_index`. So in the case of `let world = &s[6..11];`, `world` would be
a slice that contains a pointer to the 6th byte of `s` and a length value of 5.
Figure 4-6 shows this in a diagram.
<img alt="world containing a pointer to the 6th byte of String s and a length 5" src="img/trpl04-06.svg" class="center" style="width: 50%;" />
<span class="caption">Figure 4-6: String slice referring to part of a
`String`</span>
With Rusts `..` 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[..];
```
> Note: String slice range indices must occur at valid UTF-8 character
> boundaries. If you attempt to create a string slice in the middle of a
> multibyte character, your program will exit with an error. For the purposes
> of introducing string slices, we are assuming ASCII only in this section; a
> more thorough discussion of UTF-8 handling is in the “Strings” section of
> Chapter 8.
With all this information in mind, lets rewrite `first_word` to return a
slice. The type that signifies “string slice” is written as `&str`:
<span class="filename">Filename: src/main.rs</span>
```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-7, 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 thats much harder to mess up, because the
compiler will ensure the references into the `String` remain valid. Remember
the bug in the program in Listing 4-8, 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 didnt 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:
<span class="filename">Filename: src/main.rs</span>
```rust,ignore
fn main() {
let mut s = String::from("hello world");
let word = first_word(&s);
s.clear(); // Error!
}
```
Heres the compiler error:
```text
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
--> src/main.rs:6:5
|
4 | let word = first_word(&s);
| - immutable borrow occurs here
5 |
6 | s.clear(); // Error!
| ^ mutable borrow occurs here
7 | }
| - immutable borrow ends here
```
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`: its 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 Parameters
Knowing that you can take slices of literals and `String`s leads us to one more
improvement on `first_word`, and thats 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 directly. If we have a `String`, we
can pass a slice of the entire `String`. Defining a function to take a string
slice instead of a reference to a `String` makes our API more general and useful
without losing any functionality:
<span class="filename">Filename: src/main.rs</span>
```rust
# 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[..]
# }
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[..]);
// Because 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 theres a
more general slice type, too. Consider this array:
```rust
let a = [1, 2, 3, 4, 5];
```
Just as we might want to refer to a part of a string, we might want to refer
to part of an array. Wed 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. Youll use this kind of
slice for all sorts of other collections. Well discuss these collections in
detail when we talk about vectors in Chapter 8.
## Summary
The concepts of ownership, borrowing, and slices ensure memory safety in Rust
programs at compile time. The Rust language gives you control over your memory
usage in the same way as other systems programming languages, but having the
owner of data automatically clean up that data when the owner goes out of scope
means you dont have to write and debug extra code to get this control.
Ownership affects how lots of other parts of Rust work, so well talk about
these concepts further throughout the rest of the book. Lets move on to
Chapter 5 and look at grouping pieces of data together in a `struct`.

View File

@ -0,0 +1,11 @@
# Using Structs to Structure Related Data
A *struct*, or *structure*, is a custom data type that lets you name and
package together multiple related values that make up a meaningful group. If
youre familiar with an object-oriented language, a *struct* is like an
objects data attributes. In this chapter, well compare and contrast tuples
with structs, demonstrate how to use structs, and discuss how to define methods
and associated functions to specify behavior associated with a structs data.
Structs and enums (discussed in Chapter 6) are the building blocks for creating
new types in your programs domain to take full advantage of Rusts compile
time type checking.

View File

@ -0,0 +1,310 @@
## Defining and Instantiating Structs
Structs are similar to tuples, which were discussed in Chapter 3. Like tuples,
the pieces of a struct can be different types. Unlike with tuples, youll name
each piece of data so its clear what the values mean. As a result of these
names, structs are more flexible than tuples: you dont 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 name the entire struct. A
structs name should describe the significance of the pieces of data being
grouped together. Then, inside curly brackets, we define the names and types of
the pieces of data, which we call *fields*. For example, Listing 5-1 shows a
struct that stores information about a user account:
```rust
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
```
<span class="caption">Listing 5-1: A `User` struct definition</span>
To use a struct after weve defined it, we create an *instance* of that struct
by specifying concrete values for each of the fields. We create an instance by
stating the name of the struct and then add curly brackets containing `key:
value` pairs, where the keys are the names of the fields and the values are the
data we want to store in those fields. We dont have to specify the fields in
the same order in which we declared them in the struct. In other words, the
struct definition is like a general template for the type, and instances fill
in that template with particular data to create values of the type. For
example, we can declare a particular user as shown in Listing 5-2:
```rust
# struct User {
# username: String,
# email: String,
# sign_in_count: u64,
# active: bool,
# }
#
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
```
<span class="caption">Listing 5-2: Creating an instance of the `User`
struct</span>
To get a specific value from a struct, we can use dot notation. If we wanted
just this users email address, we could use `user1.email` wherever we wanted
to use this value. If the instance is mutable, we can change a value by using
the dot notation and assigning into a particular field. Listing 5-3 shows how
to change the value in the `email` field of a mutable `User` instance:
```rust
# struct User {
# username: String,
# email: String,
# sign_in_count: u64,
# active: bool,
# }
#
let mut user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
user1.email = String::from("anotheremail@example.com");
```
<span class="caption">Listing 5-3: Changing the value in the `email` field of a
`User` instance</span>
Note that the entire instance must be mutable; Rust doesnt allow us to mark
only certain fields as mutable.
As with any expression, we can construct a new instance of the struct as the
last expression in the function body to implicitly return that new instance.
Listing 5-4 shows a `build_user` function that returns a `User` instance with
the given email and username. The `active` field gets the value of `true`, and
the `sign_in_count` gets a value of `1`.
```rust
# struct User {
# username: String,
# email: String,
# sign_in_count: u64,
# active: bool,
# }
#
fn build_user(email: String, username: String) -> User {
User {
email: email,
username: username,
active: true,
sign_in_count: 1,
}
}
```
<span class="caption">Listing 5-4: A `build_user` function that takes an email
and username and returns a `User` instance</span>
It makes sense to name the function parameters with the same name as the struct
fields, but having to repeat the `email` and `username` field names and
variables is a bit tedious. If the struct had more fields, repeating each name
would get even more annoying. Luckily, theres a convenient shorthand!
### Using the Field Init Shorthand when Variables and Fields Have the Same Name
Because the parameter names and the struct field names are exactly the same in
Listing 5-4, we can use the *field init shorthand* syntax to rewrite
`build_user` so that it behaves exactly the same but doesnt have the
repetition of `email` and `username` as shown in Listing 5-5.
```rust
# struct User {
# username: String,
# email: String,
# sign_in_count: u64,
# active: bool,
# }
#
fn build_user(email: String, username: String) -> User {
User {
email,
username,
active: true,
sign_in_count: 1,
}
}
```
<span class="caption">Listing 5-5: A `build_user` function that uses field init
shorthand because the `email` and `username` parameters have the same name as
struct fields</span>
Here, were creating a new instance of the `User` struct, which has a field
named `email`. We want to set the `email` fields value to the value in the
`email` parameter of the `build_user` function. Because the `email` field and
the `email` parameter have the same name, we only need to write `email` rather
than `email: email`.
### Creating Instances From Other Instances With Struct Update Syntax
Its often useful to create a new instance of a struct that uses most of an old
instances values but changes some. Youll do this using *struct update syntax*.
First, Listing 5-6 shows how we create a new `User` instance in `user2` without
the update syntax. We set new values for `email` and `username` but otherwise
use the same values from `user1` that we created in Listing 5-2:
```rust
# struct User {
# username: String,
# email: String,
# sign_in_count: u64,
# active: bool,
# }
#
# let user1 = User {
# email: String::from("someone@example.com"),
# username: String::from("someusername123"),
# active: true,
# sign_in_count: 1,
# };
#
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
active: user1.active,
sign_in_count: user1.sign_in_count,
};
```
<span class="caption">Listing 5-6: Creating a new `User` instance using some of
the values from `user1`</span>
Using struct update syntax, we can achieve the same effect with less code, as
shown in Listing 5-7. The syntax `..` specifies that the remaining fields not
explicitly set should have the same value as the fields in the given instance.
```rust
# struct User {
# username: String,
# email: String,
# sign_in_count: u64,
# active: bool,
# }
#
# let user1 = User {
# email: String::from("someone@example.com"),
# username: String::from("someusername123"),
# active: true,
# sign_in_count: 1,
# };
#
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
..user1
};
```
<span class="caption">Listing 5-7: Using struct update syntax to set new
`email` and `username` values for a `User` instance but use the rest of the
values from the fields of the instance in the `user1` variable</span>
The code in Listing 5-7 also creates an instance in `user2` that has a
different value for `email` and `username` but has the same values for the
`active` and `sign_in_count` fields from `user1`.
### Tuple Structs without Named Fields to Create Different Types
You can also define structs that look similar to tuples, called *tuple
structs*. Tuple structs have the added meaning the struct name provides but
dont have names associated with their fields; rather, they just have the types
of the fields. Tuple structs are useful when you want to give the whole tuple a
name and make the tuple be a different type than other tuples, and naming each
field as in a regular struct would be verbose or redundant.
To define a tuple struct start with the `struct` keyword and the struct name
followed by the types in the tuple. For example, here are definitions and
usages of two tuple structs named `Color` and `Point`:
```rust
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
```
Note that the `black` and `origin` values are different types, because theyre
instances of different tuple structs. Each struct you define is its own type,
even though the fields within the struct have the same types. For example, a
function that takes a parameter of type `Color` cannot take a `Point` as an
argument, even though both types are made up of three `i32` values. Otherwise,
tuple struct instances behave like tuples: you can destructure them into their
individual pieces, you can use a `.` followed by the index to access an
individual value, and so on.
### Unit-Like Structs Without Any Fields
You can also define structs that dont have any fields! These are called
*unit-like structs* because they behave similarly to `()`, the unit type.
Unit-like structs can be useful in situations in which you need to implement a
trait on some type but dont have any data that you want to store in the type
itself. Well discuss traits in Chapter 10.
> ### 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.
>
> Its possible for structs to store references to data owned by something else,
> but to do so requires the use of *lifetimes*, a Rust feature that well
> discuss in Chapter 10. Lifetimes ensure that the data referenced by a struct
> is valid for as long as the struct is. Lets say you try to store a reference
> in a struct without specifying lifetimes, like this, which wont work:
>
> <span class="filename">Filename: src/main.rs</span>
>
> ```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
> ```
>
> In Chapter 10, well discuss how to fix these errors so you can store
> references in structs, but for now, well fix errors like these using owned
> types like `String` instead of references like `&str`.

View File

@ -0,0 +1,264 @@
## An Example Program Using Structs
To understand when we might want to use structs, lets write a program that
calculates the area of a rectangle. Well start with single variables, and then
refactor the program until were using structs instead.
Lets make a new binary project with Cargo called *rectangles* that will take
the width and height of a rectangle specified in pixels and calculate the area
of the rectangle. Listing 5-8 shows a short program with one way of doing
exactly that in our projects *src/main.rs*:
<span class="filename">Filename: src/main.rs</span>
```rust
fn main() {
let width1 = 30;
let height1 = 50;
println!(
"The area of the rectangle is {} square pixels.",
area(width1, height1)
);
}
fn area(width: u32, height: u32) -> u32 {
width * height
}
```
<span class="caption">Listing 5-8: Calculating the area of a rectangle
specified by separate width and height variables</span>
Now, run this program using `cargo run`:
```text
The area of the rectangle is 1500 square pixels.
```
Even though Listing 5-8 works and figures out the area of the rectangle by
calling the `area` function with each dimension, we can do better. The width
and the height are related to each other because together they describe one
rectangle.
The issue with this code is evident in the signature of `area`:
```rust,ignore
fn area(width: u32, height: u32) -> u32 {
```
The `area` function is supposed to calculate the area of one rectangle, but the
function we wrote has two parameters. The parameters are related, but thats
not expressed anywhere in our program. It would be more readable and more
manageable to group width and height together. Weve already discussed one way
we might do that in “The Tuple Type” section of Chapter 3: by using tuples.
### Refactoring with Tuples
Listing 5-9 shows another version of our program that uses tuples:
<span class="filename">Filename: src/main.rs</span>
```rust
fn main() {
let rect1 = (30, 50);
println!(
"The area of the rectangle is {} square pixels.",
area(rect1)
);
}
fn area(dimensions: (u32, u32)) -> u32 {
dimensions.0 * dimensions.1
}
```
<span class="caption">Listing 5-9: Specifying the width and height of the
rectangle with a tuple</span>
In one way, this program is better. Tuples let us add a bit of structure, and
were now passing just one argument. But in another way, this version is less
clear: tuples dont name their elements, so our calculation has become more
confusing because we have to index into the parts of the tuple.
It doesnt matter if we mix up width and height for the area calculation, but
if we want to draw the rectangle on the screen, it would matter! We would have
to keep in mind that `width` is the tuple index `0` and `height` is the tuple
index `1`. If someone else worked on this code, they would have to figure this
out and keep it in mind as well. It would be easy to forget or mix up these
values and cause errors, because we havent conveyed the meaning of our data in
our code.
### Refactoring with Structs: Adding More Meaning
We use structs to add meaning by labeling the data. We can transform the tuple
were using into a data type with a name for the whole as well as names for the
parts, as shown in Listing 5-10:
<span class="filename">Filename: src/main.rs</span>
```rust
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
println!(
"The area of the rectangle is {} square pixels.",
area(&rect1)
);
}
fn area(rectangle: &Rectangle) -> u32 {
rectangle.width * rectangle.height
}
```
<span class="caption">Listing 5-10: Defining a `Rectangle` struct</span>
Here weve defined a struct and named it `Rectangle`. Inside the curly
brackets, we defined the fields as `width` and `height`, both of which have
type `u32`. Then in `main`, we created a particular instance of `Rectangle`
that has a width of 30 and a height of 50.
Our `area` function is now defined with one parameter, which weve named
`rectangle`, whose type is an immutable borrow of a struct `Rectangle`
instance. As mentioned in Chapter 4, we want to borrow the struct rather than
take ownership of it. This way, `main` retains its ownership and can continue
using `rect1`, which is the reason we use the `&` in the function signature and
where we call the function.
The `area` function accesses the `width` and `height` fields of the `Rectangle`
instance. Our function signature for `area` now says exactly what we mean:
calculate the area of `Rectangle`, using its `width` and `height` fields. This
conveys that the width and height are related to each other, and it 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
Itd be nice to be able to print an instance of `Rectangle` while were
debugging our program and see the values for all its fields. Listing 5-11 tries
using the `println!` macro as we have used in previous chapters. This wont
work, however:
<span class="filename">Filename: src/main.rs</span>
```rust,ignore
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
println!("rect1 is {}", rect1);
}
```
<span class="caption">Listing 5-11: Attempting to print a `Rectangle`
instance</span>
When we run this code, 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, curly
brackets tell `println!` to use formatting known as `Display`: output intended
for direct end user consumption. The primitive types weve seen so far
implement `Display` by default, because theres only one way youd 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 because there are more
display possibilities: Do you want commas or not? Do you want to print the
curly brackets? Should all the fields be shown? Due to this ambiguity, Rust
doesnt try to guess what we want, and structs dont have a provided
implementation of `Display`.
If we continue reading the errors, well find this helpful note:
```text
`Rectangle` cannot be formatted with the default formatter; try using
`:?` instead if you are using a format string
```
Lets try it! The `println!` macro call will now look like `println!("rect1 is
{:?}", rect1);`. Putting the specifier `:?` inside the curly brackets tells
`println!` we want to use an output format called `Debug`. `Debug` is a trait
that enables us to print our struct in a way that is useful for developers so
we can see its value while were debugging our code.
Run the code with this change. Drat! We still get an error:
```text
error[E0277]: the trait bound `Rectangle: std::fmt::Debug` is not satisfied
```
But again, the compiler gives us a helpful note:
```text
`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 make that functionality available for our struct.
To do that, we add the annotation `#[derive(Debug)]` just before the struct
definition, as shown in Listing 5-12:
<span class="filename">Filename: src/main.rs</span>
```rust
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
println!("rect1 is {:?}", rect1);
}
```
<span class="caption">Listing 5-12: Adding the annotation to derive the `Debug`
trait and printing the `Rectangle` instance using debug formatting</span>
Now when we run the program, we wont get any errors, and well see the
following output:
```text
rect1 is Rectangle { width: 30, height: 50 }
```
Nice! Its not the prettiest output, but it shows the values of all the fields
for this instance, which would definitely help during debugging. When we have
larger structs, its useful to have output thats a bit easier to read; in
those cases, we can use `{:#?}` instead of `{:?}` in the `println!` string.
When we use the `{:#?}` style in the example, the output will look like this:
```text
rect1 is Rectangle {
width: 30,
height: 50
}
```
Rust has provided a number of traits for us to use with the `derive` annotation
that can add useful behavior to our custom types. Those traits and their
behaviors are listed in Appendix C, “Derivable Traits.” Well cover how to
implement these traits with custom behavior as well as how to create your own
traits in Chapter 10.
Our `area` function is very specific: it only computes the area of rectangles.
It would be helpful to tie this behavior more closely to our `Rectangle`
struct, because it wont work with any other type. Lets look at how we can
continue to refactor this code by turning the `area` function into an `area`
*method* defined on our `Rectangle` type.

View File

@ -0,0 +1,276 @@
## Method Syntax
*Methods* are similar to functions: theyre declared with the `fn` keyword and
their name, they can have parameters and a return value, and they contain some
code that is run when theyre called from somewhere else. However, methods are
different from functions in that theyre defined within the context of a struct
(or an enum or a trait object, which we cover in Chapters 6 and 17,
respectively), and their first parameter is always `self`, which represents the
instance of the struct the method is being called on.
### Defining Methods
Lets change the `area` function that has a `Rectangle` instance as a parameter
and instead make an `area` method defined on the `Rectangle` struct, as shown
in Listing 5-13:
<span class="filename">Filename: src/main.rs</span>
```rust
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
println!(
"The area of the rectangle is {} square pixels.",
rect1.area()
);
}
```
<span class="caption">Listing 5-13: Defining an `area` method on the
`Rectangle` struct</span>
To define the function within the context of `Rectangle`, we start an `impl`
(implementation) block. Then we move the `area` function within the `impl`
curly brackets and change the first (and in this case, only) parameter to be
`self` in the signature and everywhere within the body. 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.
The method syntax goes after an instance: we add a dot followed by the method
name, parentheses, and any arguments.
In the signature for `area`, we use `&self` instead of `rectangle: &Rectangle`
because Rust knows the type of `self` is `Rectangle` due to this methods being
inside the `impl Rectangle` context. Note that we still need to use the `&`
before `self`, just as we did in `&Rectangle`. Methods can take ownership of
`self`, borrow `self` immutably as weve done here, or borrow `self` mutably,
just as they can any other parameter.
Weve chosen `&self` here for the same reason we used `&Rectangle` in the
function version: we dont want to take ownership, and we just want to read the
data in the struct, not write to it. If we wanted to change the instance that
weve called the method on as part of what the method does, wed use `&mut
self` as the first parameter. Having a method that takes ownership of the
instance by using just `self` as the first parameter is rare; this technique is
usually used when the method transforms `self` into something else and you want
to prevent the caller from using the original instance after the transformation.
The main benefit of using methods instead of functions, in addition to using
method syntax and not having to repeat the type of `self` in every methods
signature, is for organization. Weve put all the things we can do with an
instance of a type in one `impl` block rather than making future users of our
code search for capabilities of `Rectangle` in various places in the library we
provide.
> ### Wheres the `->` Operator?
>
> In C and C++, two different operators are used for calling methods: you use
> `.` if youre calling a method on the object directly and `->` if youre
> calling the method on a pointer to the object and need to dereference the
> pointer first. In other words, if `object` is a pointer,
> `object->something()` is similar to `(*object).something()`.
>
> Rust doesnt 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 this behavior.
>
> Heres how it works: when you call a method with `object.something()`, Rust
> automatically adds in `&`, `&mut`, or `*` so `object` matches the signature of
> the method. In other words, the following are the same:
>
> ```rust
> # #[derive(Debug,Copy,Clone)]
> # struct Point {
> # x: f64,
> # y: f64,
> # }
> #
> # impl Point {
> # fn distance(&self, other: &Point) -> f64 {
> # let x_squared = f64::powi(other.x - self.x, 2);
> # let y_squared = f64::powi(other.y - self.y, 2);
> #
> # f64::sqrt(x_squared + y_squared)
> # }
> # }
> # let p1 = Point { x: 0.0, y: 0.0 };
> # let p2 = Point { x: 5.0, y: 6.5 };
> p1.distance(&p2);
> (&p1).distance(&p2);
> ```
>
> The first one looks 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
> reading (`&self`), mutating (`&mut self`), or consuming (`self`). The fact
> that Rust makes borrowing implicit for method receivers is a big part of
> making ownership ergonomic in practice.
### Methods with More Parameters
Lets practice using methods by implementing a second method on the `Rectangle`
struct. This time, we want an instance of `Rectangle` to take another instance
of `Rectangle` and return `true` if the second `Rectangle` can fit completely
within `self`; otherwise it should return `false`. That is, we want to be able
to write the program shown in Listing 5-14, once weve defined the `can_hold`
method:
<span class="filename">Filename: src/main.rs</span>
```rust,ignore
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
let rect2 = Rectangle { width: 10, height: 40 };
let rect3 = Rectangle { width: 60, height: 45 };
println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
}
```
<span class="caption">Listing 5-14: Using the as-yet-unwritten `can_hold`
method</span>
And the expected output would look like the following, because both dimensions
of `rect2` are smaller than the dimensions of `rect1` 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 a parameter. We can tell what the type of the
parameter will be by looking at the code that calls the method:
`rect1.can_hold(&rect2)` passes in `&rect2`, which is an immutable borrow to
`rect2`, an instance of `Rectangle`. This makes sense because we only need to
read `rect2` (rather than write, which would mean wed need a mutable borrow),
and we want `main` to retain ownership of `rect2` so we can use it again after
calling the `can_hold` method. The return value of `can_hold` will be a
Boolean, and the implementation will check whether the width and height of
`self` are both greater than the width and height of the other `Rectangle`,
respectively. Lets add the new `can_hold` method to the `impl` block from
Listing 5-13, shown in Listing 5-15:
<span class="filename">Filename: src/main.rs</span>
```rust
# #[derive(Debug)]
# struct Rectangle {
# width: u32,
# height: u32,
# }
#
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
```
<span class="caption">Listing 5-15: Implementing the `can_hold` method on
`Rectangle` that takes another `Rectangle` instance as a parameter</span>
When we run this code with the `main` function in Listing 5-14, well get our
desired output. Methods can take multiple parameters that we add to the
signature after the `self` parameter, and those parameters work just like
parameters in functions.
### Associated Functions
Another useful feature of `impl` blocks is that were allowed to define
functions within `impl` blocks that *dont* take `self` as a parameter. These
are called *associated functions* because theyre associated with the struct.
Theyre still functions, not methods, because they dont have an instance of
the struct to work with. Youve already used the `String::from` associated
function.
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 have one dimension parameter and use that as both width and height,
thus making it easier to create a square `Rectangle` rather than having to
specify the same value twice:
<span class="filename">Filename: src/main.rs</span>
```rust
# #[derive(Debug)]
# struct Rectangle {
# width: u32,
# height: u32,
# }
#
impl Rectangle {
fn square(size: u32) -> Rectangle {
Rectangle { width: size, height: size }
}
}
```
To call this associated function, we use the `::` syntax with the struct name;
`let sq = Rectangle::square(3);` is an example. This function is namespaced by
the struct: the `::` syntax is used for both associated functions and
namespaces created by modules. Well discuss modules in Chapter 7.
### Multiple `impl` Blocks
Each struct is allowed to have multiple `impl` blocks. For example, Listing
5-15 is equivalent to the code shown in Listing 5-16, which has each method
in its own `impl` block:
```rust
# #[derive(Debug)]
# struct Rectangle {
# width: u32,
# height: u32,
# }
#
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
impl Rectangle {
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
```
<span class="caption">Listing 5-16: Rewriting Listing 5-15 using multiple `impl`
blocks</span>
Theres no reason to separate these methods into multiple `impl` blocks here,
but this is valid syntax. Well see a case in which multiple `impl` blocks are
useful in Chapter 10 where we discuss generic types and traits.
## Summary
Structs let you create custom types that are meaningful for your domain. By
using structs, you can keep associated pieces of data connected to each other
and name each piece to make your code clear. Methods let you specify the
behavior that instances of your structs have, and associated functions let you
namespace functionality that is particular to your struct without having an
instance available.
But structs arent the only way you can create custom types: lets turn to
Rusts enum feature to add another tool to your toolbox.

View File

@ -0,0 +1,15 @@
# Enums and Pattern Matching
In this chapter well look at *enumerations*, also referred to as *enums*.
Enums allow you to define a type by enumerating its possible values. First,
well define and use an enum to show how an enum can encode meaning along with
data. Next, well explore a particularly useful enum, called `Option`, which
expresses that a value can be either something or nothing. Then well look at
how pattern matching in the `match` expression makes it easy to run different
code for different values of an enum. Finally, well 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. Rusts enums are most similar to *algebraic data types* in functional
languages, such as F#, OCaml, and Haskell.

View File

@ -0,0 +1,399 @@
## Defining an Enum
Lets 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, 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
# enum IpAddrKind {
# V4,
# V6,
# }
#
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
# enum IpAddrKind {
# V4,
# V6,
# }
#
fn route(ip_type: IpAddrKind) { }
```
And we can call this function with either variant:
```rust
# enum IpAddrKind {
# V4,
# V6,
# }
#
# fn route(ip_type: IpAddrKind) { }
#
route(IpAddrKind::V4);
route(IpAddrKind::V6);
```
Using enums has even more advantages. Thinking more about our IP address type,
at the moment we dont 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"),
};
```
<span class="caption">Listing 6-1: Storing the data and `IpAddrKind` variant of
an IP address using a `struct`</span>
Here, weve 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. Weve 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 inside 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.
Theres 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 wouldnt 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"));
```
Weve shown several different ways to define data structures to store version
four and version six IP addresses. 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!][IpAddr]<!-- ignore --> Lets look at how
the standard library defines `IpAddr`: it has the exact enum and variants that
weve 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:
[IpAddr]: ../../std/net/enum.IpAddr.html
```rust
struct Ipv4Addr {
// --snip--
}
struct Ipv6Addr {
// --snip--
}
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
havent brought the standard librarys definition into our scope. Well talk
more about bringing types into scope in Chapter 7.
Lets 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),
}
```
<span class="caption">Listing 6-2: A `Message` enum whose variants each store
different amounts and types of values</span>
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` values.
Defining an enum with variants like the ones in Listing 6-2 is similar to
defining different kinds of struct definitions, except the enum doesnt 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
couldnt as easily define a function to 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 were able to
define methods on structs using `impl`, were also able to define methods on
enums. Heres a method named `call` that we could define on our `Message` enum:
```rust
# enum Message {
# Quit,
# Move { x: i32, y: i32 },
# Write(String),
# ChangeColor(i32, i32, i32),
# }
#
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, weve created a variable `m` that has the value
`Message::Write(String::from("hello"))`, and that is what `self` will be in the
body of the `call` method when `m.call()` runs.
Lets 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 Rusts
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 whether youve handled all the cases you should be handling;
this functionality 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 doesnt 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 his 2009 presentation “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 couldnt 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 use a null value as a
not-null value, youll get an error of some kind. Because this null or not-null
property is pervasive, its 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 isnt really with the 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<T>`, and it is [defined by the standard library][option]<!-- ignore -->
as follows:
[option]: ../../std/option/enum.Option.html
```rust
enum Option<T> {
Some(T),
None,
}
```
The `Option<T>` enum is so useful that its even included in the prelude; you
dont need to bring it into scope explicitly. In addition, so are its variants:
you can use `Some` and `None` directly without the `Option::` prefix. The
`Option<T>` enum is still just a regular enum, and `Some(T)` and `None` are
still variants of type `Option<T>`.
The `<T>` syntax is a feature of Rust we havent talked about yet. Its a
generic type parameter, and well cover generics in more detail in Chapter 10.
For now, all you need to know is that `<T>` 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<i32> = None;
```
If we use `None` rather than `Some`, we need to tell Rust what type of
`Option<T>` we have, because the compiler cant 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 dont have a valid value. So why is having
`Option<T>` any better than having null?
In short, because `Option<T>` and `T` (where `T` can be any type) are different
types, the compiler wont let us use an `Option<T>` value as if it were
definitely a valid value. For example, this code wont compile because its
trying to add an `i8` to an `Option<i8>`:
```rust,ignore
let x: i8 = 5;
let y: Option<i8> = 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<std::option::Option<i8>>` is
not satisfied
-->
|
5 | let sum = x + y;
| ^ no implementation for `i8 + std::option::Option<i8>`
|
```
Intense! In effect, this error message means that Rust doesnt understand how
to add an `i8` and an `Option<i8>`, because theyre 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<i8>` (or
whatever type of value were 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<T>` 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 isnt null when it actually
is.
Not having to worry about incorrectly assuming 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<T>`.
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 isnt an
`Option<T>`, you *can* safely assume that the value isnt null. This was a
deliberate design decision for Rust to limit nulls 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<T>` so you can use that value? The `Option<T>` enum has a large
number of methods that are useful in a variety of situations; you can check
them out in [its documentation][docs]<!-- ignore -->. Becoming familiar with
the methods on `Option<T>` will be extremely useful in your journey with Rust.
[docs]: ../../std/option/enum.Option.html
In general, in order to use an `Option<T>` value, you want to have code that
will handle each variant. You want some code that will run only when you have a
`Some(T)` value, and this code is allowed to use the inner `T`. You want some
other code to run if you have a `None` value, and that code doesnt 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.

View File

@ -0,0 +1,295 @@
## The `match` Control Flow Operator
Rust has an extremely powerful control flow operator called `match` that allows
you 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 covers all the different
kinds of patterns and what they do. The power of `match` comes from the
expressiveness of the patterns and the fact that the compiler confirms that all
possible cases are handled.
Think of a `match` expression as being 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 falls into the associated code block to be used during execution.
Because we just mentioned coins, lets 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) -> u32 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
```
<span class="caption">Listing 6-3: An enum and a `match` expression that has
the variants of the enum as its patterns</span>
Lets 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 theres a
big difference: with `if`, the expression needs to return a Boolean value, but
here, it can be any type. The type of `coin` in this example is the `Coin` enum
that we defined on line 1.
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 doesnt match the
value, execution continues to the next arm, much as in 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 brackets typically arent 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 brackets. For example, the
following code would print “Lucky penny!” every time the method was called with
a `Coin::Penny` but would still return the last value of the block, `1`:
```rust
# enum Coin {
# Penny,
# Nickel,
# Dime,
# Quarter,
# }
#
fn value_in_cents(coin: Coin) -> u32 {
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 the parts of the
values that match the pattern. This is how we can extract values out of enum
variants.
As an example, lets change one of our enum variants to hold data inside it.
From 1999 through 2008, the United States minted quarters with different
designs for each of the 50 states on one side. No other coins got state
designs, so only quarters have this extra value. We can add this information to
our `enum` by changing the `Quarter` variant to include a `UsState` value stored
inside it, which weve done here in Listing 6-4:
```rust
#[derive(Debug)] // So we can inspect the state in a minute
enum UsState {
Alabama,
Alaska,
// --snip--
}
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState),
}
```
<span class="caption">Listing 6-4: A `Coin` enum in which the `Quarter` variant
also holds a `UsState` value</span>
Lets imagine that a friend of ours is trying to collect all 50 state quarters.
While we sort our loose change by coin type, well also call out the name of
the state associated with each quarter so if its one our friend doesnt 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
quarters state. Then we can use `state` in the code for that arm, like so:
```rust
# #[derive(Debug)]
# enum UsState {
# Alabama,
# Alaska,
# }
#
# enum Coin {
# Penny,
# Nickel,
# Dime,
# Quarter(UsState),
# }
#
fn value_in_cents(coin: Coin) -> u32 {
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<T>`
In the previous section, we wanted to get the inner `T` value out of the `Some`
case when using `Option<T>`; we can also handle `Option<T>` using `match` as we
did with the `Coin` enum! Instead of comparing coins, well compare the
variants of `Option<T>`, but the way that the `match` expression works remains
the same.
Lets say we want to write a function that takes an `Option<i32>` and, if
theres a value inside, adds 1 to that value. If there isnt 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<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
```
<span class="caption">Listing 6-5: A function that uses a `match` expression on
an `Option<i32>`</span>
Lets examine the first execution of `plus_one` in more detail. When we call
`plus_one(five)`, 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 doesnt match the pattern `None`, so we continue to the
next arm.
```rust,ignore
Some(i) => Some(i + 1),
```
Does `Some(5)` match `Some(i)`? 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 1 to the value of `i` and
create a new `Some` value with our total `6` inside.
Now lets consider the second call of `plus_one` in Listing 6-5, where `x` is
`None`. We enter the `match` and compare to the first arm.
```rust,ignore
None => None,
```
It matches! Theres 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. Youll 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. Its a bit tricky at first, but
once you get used to it, youll wish you had it in all languages. Its
consistently a user favorite.
### Matches Are Exhaustive
Theres one other aspect of `match` we need to discuss. Consider this version
of our `plus_one` function that has a bug and wont compile:
```rust,ignore
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
Some(i) => Some(i + 1),
}
}
```
We didnt handle the `None` case, so this code will cause a bug. Luckily, its
a bug Rust knows how to catch. If we try to compile this code, well get this
error:
```text
error[E0004]: non-exhaustive patterns: `None` not covered
-->
|
6 | match x {
| ^ pattern `None` not covered
```
Rust knows that we didnt 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<T>`, 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 when we dont 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 dont want to have to list out 0, 2,
4, 6, 8, 9 all the way up to 255. Fortunately, we dont 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 arent 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 dont
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`.

View File

@ -0,0 +1,118 @@
## 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 while ignoring the rest. Consider the
program in Listing 6-6 that matches on an `Option<u8>` value but only wants to
execute code if the value is 3:
```rust
let some_u8_value = Some(0u8);
match some_u8_value {
Some(3) => println!("three"),
_ => (),
}
```
<span class="caption">Listing 6-6: A `match` that only cares about executing
code when the value is `Some(3)`</span>
We want to do something with the `Some(3)` match but do nothing with any other
`Some<u8>` 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
# let some_u8_value = Some(0u8);
if let Some(3) = some_u8_value {
println!("three");
}
```
The syntax `if let` takes a pattern and an expression separated by an `=`. It
works the same way as a `match`, where the expression is given to the `match`
and the pattern is its first arm.
Using `if let` means you have less typing, less indentation, and less
boilerplate code. However, you lose the exhaustive checking that `match`
enforces. Choosing between `match` and `if let` depends on what youre doing in
your particular situation and whether gaining conciseness is an appropriate
trade-off for losing exhaustive checking.
In other words, you can think of `if let` as syntax sugar for a `match` that
runs code when the value matches one pattern and then ignores all other values.
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
# #[derive(Debug)]
# enum UsState {
# Alabama,
# Alaska,
# }
#
# enum Coin {
# Penny,
# Nickel,
# Dime,
# Quarter(UsState),
# }
# let coin = Coin::Penny;
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
# #[derive(Debug)]
# enum UsState {
# Alabama,
# Alaska,
# }
#
# enum Coin {
# Penny,
# Nickel,
# Dime,
# Quarter(UsState),
# }
# let coin = Coin::Penny;
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
Weve now covered how to use enums to create custom types that can be one of a
set of enumerated values. Weve shown how the standard librarys `Option<T>`
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 get only 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, lets now turn to
Rusts modules.

View File

@ -0,0 +1,24 @@
# Using Modules to Reuse and Organize Code
When you start writing programs in Rust, your code might live solely in the
`main` function. As your code grows, youll eventually move functionality into
other functions for reuse and better organization. By splitting your code into
smaller chunks, you make each chunk easier to understand on its own. But what
happens if you have too many functions? Rust has a module system that enables
the reuse of code in an organized fashion.
In the same way that you extract lines of code into a function, you can extract
functions (and other code, like structs and enums) 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). Heres an overview of how modules work:
* The `mod` keyword declares a new module. Code within the module appears
either immediately following this declaration within curly brackets or in
another file.
* By default, functions, types, constants, and modules are private. The `pub`
keyword makes an item public and therefore visible outside its namespace.
* The `use` keyword brings modules, or the definitions inside modules, into
scope so its easier to refer to them.
Well look at each of these parts to see how they fit into the whole.

View File

@ -0,0 +1,481 @@
## `mod` and the Filesystem
Well start our module example by making a new project with Cargo, but instead
of creating a binary crate, well make a library crate: a project that other
people can pull into their projects as a dependency. For example, the `rand`
crate discussed in Chapter 2 is a library crate that we used as a dependency in
the guessing game project.
Well create a skeleton of a library that provides some general networking
functionality; well concentrate on the organization of the modules and
functions, but we wont worry about what code goes in the function bodies.
Well call our library `communicator`. To create a library, pass the `--lib`
option instead of `--bin`:
```text
$ cargo new communicator --lib
$ cd communicator
```
Notice that Cargo generated *src/lib.rs* instead of *src/main.rs*. Inside
*src/lib.rs* well find the following:
<span class="filename">Filename: src/lib.rs</span>
```rust
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
```
Cargo creates an example test to help us get our library started, rather than
the “Hello, world!” binary that we get when we use the `--bin` option. Well
look at the `#[]` and `mod tests` syntax in the “Using `super` to Access a
Parent Module” section later in this chapter, but for now, leave this code at
the bottom of *src/lib.rs*.
Because we dont have a *src/main.rs* file, theres nothing for Cargo to
execute with the `cargo run` command. Therefore, well use the `cargo build`
command to compile our library crates code.
Well look at different options for organizing your librarys code that will be
suitable in a variety of situations, depending on the intent of the code.
### Module Definitions
For our `communicator` networking library, well first 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:
<span class="filename">Filename: src/lib.rs</span>
```rust
mod network {
fn connect() {
}
}
```
After the `mod` keyword, we put the name of the module, `network`, and then a
block of code in curly brackets. 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 code outside the `network` module, we
would need to specify the module and use the namespace syntax `::` like so:
`network::connect()`.
We can also have multiple modules, side by side, in the same *src/lib.rs* file.
For example, to also have a `client` module that has a function named
`connect`, we can add it as shown in Listing 7-1:
<span class="filename">Filename: src/lib.rs</span>
```rust
mod network {
fn connect() {
}
}
mod client {
fn connect() {
}
}
```
<span class="caption">Listing 7-1: The `network` module and the `client` module
defined side by side in *src/lib.rs*</span>
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 because theyre in different modules.
In this case, because were building a library, the file that serves as the
entry point for building our library is *src/lib.rs*. However, in respect to
creating modules, theres nothing special about *src/lib.rs*. We could also
create modules in *src/main.rs* for a binary crate in the same way as were
creating modules in *src/lib.rs* for the library crate. In fact, we can put
modules inside of modules, which can be useful as your modules grow to keep
related functionality organized together and separate functionality apart. The
way you choose to organize your code depends on how you think about the
relationship between the parts of your code. For instance, the `client` code
and its `connect` function might make more sense to users of our library if
they were inside the `network` namespace instead, as in Listing 7-2:
<span class="filename">Filename: src/lib.rs</span>
```rust
mod network {
fn connect() {
}
mod client {
fn connect() {
}
}
}
```
<span class="caption">Listing 7-2: Moving the `client` module inside the
`network` module</span>
In your *src/lib.rs* file, replace the existing `mod network` and `mod client`
definitions with the ones in Listing 7-2, which have the `client` module as an
inner module of `network`. The functions `network::connect` and
`network::client::connect` are both named `connect`, but they dont conflict
with each other because theyre 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. Heres what the
organization of our example in Listing 7-1 looks like when thought of as a
hierarchy:
```text
communicator
├── network
└── client
```
And heres the hierarchy corresponding to the example in Listing 7-2:
```text
communicator
└── network
└── client
```
The hierarchy shows that in Listing 7-2, `client` is a child of the `network`
module rather than a sibling. More complicated projects can have many modules,
and theyll need to be organized logically in order for you to keep track of
them. What “logically” means in your project is up to you and depends on how
you and your librarys users think about your projects domain. Use the
techniques 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 youre used to: filesystems! We can use Rusts module system along with
multiple files to split up Rust projects so not everything lives in
*src/lib.rs* or *src/main.rs*. For this example, lets start with the code in
Listing 7-3:
<span class="filename">Filename: src/lib.rs</span>
```rust
mod client {
fn connect() {
}
}
mod network {
fn connect() {
}
mod server {
fn connect() {
}
}
}
```
<span class="caption">Listing 7-3: Three modules, `client`, `network`, and
`network::server`, all defined in *src/lib.rs*</span>
The file *src/lib.rs* has this module hierarchy:
```text
communicator
├── client
└── network
└── server
```
If these modules had many functions, and those functions were becoming lengthy,
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 lengthy as well.
These would be good reasons to separate the `client`, `network`, and `server`
modules from *src/lib.rs* and place them into their own files.
First, lets replace the `client` module code with only the declaration of the
`client` module so that *src/lib.rs* looks like code shown in Listing 7-4:
<span class="filename">Filename: src/lib.rs</span>
```rust,ignore
mod client;
mod network {
fn connect() {
}
mod server {
fn connect() {
}
}
}
```
<span class="caption">Listing 7-4: Extracting the contents of the `client` module but leaving the declaration in *src/lib.rs*</span>
Were still *declaring* the `client` module here, but by replacing the block
with a semicolon, were telling Rust to look in another location for the code
defined within the scope of the `client` module. In other words, the line `mod
client;` means this:
```rust,ignore
mod client {
// contents of client.rs
}
```
Now we need to create the external file with that module name. Create a
*client.rs* file in your *src/* directory and open it. Then enter the
following, which is the `connect` function in the `client` module that we
removed in the previous step:
<span class="filename">Filename: src/client.rs</span>
```rust
fn connect() {
}
```
Note that we dont need a `mod` declaration in this file 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,
wed 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 cant
be defined in *src/client.rs*.
Now the project should compile successfully, although youll get a few
warnings. Remember to use `cargo build` instead of `cargo run` because 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`
--> src/client.rs:1:1
|
1 | / fn connect() {
2 | | }
| |_^
|
= note: #[warn(dead_code)] on by default
warning: function is never used: `connect`
--> src/lib.rs:4:5
|
4 | / fn connect() {
5 | | }
| |_____^
warning: function is never used: `connect`
--> src/lib.rs:8:9
|
8 | / fn connect() {
9 | | }
| |_________^
```
These warnings tell us that we have functions that are never used. Dont worry
about these warnings for now; well address them later in this chapter in the
“Controlling Visibility with `pub`” section. The good news is that theyre just
warnings; our project built successfully!
Next, lets extract the `network` module into its own file using the same
pattern. In *src/lib.rs*, delete the body of the `network` module and add a
semicolon to the declaration, like so:
<span class="filename">Filename: src/lib.rs</span>
```rust,ignore
mod client;
mod network;
```
Then create a new *src/network.rs* file and enter the following:
<span class="filename">Filename: src/network.rs</span>
```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 submodule of `network`.
Run `cargo build` again. Success! We have one more module to extract: `server`.
Because its a submodule—that is, a module within a module—our current tactic
of extracting a module into a file named after that module wont work. Well
try anyway so you can see the error. First, change *src/network.rs* to have
`mod server;` instead of the `server` modules contents:
<span class="filename">Filename: src/network.rs</span>
```rust,ignore
fn connect() {
}
mod server;
```
Then create a *src/server.rs* file and enter the contents of the `server`
module that we extracted:
<span class="filename">Filename: src/server.rs</span>
```rust
fn connect() {
}
```
When we try to `cargo build`, well get the error shown in Listing 7-5:
```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 `src/network.rs` to its own directory via `src/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;
| ^^^^^^
```
<span class="caption">Listing 7-5: Error when trying to extract the `server`
submodule into *src/server.rs*</span>
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: keep reading to understand why.
The note in the middle of Listing 7-5 is actually very helpful because it
points out something we havent 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 modules name.
2. Move the *src/network.rs* file into the new *network* directory and
rename it *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 when we try to run `cargo build`, compilation will work (well still have
warnings though). Our module layout still looks exactly the same as it did when
we had all the code in *src/lib.rs* in Listing 7-3:
```text
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 to the *src/network/mod.rs* file and put
the code for `network::server` in the *network* directory in
*src/network/server.rs*? Why couldnt we just extract the `network::server`
module into *src/server.rs*? The reason is that Rust wouldnt be able to
recognize that `server` was supposed to be a submodule of `network` if the
*server.rs* file was in the *src* directory. To clarify Rusts behavior here,
lets 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`. Following the same steps we did earlier for extracting
modules into files, we would create *src/client.rs* for the `client` module.
For the `network` module, we would create *src/network.rs*. But we wouldnt 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 could put
the code for *both* the `client` and `network::client` modules in the
*src/client.rs* file, Rust wouldnt have any way to know whether the code was
for `client` or for `network::client`.
Therefore, in order 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 Filesystems
Lets summarize the rules of modules with regard 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 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 should be declared in their parent modules file using the `mod`
keyword.
Next, well talk about the `pub` keyword and get rid of those warnings!

View File

@ -0,0 +1,288 @@
## Controlling Visibility with `pub`
We resolved the error messages shown in Listing 7-5 by moving the `network` and
`network::server` code into the *src/network/mod.rs* and
*src/network/server.rs* files, respectively. At that point, `cargo build` was
able to build our project, but we still get warning messages about the
`client::connect`, `network::connect`, and `network::server::connect` functions
not being used.
So why are we receiving these warnings? After all, were building a library
with functions that are intended to be used by our *users*, not necessarily by
us within our own project, so it shouldnt matter that these `connect`
functions go unused. The point of creating them is that they will be used by
another project, not our own.
To understand why this program invokes these warnings, lets try using the
`communicator` library from another project, calling it externally. To do that,
well create a binary crate in the same directory as our library crate by
making a *src/main.rs* file containing this code:
<span class="filename">Filename: src/main.rs</span>
```rust,ignore
extern crate communicator;
fn main() {
communicator::client::connect();
}
```
We use the `extern crate` command to bring the `communicator` library crate
into scope. Our package 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. As a result, other programs can also use the
library crate, and its a nice separation of concerns.
From the point of view of a crate outside the `communicator` library looking
in, all the modules weve 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 were 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.
Right now, our binary crate just calls our librarys `connect` function from
the `client` module. However, invoking `cargo build` will now give us an error
after the warnings:
```text
error[E0603]: module `client` is private
--> src/main.rs:4:5
|
4 | communicator::client::connect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```
Ah ha! This error tells us that the `client` module is private, which is the
crux of the warnings. Its also the first time weve 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 dont use a
private function within your program, because your program is the only code
allowed to use that function, Rust will warn you that the function has gone
unused.
After you specify that a function such as `client::connect` is public, not only
will your call to that function from your binary crate be allowed, but also the
warning that the function is unused will go away. Marking a function as public
lets Rust know that the function will be used by code outside of your program.
Rust considers the theoretical external usage thats now possible as the
function “being used.” Thus, when a function is marked public, Rust will not
require that it be used in your program and will stop warning that the function
is unused.
### Making a Function Public
To tell Rust to make a function public, we add the `pub` keyword to the start
of the declaration. Well focus on fixing the warning that indicates
`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:
<span class="filename">Filename: src/lib.rs</span>
```rust,ignore
pub mod client;
mod network;
```
The `pub` keyword is placed right before `mod`. Lets try building again:
```text
error[E0603]: 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 shows `` function `connect` is private ``, so
lets edit *src/client.rs* to make `client::connect` public too:
<span class="filename">Filename: src/client.rs</span>
```rust
pub fn connect() {
}
```
Now run `cargo build` again:
```text
warning: function is never used: `connect`
--> src/network/mod.rs:1:1
|
1 | / fn connect() {
2 | | }
| |_^
|
= note: #[warn(dead_code)] on by default
warning: function is never used: `connect`
--> src/network/server.rs:1:1
|
1 | / fn connect() {
2 | | }
| |_^
```
The code compiled, and the warning that `client::connect` is not being used is
gone!
Unused code warnings dont always indicate that an item in your code needs to
be made public: if you *didnt* want these functions to be part of your public
API, unused code warnings could be alerting you to code you no longer need that
you 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.
But in this case, we *do* want the other two functions to be part of our
crates public API, so lets mark them as `pub` as well to get rid of the
remaining warnings. Modify *src/network/mod.rs* to look like the following:
<span class="filename">Filename: src/network/mod.rs</span>
```rust,ignore
pub fn connect() {
}
mod server;
```
Then compile the code:
```text
warning: function is never used: `connect`
--> src/network/mod.rs:1:1
|
1 | / pub fn connect() {
2 | | }
| |_^
|
= note: #[warn(dead_code)] on by default
warning: function is never used: `connect`
--> src/network/server.rs:1:1
|
1 | / fn connect() {
2 | | }
| |_^
```
Hmmm, were still getting an unused function warning, even though
`network::connect` is set to `pub`. The reason is that the function is public
within the module, but the `network` module that the function resides in is not
public. Were working from the interior of the library out this time, whereas
with `client::connect` we worked from the outside in. We need to change
*src/lib.rs* to make `network` public too, like so:
<span class="filename">Filename: src/lib.rs</span>
```rust,ignore
pub mod client;
pub mod network;
```
Now when we compile, that warning is gone:
```text
warning: function is never used: `connect`
--> src/network/server.rs:1:1
|
1 | / fn connect() {
2 | | }
| |_^
|
= note: #[warn(dead_code)] on by default
```
Only one warning is left—try to fix this one on your own!
### Privacy Rules
Overall, these are the rules for item visibility:
- If an item is public, it can be accessed through any of its parent modules.
- If an item is private, it can be accessed only by its immediate parent
module and any of the parents child modules.
### Privacy Examples
Lets look at a few more privacy examples to get some practice. Create a new
library project and enter the code in Listing 7-6 into your new projects
*src/lib.rs*:
<span class="filename">Filename: src/lib.rs</span>
```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();
}
```
<span class="caption">Listing 7-6: Examples of private and public functions,
some of which are incorrect</span>
Before you try to compile this code, make a guess about which lines in the
`try_me` function will have errors. Then, try compiling the code to see whether
you were right—and read on for the 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 states that the `try_me`
function is allowed to access the `outermost` module because `outermost` is in
the current (root) module, as is `try_me`.
The call to `outermost::middle_function` will work because `middle_function` is
public and `try_me` is accessing `middle_function` through its parent module
`outermost`. We determined in the previous paragraph that this module is
accessible.
The call to `outermost::middle_secret_function` will cause a compilation error.
Because `middle_secret_function` is private, 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 be
accessed only 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`.
#### Fixing the Errors
Here are some suggestions for changing the code in an attempt to fix the
errors. Make a guess as to whether it will fix the errors before you try each
one. Then compile the code to see whether or not youre right, using the
privacy rules to understand why. Feel free to design more experiments and try
them out!
* What if the `inside` module were public?
* What if `outermost` were public and `inside` were 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.)
Next, lets talk about bringing items into scope with the `use` keyword.

View File

@ -0,0 +1,271 @@
## Referring to Names in Different Modules
Weve covered how to call functions defined within a module using the module
name as part of the call, as in the call to the `nested_modules` function shown
here in Listing 7-7:
<span class="filename">Filename: src/main.rs</span>
```rust
pub mod a {
pub mod series {
pub mod of {
pub fn nested_modules() {}
}
}
}
fn main() {
a::series::of::nested_modules();
}
```
<span class="caption">Listing 7-7: Calling a function by fully specifying its
enclosing modules path</span>
As you can see, referring to the fully qualified name can get quite lengthy.
Fortunately, Rust has a keyword to make these calls more concise.
### Bringing Names into Scope with the `use` Keyword
Rusts `use` keyword shortens lengthy function calls by bringing the modules of
the function you want to call into scope. Heres an example of bringing the
`a::series::of` module into a binary crates root scope:
<span class="filename">Filename: src/main.rs</span>
```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 weve specified into scope: it does not
bring children of modules into scope. Thats why we still have to use
`of::nested_modules` when we want to call the `nested_modules` function.
We could have chosen to bring the function 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();
}
```
Doing so allows us to exclude all the modules and reference the function
directly.
Because enums also form a sort of namespace like modules, we can bring an
enums variants into scope with `use` as well. For any kind of `use` statement,
if youre bringing multiple items from one namespace into scope, you can list
them using curly brackets 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;
}
```
Were still specifying the `TrafficLight` namespace for the `Green` variant
because we didnt include `Green` in the `use` statement.
### Bringing All Names into Scope with a Glob
To bring all the items in a namespace into scope at once, we can use the `*`
syntax, which is called the *glob operator*. This example brings all the
variants of an enum into scope without having to list each specifically:
```rust
enum TrafficLight {
Red,
Yellow,
Green,
}
use TrafficLight::*;
fn main() {
let red = Red;
let yellow = Yellow;
let green = Green;
}
```
The `*` will bring into scope all the visible items in the `TrafficLight`
namespace. You should use globs sparingly: they are convenient, but a glob
might also pull in more items than you expected and cause naming conflicts.
### Using `super` to Access a Parent Module
As you saw at the beginning of this chapter, when you create a library crate,
Cargo makes a `tests` module for you. Lets go into more detail about that now.
In your `communicator` project, open *src/lib.rs*:
<span class="filename">Filename: src/lib.rs</span>
```rust,ignore
pub mod client;
pub mod network;
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
```
Chapter 11 explains more about testing, but parts of this example 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 lets try to call our
`client::connect` function from this `it_works` function, even though we wont
be checking any functionality right now. This wont work yet:
<span class="filename">Filename: src/lib.rs</span>
```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`
```
The compilation failed, but why? We dont need to place `communicator::` in
front of the function, as 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 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, like this:
```rust,ignore
::client::connect();
```
Or, we can use `super` to move up one module in the hierarchy from our current
module, like this:
```rust,ignore
super::client::connect();
```
These two options dont look that different in this example, but if youre
deeper in a module hierarchy, starting from the root every time would make your
code lengthy. In those cases, using `super` to get from the current module to
sibling modules is a good shortcut. Plus, if youve specified the path from the
root in many places in your code and then rearrange your modules by moving a
subtree to another place, youll end up needing to update the path in several
places, which would be tedious.
It would also be annoying to have to type `super::` in each test, but youve
already seen the tool for that solution: `use`! The `super::` functionality
changes the path you give to `use` so 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 best solution. So now our test looks like this:
<span class="filename">Filename: src/lib.rs</span>
```rust
#[cfg(test)]
mod tests {
use super::client;
#[test]
fn it_works() {
client::connect();
}
}
```
When we run `cargo test` again, the test will pass, and the first part of the
test result output will be the following:
```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; 0 filtered out
```
## Summary
Now you know some new techniques for organizing your code! Use these techniques
to group related functionality together, keep files from becoming too long, and
present a tidy public API to your library users.
Next, well look at some collection data structures in the standard library
that you can use in your nice, neat code.

Some files were not shown because too many files have changed in this diff Show More