mirror of
https://git.proxmox.com/git/rustc
synced 2025-08-02 22:09:09 +00:00
New upstream version 1.31.0~beta.4+dfsg1
This commit is contained in:
parent
4462d4a060
commit
0bf4aa26bc
@ -566,7 +566,7 @@ labels to triage issues:
|
||||
to fix the issue.
|
||||
|
||||
* The dark blue **final-comment-period** label marks bugs that are using the
|
||||
RFC signoff functionality of [rfcbot][rfcbot] and are currenty in the final
|
||||
RFC signoff functionality of [rfcbot][rfcbot] and are currently in the final
|
||||
comment period.
|
||||
|
||||
* Red, **I**-prefixed labels indicate the **importance** of the issue. The
|
||||
@ -646,7 +646,7 @@ are:
|
||||
* Don't be afraid to ask! The Rust community is friendly and helpful.
|
||||
|
||||
[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/about-this-guide.html
|
||||
[gdfrustc]: http://manishearth.github.io/rust-internals-docs/rustc/
|
||||
[gdfrustc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/
|
||||
[gsearchdocs]: https://www.google.com/search?q=site:doc.rust-lang.org+your+query+here
|
||||
[rif]: http://internals.rust-lang.org
|
||||
[rr]: https://doc.rust-lang.org/book/README.html
|
||||
|
@ -64,9 +64,6 @@ Cargo
|
||||
- [`cargo run` doesn't require specifying a package in workspaces.][cargo/5877]
|
||||
- [`cargo doc` now supports `--message-format=json`.][cargo/5878] This is
|
||||
equivalent to calling `rustdoc --error-format=json`.
|
||||
- [You can specify which edition to create a project in cargo
|
||||
with `cargo new --edition`.][cargo/5984] Currently only `2015` is a
|
||||
valid option.
|
||||
- [Cargo will now provide a progress bar for builds.][cargo/5995]
|
||||
|
||||
Misc
|
||||
@ -100,9 +97,8 @@ Misc
|
||||
[54404]: https://github.com/rust-lang/rust/pull/54404/
|
||||
[cargo/5877]: https://github.com/rust-lang/cargo/pull/5877/
|
||||
[cargo/5878]: https://github.com/rust-lang/cargo/pull/5878/
|
||||
[cargo/5984]: https://github.com/rust-lang/cargo/pull/5984/
|
||||
[cargo/5995]: https://github.com/rust-lang/cargo/pull/5995/
|
||||
[proc-macros]: https://doc.rust-lang.org/book/2018-edition/ch19-06-macros.html
|
||||
[proc-macros]: https://doc.rust-lang.org/stable/book/2018-edition/ch19-06-macros.html
|
||||
|
||||
[`Ipv4Addr::BROADCAST`]: https://doc.rust-lang.org/nightly/std/net/struct.Ipv4Addr.html#associatedconstant.BROADCAST
|
||||
[`Ipv4Addr::LOCALHOST`]: https://doc.rust-lang.org/nightly/std/net/struct.Ipv4Addr.html#associatedconstant.LOCALHOST
|
||||
|
@ -182,10 +182,9 @@
|
||||
# Build the profiler runtime
|
||||
#profiler = false
|
||||
|
||||
# Indicates whether the OpenSSL linked into Cargo will be statically linked or
|
||||
# not. If static linkage is specified then the build system will download a
|
||||
# known-good version of OpenSSL, compile it, and link it to Cargo.
|
||||
#openssl-static = false
|
||||
# Indicates whether the native libraries linked into Cargo will be statically
|
||||
# linked or not.
|
||||
#cargo-native-static = false
|
||||
|
||||
# Run the build with low priority, by setting the process group's "nice" value
|
||||
# to +10 on Unix platforms, and by using a "low priority" job object on Windows.
|
||||
@ -243,19 +242,36 @@
|
||||
# =============================================================================
|
||||
[rust]
|
||||
|
||||
# Indicates that the build should be optimized for debugging Rust. Note that
|
||||
# this is typically not what you want as it takes an incredibly large amount of
|
||||
# time to have a debug-mode rustc compile any code (notably libstd). If this
|
||||
# value is set to `true` it will affect a number of configuration options below
|
||||
# as well, if unconfigured.
|
||||
#debug = false
|
||||
|
||||
# Whether or not to optimize the compiler and standard library
|
||||
# Whether or not to optimize the compiler and standard library.
|
||||
#
|
||||
# Note: the slowness of the non optimized compiler compiling itself usually
|
||||
# outweighs the time gains in not doing optimizations, therefore a
|
||||
# full bootstrap takes much more time with optimize set to false.
|
||||
# full bootstrap takes much more time with `optimize` set to false.
|
||||
#optimize = true
|
||||
|
||||
# Indicates that the build should be configured for debugging Rust. A
|
||||
# `debug`-enabled compiler and standard library will be somewhat
|
||||
# slower (due to e.g. checking of debug assertions) but should remain
|
||||
# usable.
|
||||
#
|
||||
# Note: If this value is set to `true`, it will affect a number of
|
||||
# configuration options below as well, if they have been left
|
||||
# unconfigured in this file.
|
||||
#
|
||||
# Note: changes to the `debug` setting do *not* affect `optimize`
|
||||
# above. In theory, a "maximally debuggable" environment would
|
||||
# set `optimize` to `false` above to assist the introspection
|
||||
# facilities of debuggers like lldb and gdb. To recreate such an
|
||||
# environment, explicitly set `optimize` to `false` and `debug`
|
||||
# to `true`. In practice, everyone leaves `optimize` set to
|
||||
# `true`, because an unoptimized rustc with debugging
|
||||
# enabled becomes *unusably slow* (e.g. rust-lang/rust#24840
|
||||
# reported a 25x slowdown) and bootstrapping the supposed
|
||||
# "maximally debuggable" environment (notably libstd) takes
|
||||
# hours to build.
|
||||
#
|
||||
#debug = false
|
||||
|
||||
# Number of codegen units to use for each compiler invocation. A value of 0
|
||||
# means "the number of cores on this machine", and 1+ is passed through to the
|
||||
# compiler.
|
||||
@ -322,6 +338,7 @@
|
||||
|
||||
# Flag indicating whether codegen tests will be run or not. If you get an error
|
||||
# saying that the FileCheck executable is missing, you may want to disable this.
|
||||
# Also see the target's llvm-filecheck option.
|
||||
#codegen-tests = true
|
||||
|
||||
# Flag indicating whether git info will be retrieved from .git automatically.
|
||||
@ -416,6 +433,10 @@
|
||||
# target.
|
||||
#llvm-config = "../path/to/llvm/root/bin/llvm-config"
|
||||
|
||||
# Normally the build system can find LLVM's FileCheck utility, but if
|
||||
# not, you can specify an explicit file name for it.
|
||||
#llvm-filecheck = "/path/to/FileCheck"
|
||||
|
||||
# Path to the custom jemalloc static library to link into the standard library
|
||||
# by default. This is only used if jemalloc is still enabled above
|
||||
#jemalloc = "/path/to/jemalloc/libjemalloc_pic.a"
|
||||
@ -476,3 +497,7 @@
|
||||
# as the one built on Windows will contain backslashes in paths causing problems
|
||||
# on linux
|
||||
#src-tarball = true
|
||||
#
|
||||
|
||||
# Whether to allow failures when building tools
|
||||
#missing-tools = false
|
||||
|
@ -1 +1 @@
|
||||
da5f414c2c0bfe5198934493f04c676e2b23ff2e
|
||||
04da282bb42d12e4e6fa0ee2742f3c7c95866773
|
639
src/Cargo.lock
generated
639
src/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -64,3 +64,4 @@ rustc-workspace-hack = { path = 'tools/rustc-workspace-hack' }
|
||||
|
||||
[patch."https://github.com/rust-lang-nursery/rust-clippy"]
|
||||
clippy_lints = { path = "tools/clippy/clippy_lints" }
|
||||
rustc_tools_util = { path = "tools/clippy/rustc_tools_util" }
|
||||
|
@ -287,10 +287,6 @@ fn main() {
|
||||
cmd.arg("--cfg").arg("parallel_queries");
|
||||
}
|
||||
|
||||
if env::var_os("RUSTC_VERIFY_LLVM_IR").is_some() {
|
||||
cmd.arg("-Z").arg("verify-llvm-ir");
|
||||
}
|
||||
|
||||
if env::var_os("RUSTC_DENY_WARNINGS").is_some() && env::var_os("RUSTC_EXTERNAL_TOOL").is_none()
|
||||
{
|
||||
cmd.arg("-Dwarnings");
|
||||
|
@ -594,7 +594,7 @@ class RustBuild(object):
|
||||
return ''
|
||||
|
||||
def bootstrap_binary(self):
|
||||
"""Return the path of the boostrap binary
|
||||
"""Return the path of the bootstrap binary
|
||||
|
||||
>>> rb = RustBuild()
|
||||
>>> rb.build_dir = "build"
|
||||
@ -844,6 +844,11 @@ def bootstrap(help_triggered):
|
||||
def main():
|
||||
"""Entry point for the bootstrap process"""
|
||||
start_time = time()
|
||||
|
||||
# x.py help <cmd> ...
|
||||
if len(sys.argv) > 1 and sys.argv[1] == 'help':
|
||||
sys.argv = sys.argv[:1] + [sys.argv[2], '-h'] + sys.argv[3:]
|
||||
|
||||
help_triggered = (
|
||||
'-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1)
|
||||
try:
|
||||
|
@ -379,7 +379,6 @@ impl<'a> Builder<'a> {
|
||||
test::Ui,
|
||||
test::RunPass,
|
||||
test::CompileFail,
|
||||
test::ParseFail,
|
||||
test::RunFail,
|
||||
test::RunPassValgrind,
|
||||
test::MirOpt,
|
||||
@ -1000,10 +999,6 @@ impl<'a> Builder<'a> {
|
||||
cargo.env("RUSTC_BACKTRACE_ON_ICE", "1");
|
||||
}
|
||||
|
||||
if self.config.rust_verify_llvm_ir {
|
||||
cargo.env("RUSTC_VERIFY_LLVM_IR", "1");
|
||||
}
|
||||
|
||||
cargo.env("RUSTC_VERBOSE", self.verbosity.to_string());
|
||||
|
||||
// in std, we want to avoid denying warnings for stage 0 as that makes cfg's painful.
|
||||
|
@ -169,19 +169,21 @@ impl Ord for Interned<String> {
|
||||
}
|
||||
}
|
||||
|
||||
struct TyIntern<T> {
|
||||
struct TyIntern<T: Hash + Clone + Eq> {
|
||||
items: Vec<T>,
|
||||
set: HashMap<T, Interned<T>>,
|
||||
}
|
||||
|
||||
impl<T: Hash + Clone + Eq> TyIntern<T> {
|
||||
fn new() -> TyIntern<T> {
|
||||
impl<T: Hash + Clone + Eq> Default for TyIntern<T> {
|
||||
fn default() -> Self {
|
||||
TyIntern {
|
||||
items: Vec::new(),
|
||||
set: HashMap::new(),
|
||||
set: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Hash + Clone + Eq> TyIntern<T> {
|
||||
fn intern_borrow<B>(&mut self, item: &B) -> Interned<T>
|
||||
where
|
||||
B: Eq + Hash + ToOwned<Owned=T> + ?Sized,
|
||||
@ -212,19 +214,13 @@ impl<T: Hash + Clone + Eq> TyIntern<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Interner {
|
||||
strs: Mutex<TyIntern<String>>,
|
||||
paths: Mutex<TyIntern<PathBuf>>,
|
||||
}
|
||||
|
||||
impl Interner {
|
||||
fn new() -> Interner {
|
||||
Interner {
|
||||
strs: Mutex::new(TyIntern::new()),
|
||||
paths: Mutex::new(TyIntern::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intern_str(&self, s: &str) -> Interned<String> {
|
||||
self.strs.lock().unwrap().intern_borrow(s)
|
||||
}
|
||||
@ -238,7 +234,7 @@ impl Interner {
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref INTERNER: Interner = Interner::new();
|
||||
pub static ref INTERNER: Interner = Interner::default();
|
||||
}
|
||||
|
||||
/// This is essentially a HashMap which allows storing any type in its input and
|
||||
|
@ -24,7 +24,7 @@ use Build;
|
||||
use config::Config;
|
||||
|
||||
// The version number
|
||||
pub const CFG_RELEASE_NUM: &str = "1.30.0";
|
||||
pub const CFG_RELEASE_NUM: &str = "1.31.0";
|
||||
|
||||
pub struct GitInfo {
|
||||
inner: Option<Info>,
|
||||
|
@ -224,7 +224,8 @@ impl Step for Rustdoc {
|
||||
target,
|
||||
"check",
|
||||
"src/tools/rustdoc",
|
||||
SourceType::InTree);
|
||||
SourceType::InTree,
|
||||
&[]);
|
||||
|
||||
let _folder = builder.fold_output(|| format!("stage{}-rustdoc", compiler.stage));
|
||||
println!("Checking rustdoc artifacts ({} -> {})", &compiler.host, target);
|
||||
|
@ -249,7 +249,7 @@ impl Step for StdLink {
|
||||
|
||||
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 filename = format!("lib__rustc__clang_rt.{}_{}_dynamic.dylib", sanitizer, platform);
|
||||
let mut src_path = native_dir.join(sanitizer);
|
||||
src_path.push("build");
|
||||
src_path.push("lib");
|
||||
@ -569,6 +569,9 @@ pub fn rustc_cargo_env(builder: &Builder, cargo: &mut Command) {
|
||||
if builder.config.rustc_parallel_queries {
|
||||
cargo.env("RUSTC_PARALLEL_QUERIES", "1");
|
||||
}
|
||||
if builder.config.rust_verify_llvm_ir {
|
||||
cargo.env("RUSTC_VERIFY_LLVM_IR", "1");
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -134,6 +134,7 @@ pub struct Config {
|
||||
pub test_miri: bool,
|
||||
pub save_toolstates: Option<PathBuf>,
|
||||
pub print_step_timings: bool,
|
||||
pub missing_tools: bool,
|
||||
|
||||
// Fallback musl-root for all targets
|
||||
pub musl_root: Option<PathBuf>,
|
||||
@ -148,7 +149,7 @@ pub struct Config {
|
||||
pub nodejs: Option<PathBuf>,
|
||||
pub gdb: Option<PathBuf>,
|
||||
pub python: Option<PathBuf>,
|
||||
pub openssl_static: bool,
|
||||
pub cargo_native_static: bool,
|
||||
pub configure_args: Vec<String>,
|
||||
|
||||
// These are either the stage0 downloaded binaries or the locally installed ones.
|
||||
@ -162,6 +163,8 @@ pub struct Config {
|
||||
pub struct Target {
|
||||
/// Some(path to llvm-config) if using an external LLVM.
|
||||
pub llvm_config: Option<PathBuf>,
|
||||
/// Some(path to FileCheck) if one was specified.
|
||||
pub llvm_filecheck: Option<PathBuf>,
|
||||
pub jemalloc: Option<PathBuf>,
|
||||
pub cc: Option<PathBuf>,
|
||||
pub cxx: Option<PathBuf>,
|
||||
@ -218,7 +221,7 @@ struct Build {
|
||||
verbose: Option<usize>,
|
||||
sanitizers: Option<bool>,
|
||||
profiler: Option<bool>,
|
||||
openssl_static: Option<bool>,
|
||||
cargo_native_static: Option<bool>,
|
||||
configure_args: Option<Vec<String>>,
|
||||
local_rebuild: Option<bool>,
|
||||
print_step_timings: Option<bool>,
|
||||
@ -269,6 +272,7 @@ struct Dist {
|
||||
gpg_password_file: Option<String>,
|
||||
upload_addr: Option<String>,
|
||||
src_tarball: Option<bool>,
|
||||
missing_tools: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@ -330,6 +334,7 @@ struct Rust {
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
struct TomlTarget {
|
||||
llvm_config: Option<String>,
|
||||
llvm_filecheck: Option<String>,
|
||||
jemalloc: Option<String>,
|
||||
cc: Option<String>,
|
||||
cxx: Option<String>,
|
||||
@ -372,6 +377,7 @@ impl Config {
|
||||
config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
|
||||
config.rust_codegen_backends_dir = "codegen-backends".to_owned();
|
||||
config.deny_warnings = true;
|
||||
config.missing_tools = false;
|
||||
|
||||
// set by bootstrap.py
|
||||
config.build = INTERNER.intern_str(&env::var("BUILD").expect("'BUILD' to be set"));
|
||||
@ -424,7 +430,7 @@ impl Config {
|
||||
}
|
||||
}).unwrap_or_else(|| TomlConfig::default());
|
||||
|
||||
let build = toml.build.clone().unwrap_or(Build::default());
|
||||
let build = toml.build.clone().unwrap_or_default();
|
||||
// set by bootstrap.py
|
||||
config.hosts.push(config.build.clone());
|
||||
for host in build.host.iter() {
|
||||
@ -468,7 +474,7 @@ impl Config {
|
||||
set(&mut config.verbose, build.verbose);
|
||||
set(&mut config.sanitizers, build.sanitizers);
|
||||
set(&mut config.profiler, build.profiler);
|
||||
set(&mut config.openssl_static, build.openssl_static);
|
||||
set(&mut config.cargo_native_static, build.cargo_native_static);
|
||||
set(&mut config.configure_args, build.configure_args);
|
||||
set(&mut config.local_rebuild, build.local_rebuild);
|
||||
set(&mut config.print_step_timings, build.print_step_timings);
|
||||
@ -518,7 +524,7 @@ impl Config {
|
||||
set(&mut config.llvm_link_shared, llvm.link_shared);
|
||||
config.llvm_targets = llvm.targets.clone();
|
||||
config.llvm_experimental_targets = llvm.experimental_targets.clone()
|
||||
.unwrap_or("WebAssembly;RISCV".to_string());
|
||||
.unwrap_or_else(|| "WebAssembly;RISCV".to_string());
|
||||
config.llvm_link_jobs = llvm.link_jobs;
|
||||
config.llvm_version_suffix = llvm.version_suffix.clone();
|
||||
config.llvm_clang_cl = llvm.clang_cl.clone();
|
||||
@ -583,6 +589,9 @@ impl Config {
|
||||
if let Some(ref s) = cfg.llvm_config {
|
||||
target.llvm_config = Some(config.src.join(s));
|
||||
}
|
||||
if let Some(ref s) = cfg.llvm_filecheck {
|
||||
target.llvm_filecheck = Some(config.src.join(s));
|
||||
}
|
||||
if let Some(ref s) = cfg.jemalloc {
|
||||
target.jemalloc = Some(config.src.join(s));
|
||||
}
|
||||
@ -607,6 +616,7 @@ impl Config {
|
||||
config.dist_gpg_password_file = t.gpg_password_file.clone().map(PathBuf::from);
|
||||
config.dist_upload_addr = t.upload_addr.clone();
|
||||
set(&mut config.rust_dist_src, t.src_tarball);
|
||||
set(&mut config.missing_tools, t.missing_tools);
|
||||
}
|
||||
|
||||
// Now that we've reached the end of our configuration, infer the
|
||||
@ -618,6 +628,9 @@ impl Config {
|
||||
let default = false;
|
||||
config.llvm_assertions = llvm_assertions.unwrap_or(default);
|
||||
|
||||
let default = true;
|
||||
config.rust_optimize = optimize.unwrap_or(default);
|
||||
|
||||
let default = match &config.channel[..] {
|
||||
"stable" | "beta" | "nightly" => true,
|
||||
_ => false,
|
||||
@ -630,7 +643,6 @@ impl Config {
|
||||
config.debug_jemalloc = debug_jemalloc.unwrap_or(default);
|
||||
config.rust_debuginfo = debuginfo.unwrap_or(default);
|
||||
config.rust_debug_assertions = debug_assertions.unwrap_or(default);
|
||||
config.rust_optimize = optimize.unwrap_or(!default);
|
||||
|
||||
let default = config.channel == "dev";
|
||||
config.ignore_git = ignore_git.unwrap_or(default);
|
||||
|
@ -64,11 +64,12 @@ o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date")
|
||||
o("vendor", "build.vendor", "enable usage of vendored Rust crates")
|
||||
o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan)")
|
||||
o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball")
|
||||
o("cargo-openssl-static", "build.openssl-static", "static openssl in cargo")
|
||||
o("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo")
|
||||
o("profiler", "build.profiler", "build the profiler runtime")
|
||||
o("emscripten", None, "compile the emscripten backend as well as LLVM")
|
||||
o("full-tools", None, "enable all tools")
|
||||
o("lldb", "rust.lldb", "build lldb")
|
||||
o("missing-tools", "dist.missing-tools", "allow failures when building tools")
|
||||
|
||||
# Optimization and debugging options. These may be overridden by the release
|
||||
# channel, etc.
|
||||
@ -95,6 +96,8 @@ v("docdir", "install.docdir", "install documentation in PATH")
|
||||
v("bindir", "install.bindir", "install binaries")
|
||||
|
||||
v("llvm-root", None, "set LLVM root")
|
||||
v("llvm-config", None, "set path to llvm-config")
|
||||
v("llvm-filecheck", None, "set path to LLVM's FileCheck utility")
|
||||
v("python", "build.python", "set path to python")
|
||||
v("jemalloc-root", None, "set directory where libjemalloc_pic.a is located")
|
||||
v("android-cross-path", "target.arm-linux-androideabi.android-ndk",
|
||||
@ -323,6 +326,10 @@ for key in known_args:
|
||||
set('build.cargo', value + '/bin/cargo')
|
||||
elif option.name == 'llvm-root':
|
||||
set('target.{}.llvm-config'.format(build()), value + '/bin/llvm-config')
|
||||
elif option.name == 'llvm-config':
|
||||
set('target.{}.llvm-config'.format(build()), value)
|
||||
elif option.name == 'llvm-filecheck':
|
||||
set('target.{}.llvm-filecheck'.format(build()), value)
|
||||
elif option.name == 'jemalloc-root':
|
||||
set('target.{}.jemalloc'.format(build()), value + '/libjemalloc_pic.a')
|
||||
elif option.name == 'tools':
|
||||
|
@ -31,7 +31,6 @@ use channel;
|
||||
use util::{libdir, is_dylib, exe};
|
||||
use builder::{Builder, RunConfig, ShouldRun, Step};
|
||||
use compile;
|
||||
use native;
|
||||
use tool::{self, Tool};
|
||||
use cache::{INTERNER, Interned};
|
||||
use time;
|
||||
@ -67,6 +66,14 @@ fn rust_installer(builder: &Builder) -> Command {
|
||||
builder.tool_cmd(Tool::RustInstaller)
|
||||
}
|
||||
|
||||
fn missing_tool(tool_name: &str, skip: bool) {
|
||||
if skip {
|
||||
println!("Unable to build {}, skipping dist", tool_name)
|
||||
} else {
|
||||
panic!("Unable to build {}", tool_name)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Docs {
|
||||
pub stage: u32,
|
||||
@ -982,12 +989,6 @@ impl Step for PlainSourceTarball {
|
||||
.arg("--debug")
|
||||
.arg("--vers").arg(CARGO_VENDOR_VERSION)
|
||||
.arg("cargo-vendor");
|
||||
if let Some(dir) = builder.openssl_install_dir(builder.config.build) {
|
||||
builder.ensure(native::Openssl {
|
||||
target: builder.config.build,
|
||||
});
|
||||
cmd.env("OPENSSL_DIR", dir);
|
||||
}
|
||||
builder.run(&mut cmd);
|
||||
}
|
||||
|
||||
@ -1166,7 +1167,7 @@ impl Step for Rls {
|
||||
let rls = builder.ensure(tool::Rls {
|
||||
compiler: builder.compiler(stage, builder.config.build),
|
||||
target, extra_features: Vec::new()
|
||||
}).or_else(|| { println!("Unable to build RLS, skipping dist"); None })?;
|
||||
}).or_else(|| { missing_tool("RLS", builder.build.config.missing_tools); None })?;
|
||||
|
||||
builder.install(&rls, &image.join("bin"), 0o755);
|
||||
let doc = image.join("share/doc/rls");
|
||||
@ -1245,24 +1246,26 @@ impl Step for Clippy {
|
||||
let clippy = builder.ensure(tool::Clippy {
|
||||
compiler: builder.compiler(stage, builder.config.build),
|
||||
target, extra_features: Vec::new()
|
||||
}).or_else(|| { println!("Unable to build clippy, skipping dist"); None })?;
|
||||
}).or_else(|| { missing_tool("clippy", builder.build.config.missing_tools); None })?;
|
||||
let cargoclippy = builder.ensure(tool::CargoClippy {
|
||||
compiler: builder.compiler(stage, builder.config.build),
|
||||
target, extra_features: Vec::new()
|
||||
}).or_else(|| { println!("Unable to build cargo clippy, skipping dist"); None })?;
|
||||
}).or_else(|| { missing_tool("cargo clippy", builder.build.config.missing_tools); None })?;
|
||||
|
||||
builder.install(&clippy, &image.join("bin"), 0o755);
|
||||
builder.install(&cargoclippy, &image.join("bin"), 0o755);
|
||||
let doc = image.join("share/doc/clippy");
|
||||
builder.install(&src.join("README.md"), &doc, 0o644);
|
||||
builder.install(&src.join("LICENSE"), &doc, 0o644);
|
||||
builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
|
||||
builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
|
||||
|
||||
// Prepare the overlay
|
||||
let overlay = tmp.join("clippy-overlay");
|
||||
drop(fs::remove_dir_all(&overlay));
|
||||
t!(fs::create_dir_all(&overlay));
|
||||
builder.install(&src.join("README.md"), &overlay, 0o644);
|
||||
builder.install(&src.join("LICENSE"), &doc, 0o644);
|
||||
builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
|
||||
builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
|
||||
builder.create(&overlay.join("version"), &version);
|
||||
|
||||
// Generate the installer tarball
|
||||
@ -1324,11 +1327,11 @@ impl Step for Rustfmt {
|
||||
let rustfmt = builder.ensure(tool::Rustfmt {
|
||||
compiler: builder.compiler(stage, builder.config.build),
|
||||
target, extra_features: Vec::new()
|
||||
}).or_else(|| { println!("Unable to build Rustfmt, skipping dist"); None })?;
|
||||
}).or_else(|| { missing_tool("Rustfmt", builder.build.config.missing_tools); None })?;
|
||||
let cargofmt = builder.ensure(tool::Cargofmt {
|
||||
compiler: builder.compiler(stage, builder.config.build),
|
||||
target, extra_features: Vec::new()
|
||||
}).or_else(|| { println!("Unable to build Cargofmt, skipping dist"); None })?;
|
||||
}).or_else(|| { missing_tool("Cargofmt", builder.build.config.missing_tools); None })?;
|
||||
|
||||
builder.install(&rustfmt, &image.join("bin"), 0o755);
|
||||
builder.install(&cargofmt, &image.join("bin"), 0o755);
|
||||
@ -1444,8 +1447,8 @@ impl Step for Extended {
|
||||
tarballs.extend(rls_installer.clone());
|
||||
tarballs.extend(clippy_installer.clone());
|
||||
tarballs.extend(rustfmt_installer.clone());
|
||||
tarballs.extend(llvm_tools_installer.clone());
|
||||
tarballs.extend(lldb_installer.clone());
|
||||
tarballs.extend(llvm_tools_installer);
|
||||
tarballs.extend(lldb_installer);
|
||||
tarballs.push(analysis_installer);
|
||||
tarballs.push(std_installer);
|
||||
if builder.config.docs {
|
||||
|
@ -805,6 +805,7 @@ impl Step for Rustdoc {
|
||||
"doc",
|
||||
"src/tools/rustdoc",
|
||||
SourceType::InTree,
|
||||
&[]
|
||||
);
|
||||
|
||||
cargo.env("RUSTDOCFLAGS", "--document-private-items");
|
||||
|
@ -278,10 +278,6 @@ pub struct Build {
|
||||
initial_rustc: PathBuf,
|
||||
initial_cargo: PathBuf,
|
||||
|
||||
// Probed tools at runtime
|
||||
lldb_version: Option<String>,
|
||||
lldb_python_dir: Option<String>,
|
||||
|
||||
// Runtime state filled in later on
|
||||
// C/C++ compilers and archiver for all targets
|
||||
cc: HashMap<Interned<String>, cc::Tool>,
|
||||
@ -416,8 +412,6 @@ impl Build {
|
||||
ar: HashMap::new(),
|
||||
ranlib: HashMap::new(),
|
||||
crates: HashMap::new(),
|
||||
lldb_version: None,
|
||||
lldb_python_dir: None,
|
||||
is_sudo,
|
||||
ci_env: CiEnv::current(),
|
||||
delayed_failures: RefCell::new(Vec::new()),
|
||||
@ -641,9 +635,28 @@ impl Build {
|
||||
/// Returns the path to `FileCheck` binary for the specified target
|
||||
fn llvm_filecheck(&self, target: Interned<String>) -> PathBuf {
|
||||
let target_config = self.config.target_config.get(&target);
|
||||
if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
|
||||
if let Some(s) = target_config.and_then(|c| c.llvm_filecheck.as_ref()) {
|
||||
s.to_path_buf()
|
||||
} else if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
|
||||
let llvm_bindir = output(Command::new(s).arg("--bindir"));
|
||||
Path::new(llvm_bindir.trim()).join(exe("FileCheck", &*target))
|
||||
let filecheck = Path::new(llvm_bindir.trim()).join(exe("FileCheck", &*target));
|
||||
if filecheck.exists() {
|
||||
filecheck
|
||||
} else {
|
||||
// On Fedora the system LLVM installs FileCheck in the
|
||||
// llvm subdirectory of the libdir.
|
||||
let llvm_libdir = output(Command::new(s).arg("--libdir"));
|
||||
let lib_filecheck = Path::new(llvm_libdir.trim())
|
||||
.join("llvm").join(exe("FileCheck", &*target));
|
||||
if lib_filecheck.exists() {
|
||||
lib_filecheck
|
||||
} else {
|
||||
// Return the most normal file name, even though
|
||||
// it doesn't exist, so that any error message
|
||||
// refers to that.
|
||||
filecheck
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let base = self.llvm_out(self.config.build).join("build");
|
||||
let base = if !self.config.ninja && self.config.build.contains("msvc") {
|
||||
@ -752,7 +765,7 @@ impl Build {
|
||||
|
||||
let path = match which {
|
||||
GitRepo::Rustc => {
|
||||
let sha = self.rust_info.sha().expect("failed to find sha");
|
||||
let sha = self.rust_sha().unwrap_or(channel::CFG_RELEASE_NUM);
|
||||
format!("/rustc/{}", sha)
|
||||
}
|
||||
GitRepo::Llvm => format!("/rustc/llvm"),
|
||||
@ -913,25 +926,6 @@ impl Build {
|
||||
(self.hosts.iter().any(|h| *h == target) || target == self.build)
|
||||
}
|
||||
|
||||
/// Returns the directory that OpenSSL artifacts are compiled into if
|
||||
/// configured to do so.
|
||||
fn openssl_dir(&self, target: Interned<String>) -> Option<PathBuf> {
|
||||
// OpenSSL not used on Windows
|
||||
if target.contains("windows") {
|
||||
None
|
||||
} else if self.config.openssl_static {
|
||||
Some(self.out.join(&*target).join("openssl"))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the directory that OpenSSL artifacts are installed into if
|
||||
/// configured as such.
|
||||
fn openssl_install_dir(&self, target: Interned<String>) -> Option<PathBuf> {
|
||||
self.openssl_dir(target).map(|p| p.join("install"))
|
||||
}
|
||||
|
||||
/// Given `num` in the form "a.b.c" return a "release string" which
|
||||
/// describes the release version number.
|
||||
///
|
||||
@ -1275,6 +1269,9 @@ impl Build {
|
||||
t!(fs::create_dir_all(dstdir));
|
||||
drop(fs::remove_file(&dst));
|
||||
{
|
||||
if !src.exists() {
|
||||
panic!("Error: File \"{}\" not found!", src.display());
|
||||
}
|
||||
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");
|
||||
|
@ -531,189 +531,3 @@ impl Step for TestHelpers {
|
||||
.compile("rust_test_helpers");
|
||||
}
|
||||
}
|
||||
|
||||
const OPENSSL_VERS: &'static str = "1.0.2n";
|
||||
const OPENSSL_SHA256: &'static str =
|
||||
"370babb75f278c39e0c50e8c4e7493bc0f18db6867478341a832a982fd15a8fe";
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Openssl {
|
||||
pub target: Interned<String>,
|
||||
}
|
||||
|
||||
impl Step for Openssl {
|
||||
type Output = ();
|
||||
|
||||
fn should_run(run: ShouldRun) -> ShouldRun {
|
||||
run.never()
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder) {
|
||||
if builder.config.dry_run {
|
||||
return;
|
||||
}
|
||||
let target = self.target;
|
||||
let out = match builder.openssl_dir(target) {
|
||||
Some(dir) => dir,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let stamp = out.join(".stamp");
|
||||
let mut contents = String::new();
|
||||
drop(File::open(&stamp).and_then(|mut f| f.read_to_string(&mut contents)));
|
||||
if contents == OPENSSL_VERS {
|
||||
return
|
||||
}
|
||||
t!(fs::create_dir_all(&out));
|
||||
|
||||
let name = format!("openssl-{}.tar.gz", OPENSSL_VERS);
|
||||
let tarball = out.join(&name);
|
||||
if !tarball.exists() {
|
||||
let tmp = tarball.with_extension("tmp");
|
||||
// originally from https://www.openssl.org/source/...
|
||||
let url = format!("https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/{}",
|
||||
name);
|
||||
let mut last_error = None;
|
||||
for _ in 0..3 {
|
||||
let status = Command::new("curl")
|
||||
.arg("-o").arg(&tmp)
|
||||
.arg("-f") // make curl fail if the URL does not return HTTP 200
|
||||
.arg(&url)
|
||||
.status()
|
||||
.expect("failed to spawn curl");
|
||||
|
||||
// Retry if download failed.
|
||||
if !status.success() {
|
||||
last_error = Some(status.to_string());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ensure the hash is correct.
|
||||
let mut shasum = if target.contains("apple") ||
|
||||
builder.config.build.contains("netbsd") {
|
||||
let mut cmd = Command::new("shasum");
|
||||
cmd.arg("-a").arg("256");
|
||||
cmd
|
||||
} else {
|
||||
Command::new("sha256sum")
|
||||
};
|
||||
let output = output(&mut shasum.arg(&tmp));
|
||||
let found = output.split_whitespace().next().unwrap();
|
||||
|
||||
// If the hash is wrong, probably the download is incomplete or S3 served an error
|
||||
// page. In any case, retry.
|
||||
if found != OPENSSL_SHA256 {
|
||||
last_error = Some(format!(
|
||||
"downloaded openssl sha256 different\n\
|
||||
expected: {}\n\
|
||||
found: {}\n",
|
||||
OPENSSL_SHA256,
|
||||
found
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Everything is fine, so exit the retry loop.
|
||||
last_error = None;
|
||||
break;
|
||||
}
|
||||
if let Some(error) = last_error {
|
||||
panic!("failed to download openssl source: {}", error);
|
||||
}
|
||||
t!(fs::rename(&tmp, &tarball));
|
||||
}
|
||||
let obj = out.join(format!("openssl-{}", OPENSSL_VERS));
|
||||
let dst = builder.openssl_install_dir(target).unwrap();
|
||||
drop(fs::remove_dir_all(&obj));
|
||||
drop(fs::remove_dir_all(&dst));
|
||||
builder.run(Command::new("tar").arg("zxf").arg(&tarball).current_dir(&out));
|
||||
|
||||
let mut configure = Command::new("perl");
|
||||
configure.arg(obj.join("Configure"));
|
||||
configure.arg(format!("--prefix={}", dst.display()));
|
||||
configure.arg("no-dso");
|
||||
configure.arg("no-ssl2");
|
||||
configure.arg("no-ssl3");
|
||||
|
||||
let os = match &*target {
|
||||
"aarch64-linux-android" => "linux-aarch64",
|
||||
"aarch64-unknown-linux-gnu" => "linux-aarch64",
|
||||
"aarch64-unknown-linux-musl" => "linux-aarch64",
|
||||
"aarch64-unknown-netbsd" => "BSD-generic64",
|
||||
"arm-linux-androideabi" => "android",
|
||||
"arm-unknown-linux-gnueabi" => "linux-armv4",
|
||||
"arm-unknown-linux-gnueabihf" => "linux-armv4",
|
||||
"armv6-unknown-netbsd-eabihf" => "BSD-generic32",
|
||||
"armv7-linux-androideabi" => "android-armv7",
|
||||
"armv7-unknown-linux-gnueabihf" => "linux-armv4",
|
||||
"armv7-unknown-netbsd-eabihf" => "BSD-generic32",
|
||||
"i586-unknown-linux-gnu" => "linux-elf",
|
||||
"i586-unknown-linux-musl" => "linux-elf",
|
||||
"i686-apple-darwin" => "darwin-i386-cc",
|
||||
"i686-linux-android" => "android-x86",
|
||||
"i686-unknown-freebsd" => "BSD-x86-elf",
|
||||
"i686-unknown-linux-gnu" => "linux-elf",
|
||||
"i686-unknown-linux-musl" => "linux-elf",
|
||||
"i686-unknown-netbsd" => "BSD-x86-elf",
|
||||
"mips-unknown-linux-gnu" => "linux-mips32",
|
||||
"mips64-unknown-linux-gnuabi64" => "linux64-mips64",
|
||||
"mips64el-unknown-linux-gnuabi64" => "linux64-mips64",
|
||||
"mipsel-unknown-linux-gnu" => "linux-mips32",
|
||||
"powerpc-unknown-linux-gnu" => "linux-ppc",
|
||||
"powerpc-unknown-linux-gnuspe" => "linux-ppc",
|
||||
"powerpc-unknown-netbsd" => "BSD-generic32",
|
||||
"powerpc64-unknown-linux-gnu" => "linux-ppc64",
|
||||
"powerpc64le-unknown-linux-gnu" => "linux-ppc64le",
|
||||
"powerpc64le-unknown-linux-musl" => "linux-ppc64le",
|
||||
"s390x-unknown-linux-gnu" => "linux64-s390x",
|
||||
"sparc-unknown-linux-gnu" => "linux-sparcv9",
|
||||
"sparc64-unknown-linux-gnu" => "linux64-sparcv9",
|
||||
"sparc64-unknown-netbsd" => "BSD-sparc64",
|
||||
"x86_64-apple-darwin" => "darwin64-x86_64-cc",
|
||||
"x86_64-linux-android" => "linux-x86_64",
|
||||
"x86_64-unknown-freebsd" => "BSD-x86_64",
|
||||
"x86_64-unknown-dragonfly" => "BSD-x86_64",
|
||||
"x86_64-unknown-linux-gnu" => "linux-x86_64",
|
||||
"x86_64-unknown-linux-gnux32" => "linux-x32",
|
||||
"x86_64-unknown-linux-musl" => "linux-x86_64",
|
||||
"x86_64-unknown-netbsd" => "BSD-x86_64",
|
||||
_ => panic!("don't know how to configure OpenSSL for {}", target),
|
||||
};
|
||||
configure.arg(os);
|
||||
configure.env("CC", builder.cc(target));
|
||||
for flag in builder.cflags(target, GitRepo::Rustc) {
|
||||
configure.arg(flag);
|
||||
}
|
||||
// There is no specific os target for android aarch64 or x86_64,
|
||||
// so we need to pass some extra cflags
|
||||
if target == "aarch64-linux-android" || target == "x86_64-linux-android" {
|
||||
configure.arg("-mandroid");
|
||||
configure.arg("-fomit-frame-pointer");
|
||||
}
|
||||
if target == "sparc64-unknown-netbsd" {
|
||||
// Need -m64 to get assembly generated correctly for sparc64.
|
||||
configure.arg("-m64");
|
||||
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");
|
||||
}
|
||||
}
|
||||
// Make PIE binaries
|
||||
// Non-PIE linker support was removed in Lollipop
|
||||
// https://source.android.com/security/enhancements/enhancements50
|
||||
if target == "i686-linux-android" {
|
||||
configure.arg("no-asm");
|
||||
}
|
||||
configure.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()));
|
||||
}
|
||||
}
|
||||
|
@ -236,19 +236,6 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
|
||||
}
|
||||
}
|
||||
|
||||
let run = |cmd: &mut Command| {
|
||||
cmd.output().map(|output| {
|
||||
String::from_utf8_lossy(&output.stdout)
|
||||
.lines().next().unwrap_or_else(|| {
|
||||
panic!("{:?} failed {:?}", cmd, output)
|
||||
}).to_string()
|
||||
})
|
||||
};
|
||||
build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
|
||||
if build.lldb_version.is_some() {
|
||||
build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
|
||||
}
|
||||
|
||||
if let Some(ref s) = build.config.ccache {
|
||||
cmd_finder.must_have(s);
|
||||
}
|
||||
|
@ -228,7 +228,8 @@ impl Step for Cargo {
|
||||
self.host,
|
||||
"test",
|
||||
"src/tools/cargo",
|
||||
SourceType::Submodule);
|
||||
SourceType::Submodule,
|
||||
&[]);
|
||||
|
||||
if !builder.fail_fast {
|
||||
cargo.arg("--no-fail-fast");
|
||||
@ -290,7 +291,8 @@ impl Step for Rls {
|
||||
host,
|
||||
"test",
|
||||
"src/tools/rls",
|
||||
SourceType::Submodule);
|
||||
SourceType::Submodule,
|
||||
&[]);
|
||||
|
||||
// Copy `src/tools/rls/test_data` to a writable drive.
|
||||
let test_workspace_path = builder.out.join("rls-test-data");
|
||||
@ -352,7 +354,8 @@ impl Step for Rustfmt {
|
||||
host,
|
||||
"test",
|
||||
"src/tools/rustfmt",
|
||||
SourceType::Submodule);
|
||||
SourceType::Submodule,
|
||||
&[]);
|
||||
|
||||
let dir = testdir(builder, compiler.host);
|
||||
t!(fs::create_dir_all(&dir));
|
||||
@ -407,7 +410,8 @@ impl Step for Miri {
|
||||
host,
|
||||
"test",
|
||||
"src/tools/miri",
|
||||
SourceType::Submodule);
|
||||
SourceType::Submodule,
|
||||
&[]);
|
||||
|
||||
// miri tests need to know about the stage sysroot
|
||||
cargo.env("MIRI_SYSROOT", builder.sysroot(compiler));
|
||||
@ -466,7 +470,8 @@ impl Step for Clippy {
|
||||
host,
|
||||
"test",
|
||||
"src/tools/clippy",
|
||||
SourceType::Submodule);
|
||||
SourceType::Submodule,
|
||||
&[]);
|
||||
|
||||
// clippy tests need to know about the stage sysroot
|
||||
cargo.env("SYSROOT", builder.sysroot(compiler));
|
||||
@ -755,10 +760,11 @@ default_test_with_compare_mode!(Ui {
|
||||
compare_mode: "nll"
|
||||
});
|
||||
|
||||
default_test!(RunPass {
|
||||
default_test_with_compare_mode!(RunPass {
|
||||
path: "src/test/run-pass",
|
||||
mode: "run-pass",
|
||||
suite: "run-pass"
|
||||
suite: "run-pass",
|
||||
compare_mode: "nll"
|
||||
});
|
||||
|
||||
default_test!(CompileFail {
|
||||
@ -767,12 +773,6 @@ default_test!(CompileFail {
|
||||
suite: "compile-fail"
|
||||
});
|
||||
|
||||
default_test!(ParseFail {
|
||||
path: "src/test/parse-fail",
|
||||
mode: "parse-fail",
|
||||
suite: "parse-fail"
|
||||
});
|
||||
|
||||
default_test!(RunFail {
|
||||
path: "src/test/run-fail",
|
||||
mode: "run-fail",
|
||||
@ -811,8 +811,7 @@ default_test!(Incremental {
|
||||
|
||||
default_test!(Debuginfo {
|
||||
path: "src/test/debuginfo",
|
||||
// What this runs varies depending on the native platform being apple
|
||||
mode: "debuginfo-XXX",
|
||||
mode: "debuginfo",
|
||||
suite: "debuginfo"
|
||||
});
|
||||
|
||||
@ -949,18 +948,11 @@ impl Step for Compiletest {
|
||||
return;
|
||||
}
|
||||
|
||||
if mode == "debuginfo-XXX" {
|
||||
return if builder.config.build.contains("apple") {
|
||||
builder.ensure(Compiletest {
|
||||
mode: "debuginfo-lldb",
|
||||
..self
|
||||
});
|
||||
} else {
|
||||
builder.ensure(Compiletest {
|
||||
mode: "debuginfo-gdb",
|
||||
..self
|
||||
});
|
||||
};
|
||||
if mode == "debuginfo" {
|
||||
return builder.ensure(Compiletest {
|
||||
mode: "debuginfo-both",
|
||||
..self
|
||||
});
|
||||
}
|
||||
|
||||
builder.ensure(dist::DebuggerScripts {
|
||||
@ -1060,7 +1052,7 @@ impl Step for Compiletest {
|
||||
let hostflags = flags.clone();
|
||||
cmd.arg("--host-rustcflags").arg(hostflags.join(" "));
|
||||
|
||||
let mut targetflags = flags.clone();
|
||||
let mut targetflags = flags;
|
||||
targetflags.push(format!(
|
||||
"-Lnative={}",
|
||||
builder.test_helpers_out(target).display()
|
||||
@ -1081,11 +1073,34 @@ impl Step for Compiletest {
|
||||
if let Some(ref gdb) = builder.config.gdb {
|
||||
cmd.arg("--gdb").arg(gdb);
|
||||
}
|
||||
if let Some(ref vers) = builder.lldb_version {
|
||||
|
||||
let run = |cmd: &mut Command| {
|
||||
cmd.output().map(|output| {
|
||||
String::from_utf8_lossy(&output.stdout)
|
||||
.lines().next().unwrap_or_else(|| {
|
||||
panic!("{:?} failed {:?}", cmd, output)
|
||||
}).to_string()
|
||||
})
|
||||
};
|
||||
let lldb_exe = if builder.config.lldb_enabled && !target.contains("emscripten") {
|
||||
// Test against the lldb that was just built.
|
||||
builder.llvm_out(target)
|
||||
.join("bin")
|
||||
.join("lldb")
|
||||
} else {
|
||||
PathBuf::from("lldb")
|
||||
};
|
||||
let lldb_version = Command::new(&lldb_exe)
|
||||
.arg("--version")
|
||||
.output()
|
||||
.map(|output| { String::from_utf8_lossy(&output.stdout).to_string() })
|
||||
.ok();
|
||||
if let Some(ref vers) = lldb_version {
|
||||
cmd.arg("--lldb-version").arg(vers);
|
||||
}
|
||||
if let Some(ref dir) = builder.lldb_python_dir {
|
||||
cmd.arg("--lldb-python-dir").arg(dir);
|
||||
let lldb_python_dir = run(Command::new(&lldb_exe).arg("-P")).ok();
|
||||
if let Some(ref dir) = lldb_python_dir {
|
||||
cmd.arg("--lldb-python-dir").arg(dir);
|
||||
}
|
||||
}
|
||||
|
||||
// Get paths from cmd args
|
||||
@ -1761,7 +1776,8 @@ impl Step for CrateRustdoc {
|
||||
target,
|
||||
test_kind.subcommand(),
|
||||
"src/tools/rustdoc",
|
||||
SourceType::InTree);
|
||||
SourceType::InTree,
|
||||
&[]);
|
||||
if test_kind.subcommand() == "test" && !builder.fail_fast {
|
||||
cargo.arg("--no-fail-fast");
|
||||
}
|
||||
|
@ -80,8 +80,8 @@ impl Step for ToolBuild {
|
||||
"build",
|
||||
path,
|
||||
self.source_type,
|
||||
&self.extra_features,
|
||||
);
|
||||
cargo.arg("--features").arg(self.extra_features.join(" "));
|
||||
|
||||
let _folder = builder.fold_output(|| format!("stage{}-{}", compiler.stage, tool));
|
||||
builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target));
|
||||
@ -208,6 +208,7 @@ pub fn prepare_tool_cargo(
|
||||
command: &'static str,
|
||||
path: &'static str,
|
||||
source_type: SourceType,
|
||||
extra_features: &[String],
|
||||
) -> Command {
|
||||
let mut cargo = builder.cargo(compiler, mode, target, command);
|
||||
let dir = builder.src.join(path);
|
||||
@ -221,10 +222,16 @@ pub fn prepare_tool_cargo(
|
||||
cargo.env("RUSTC_EXTERNAL_TOOL", "1");
|
||||
}
|
||||
|
||||
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");
|
||||
let mut features = extra_features.iter().cloned().collect::<Vec<_>>();
|
||||
if builder.build.config.cargo_native_static {
|
||||
if path.ends_with("cargo") ||
|
||||
path.ends_with("rls") ||
|
||||
path.ends_with("clippy") ||
|
||||
path.ends_with("rustfmt")
|
||||
{
|
||||
cargo.env("LIBZ_SYS_STATIC", "1");
|
||||
features.push("rustc-workspace-hack/all-static".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// if tools are using lzma we want to force the build script to build its
|
||||
@ -244,6 +251,9 @@ pub fn prepare_tool_cargo(
|
||||
if let Some(date) = info.commit_date() {
|
||||
cargo.env("CFG_COMMIT_DATE", date);
|
||||
}
|
||||
if features.len() > 0 {
|
||||
cargo.arg("--features").arg(&features.join(", "));
|
||||
}
|
||||
cargo
|
||||
}
|
||||
|
||||
@ -439,6 +449,7 @@ impl Step for Rustdoc {
|
||||
"build",
|
||||
"src/tools/rustdoc",
|
||||
SourceType::InTree,
|
||||
&[],
|
||||
);
|
||||
|
||||
// Most tools don't get debuginfo, but rustdoc should.
|
||||
@ -495,9 +506,6 @@ impl Step for Cargo {
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder) -> PathBuf {
|
||||
builder.ensure(native::Openssl {
|
||||
target: self.target,
|
||||
});
|
||||
// Cargo depends on procedural macros, which requires a full host
|
||||
// compiler to be available, so we need to depend on that.
|
||||
builder.ensure(compile::Rustc {
|
||||
@ -597,9 +605,6 @@ tool_extended!((self, builder),
|
||||
if clippy.is_some() {
|
||||
self.extra_features.push("clippy".to_owned());
|
||||
}
|
||||
builder.ensure(native::Openssl {
|
||||
target: self.target,
|
||||
});
|
||||
// RLS depends on procedural macros, which requires a full host
|
||||
// compiler to be available, so we need to depend on that.
|
||||
builder.ensure(compile::Rustc {
|
||||
|
@ -91,13 +91,13 @@ pub fn try_run_suppressed(cmd: &mut Command) -> bool {
|
||||
output.status.success()
|
||||
}
|
||||
|
||||
pub fn gnu_target(target: &str) -> String {
|
||||
pub fn gnu_target(target: &str) -> &str {
|
||||
match target {
|
||||
"i686-pc-windows-msvc" => "i686-pc-win32".to_string(),
|
||||
"x86_64-pc-windows-msvc" => "x86_64-pc-win32".to_string(),
|
||||
"i686-pc-windows-gnu" => "i686-w64-mingw32".to_string(),
|
||||
"x86_64-pc-windows-gnu" => "x86_64-w64-mingw32".to_string(),
|
||||
s => s.to_string(),
|
||||
"i686-pc-windows-msvc" => "i686-pc-win32",
|
||||
"x86_64-pc-windows-msvc" => "x86_64-pc-win32",
|
||||
"i686-pc-windows-gnu" => "i686-w64-mingw32",
|
||||
"x86_64-pc-windows-gnu" => "x86_64-w64-mingw32",
|
||||
s => s,
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,6 +178,37 @@ pub struct NativeLibBoilerplate {
|
||||
pub out_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl NativeLibBoilerplate {
|
||||
/// On OSX we don't want to ship the exact filename that compiler-rt builds.
|
||||
/// This conflicts with the system and ours is likely a wildly different
|
||||
/// version, so they can't be substituted.
|
||||
///
|
||||
/// As a result, we rename it here but we need to also use
|
||||
/// `install_name_tool` on OSX to rename the commands listed inside of it to
|
||||
/// ensure it's linked against correctly.
|
||||
pub fn fixup_sanitizer_lib_name(&self, sanitizer_name: &str) {
|
||||
if env::var("TARGET").unwrap() != "x86_64-apple-darwin" {
|
||||
return
|
||||
}
|
||||
|
||||
let dir = self.out_dir.join("build/lib/darwin");
|
||||
let name = format!("clang_rt.{}_osx_dynamic", sanitizer_name);
|
||||
let src = dir.join(&format!("lib{}.dylib", name));
|
||||
let new_name = format!("lib__rustc__{}.dylib", name);
|
||||
let dst = dir.join(&new_name);
|
||||
|
||||
println!("{} => {}", src.display(), dst.display());
|
||||
fs::rename(&src, &dst).unwrap();
|
||||
let status = Command::new("install_name_tool")
|
||||
.arg("-id")
|
||||
.arg(format!("@rpath/{}", new_name))
|
||||
.arg(&dst)
|
||||
.status()
|
||||
.expect("failed to execute `install_name_tool`");
|
||||
assert!(status.success());
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for NativeLibBoilerplate {
|
||||
fn drop(&mut self) {
|
||||
if !thread::panicking() {
|
||||
@ -202,7 +233,8 @@ pub fn native_lib_boilerplate(
|
||||
let src_dir = current_dir.join("..").join(src_name);
|
||||
rerun_if_changed_anything_in_dir(&src_dir);
|
||||
|
||||
let out_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or(env::var_os("OUT_DIR").unwrap());
|
||||
let out_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or_else(||
|
||||
env::var_os("OUT_DIR").unwrap());
|
||||
let out_dir = PathBuf::from(out_dir).join(out_name);
|
||||
t!(fs::create_dir_all(&out_dir));
|
||||
if link_name.contains('=') {
|
||||
@ -229,7 +261,7 @@ pub fn native_lib_boilerplate(
|
||||
pub fn sanitizer_lib_boilerplate(sanitizer_name: &str)
|
||||
-> Result<(NativeLibBoilerplate, String), ()>
|
||||
{
|
||||
let (link_name, search_path, dynamic) = match &*env::var("TARGET").unwrap() {
|
||||
let (link_name, search_path, apple) = match &*env::var("TARGET").unwrap() {
|
||||
"x86_64-unknown-linux-gnu" => (
|
||||
format!("clang_rt.{}-x86_64", sanitizer_name),
|
||||
"build/lib/linux",
|
||||
@ -242,8 +274,8 @@ pub fn sanitizer_lib_boilerplate(sanitizer_name: &str)
|
||||
),
|
||||
_ => return Err(()),
|
||||
};
|
||||
let to_link = if dynamic {
|
||||
format!("dylib={}", link_name)
|
||||
let to_link = if apple {
|
||||
format!("dylib=__rustc__{}", link_name)
|
||||
} else {
|
||||
format!("static={}", link_name)
|
||||
};
|
||||
|
@ -83,6 +83,11 @@ RUN ./build-git.sh
|
||||
COPY dist-x86_64-linux/build-headers.sh /tmp/
|
||||
RUN ./build-headers.sh
|
||||
|
||||
# OpenSSL requires a more recent version of perl
|
||||
# with so we install newer ones here
|
||||
COPY dist-x86_64-linux/build-perl.sh /tmp/
|
||||
RUN ./build-perl.sh
|
||||
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
||||
@ -110,3 +115,5 @@ ENV CFLAGS -mstackrealign
|
||||
# When we build cargo in this container, we don't want it to use the system
|
||||
# libcurl, instead it should compile its own.
|
||||
ENV LIBCURL_NO_PKG_CONFIG 1
|
||||
|
||||
ENV DIST_REQUIRE_ALL_TOOLS 1
|
||||
|
@ -83,6 +83,11 @@ RUN ./build-git.sh
|
||||
COPY dist-x86_64-linux/build-headers.sh /tmp/
|
||||
RUN ./build-headers.sh
|
||||
|
||||
# OpenSSL requires a more recent version of perl
|
||||
# with so we install newer ones here
|
||||
COPY dist-x86_64-linux/build-perl.sh /tmp/
|
||||
RUN ./build-perl.sh
|
||||
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
||||
@ -106,3 +111,5 @@ ENV DIST_SRC 1
|
||||
# When we build cargo in this container, we don't want it to use the system
|
||||
# libcurl, instead it should compile its own.
|
||||
ENV LIBCURL_NO_PKG_CONFIG 1
|
||||
|
||||
ENV DIST_REQUIRE_ALL_TOOLS 1
|
||||
|
29
src/ci/docker/dist-x86_64-linux/build-perl.sh
Executable file
29
src/ci/docker/dist-x86_64-linux/build-perl.sh
Executable file
@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
# file at the top-level directory of this distribution and at
|
||||
# http://rust-lang.org/COPYRIGHT.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 <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 -ex
|
||||
source shared.sh
|
||||
|
||||
curl https://www.cpan.org/src/5.0/perl-5.28.0.tar.gz | \
|
||||
tar xzf -
|
||||
|
||||
cd perl-5.28.0
|
||||
|
||||
# Gotta do some hackery to tell python about our custom OpenSSL build, but other
|
||||
# than that fairly normal.
|
||||
CC=gcc \
|
||||
CFLAGS='-I /rustroot/include' LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \
|
||||
hide_output ./configure.gnu
|
||||
hide_output make -j10
|
||||
hide_output make install
|
||||
|
||||
cd ..
|
||||
rm -rf perl-5.28.0
|
@ -32,17 +32,11 @@ shift
|
||||
|
||||
export CFLAGS="-fPIC $CFLAGS"
|
||||
|
||||
# FIXME: remove the patch when updating to 1.1.20
|
||||
MUSL=musl-1.1.19
|
||||
MUSL=musl-1.1.20
|
||||
|
||||
# may have been downloaded in a previous run
|
||||
if [ ! -d $MUSL ]; then
|
||||
curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf -
|
||||
# Patch to fix https://github.com/rust-lang/rust/issues/48967
|
||||
cd $MUSL && \
|
||||
curl "https://git.musl-libc.org/cgit/musl/patch/?id=610c5a8524c3d6cd3ac5a5f1231422e7648a3791" |\
|
||||
patch -p1 && \
|
||||
cd -
|
||||
fi
|
||||
|
||||
cd $MUSL
|
||||
|
@ -36,7 +36,6 @@ ENV SCRIPT python2.7 /checkout/x.py test --target $TARGETS \
|
||||
src/test/ui \
|
||||
src/test/run-pass \
|
||||
src/test/compile-fail \
|
||||
src/test/parse-fail \
|
||||
src/test/mir-opt \
|
||||
src/test/codegen-units \
|
||||
src/libcore \
|
||||
|
@ -39,7 +39,7 @@ fi
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache"
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-manage-submodules"
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-locked-deps"
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-cargo-openssl-static"
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-cargo-native-static"
|
||||
|
||||
if [ "$DIST_SRC" = "" ]; then
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-dist-src"
|
||||
@ -51,7 +51,7 @@ fi
|
||||
#
|
||||
# FIXME: need a scheme for changing this `nightly` value to `beta` and `stable`
|
||||
# either automatically or manually.
|
||||
export RUST_RELEASE_CHANNEL=stable
|
||||
export RUST_RELEASE_CHANNEL=beta
|
||||
if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL"
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp"
|
||||
@ -61,6 +61,7 @@ if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions"
|
||||
elif [ "$DEPLOY_ALT" != "" ]; then
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-assertions"
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.verify-llvm-ir"
|
||||
fi
|
||||
else
|
||||
# We almost always want debug assertions enabled, but sometimes this takes too
|
||||
@ -74,6 +75,12 @@ else
|
||||
if [ "$NO_LLVM_ASSERTIONS" = "" ]; then
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-assertions"
|
||||
fi
|
||||
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.verify-llvm-ir"
|
||||
fi
|
||||
|
||||
if [ "$RUST_RELEASE_CHANNEL" = "nightly" ] || [ "$DIST_REQUIRE_ALL_TOOLS" = "" ]; then
|
||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-missing-tools"
|
||||
fi
|
||||
|
||||
# We've had problems in the past of shell scripts leaking fds into the sccache
|
||||
|
@ -1,32 +0,0 @@
|
||||
# Rust documentations
|
||||
|
||||
## Building
|
||||
|
||||
To generate all the docs, follow the "Building Documentation" instructions in
|
||||
the README in the root of the repository. This will convert the distributed
|
||||
Markdown docs to HTML and generate HTML doc for the books, 'std' and 'extra'
|
||||
libraries.
|
||||
|
||||
To generate HTML documentation from one source file/crate, do something like:
|
||||
|
||||
~~~~text
|
||||
rustdoc --output html-doc/ --output-format html ../src/libstd/path.rs
|
||||
~~~~
|
||||
|
||||
(This, of course, requires a working build of the `rustdoc` tool.)
|
||||
|
||||
## Additional notes
|
||||
|
||||
To generate an HTML version of a doc from Markdown manually, you can do
|
||||
something like:
|
||||
|
||||
~~~~text
|
||||
rustdoc reference.md
|
||||
~~~~
|
||||
|
||||
(`reference.md` being the Rust Reference Manual.)
|
||||
|
||||
An overview of how to use the `rustdoc` command is available [in the docs][1].
|
||||
Further details are available from the command line by with `rustdoc --help`.
|
||||
|
||||
[1]: https://github.com/rust-lang/rust/blob/master/src/doc/rustdoc/src/what-is-rustdoc.md
|
@ -1,3 +1,7 @@
|
||||
[book]
|
||||
title = "The Rust Programming Language"
|
||||
author = "Steve Klabnik and Carol Nichols, with Contributions from the Rust Community"
|
||||
|
||||
[output.html]
|
||||
additional-css = ["ferris.css", "src/theme/2018-edition.css"]
|
||||
additional-js = ["ferris.js"]
|
||||
|
33
src/doc/book/2018-edition/ferris.css
Normal file
33
src/doc/book/2018-edition/ferris.css
Normal file
@ -0,0 +1,33 @@
|
||||
body.light .does_not_compile,
|
||||
body.light .panics,
|
||||
body.light .not_desired_behavior,
|
||||
body.rust .does_not_compile,
|
||||
body.rust .panics,
|
||||
body.rust .not_desired_behavior {
|
||||
background: #fff1f1;
|
||||
}
|
||||
|
||||
body.coal .does_not_compile,
|
||||
body.coal .panics,
|
||||
body.coal .not_desired_behavior,
|
||||
body.navy .does_not_compile,
|
||||
body.navy .panics,
|
||||
body.navy .not_desired_behavior,
|
||||
body.ayu .does_not_compile,
|
||||
body.ayu .panics,
|
||||
body.ayu .not_desired_behavior {
|
||||
background: #501f21;
|
||||
}
|
||||
|
||||
.ferris {
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
right: 5px;
|
||||
top: 30px;
|
||||
width: 10%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.ferris-explain {
|
||||
width: 100px;
|
||||
}
|
51
src/doc/book/2018-edition/ferris.js
Normal file
51
src/doc/book/2018-edition/ferris.js
Normal file
@ -0,0 +1,51 @@
|
||||
var ferrisTypes = [
|
||||
{
|
||||
attr: 'does_not_compile',
|
||||
title: 'This code does not compile!'
|
||||
},
|
||||
{
|
||||
attr: 'panics',
|
||||
title: 'This code panics!'
|
||||
},
|
||||
{
|
||||
attr: 'unsafe',
|
||||
title: 'This code block contains unsafe code.'
|
||||
},
|
||||
{
|
||||
attr: 'not_desired_behavior',
|
||||
title: 'This code does not produce the desired behavior.'
|
||||
}
|
||||
]
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
for (var ferrisType of ferrisTypes) {
|
||||
attachFerrises(ferrisType)
|
||||
}
|
||||
})
|
||||
|
||||
function attachFerrises (type) {
|
||||
var elements = document.getElementsByClassName(type.attr)
|
||||
|
||||
for (var codeBlock of elements) {
|
||||
var lines = codeBlock.textContent.split(/\r|\r\n|\n/).length - 1;
|
||||
|
||||
if (lines >= 4) {
|
||||
attachFerris(codeBlock, type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function attachFerris (element, type) {
|
||||
var a = document.createElement('a')
|
||||
a.setAttribute('href', 'ch00-00-introduction.html#ferris')
|
||||
a.setAttribute('target', '_blank')
|
||||
|
||||
var img = document.createElement('img')
|
||||
img.setAttribute('src', 'img/ferris/' + type.attr + '.svg')
|
||||
img.setAttribute('title', type.title)
|
||||
img.className = 'ferris'
|
||||
|
||||
a.appendChild(img)
|
||||
|
||||
element.parentElement.insertBefore(a, element)
|
||||
}
|
@ -36,10 +36,9 @@
|
||||
|
||||
## 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)
|
||||
- [Packages, Crates, and Modules](ch07-00-packages-crates-and-modules.md)
|
||||
- [Packages and crates for making libraries and executables](ch07-01-packages-and-crates-for-making-libraries-and-executables.md)
|
||||
- [Modules and `use` to control scope and privacy](ch07-02-modules-and-use-to-control-scope-and-privacy.md)
|
||||
|
||||
- [Common Collections](ch08-00-common-collections.md)
|
||||
- [Vectors](ch08-01-vectors.md)
|
||||
@ -116,6 +115,7 @@
|
||||
- [Advanced Traits](ch19-03-advanced-traits.md)
|
||||
- [Advanced Types](ch19-04-advanced-types.md)
|
||||
- [Advanced Functions & Closures](ch19-05-advanced-functions-and-closures.md)
|
||||
- [Macros](ch19-06-macros.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)
|
||||
@ -130,3 +130,4 @@
|
||||
- [E - Translations](appendix-05-translation.md)
|
||||
- [F - How Rust is Made and “Nightly Rust”](appendix-06-nightly-rust.md)
|
||||
- [G - Other useful tools](appendix-07-other-useful-tools.md)
|
||||
- [H - Editions](appendix-08-editions.md)
|
||||
|
@ -25,6 +25,85 @@ you both `rustc` and `cargo`. To take any Cargo project and format it:
|
||||
$ cargo fmt
|
||||
```
|
||||
|
||||
## Fix up your code with `rustfix`
|
||||
|
||||
If you’ve written code in Rust before, you’ve probably seen a compiler
|
||||
warning before. For example, consider this code:
|
||||
|
||||
```rust
|
||||
fn do_something() {}
|
||||
|
||||
fn main() {
|
||||
for i in 0..100 {
|
||||
do_something();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here, we’re calling do_something a hundred times. But we never use the
|
||||
variable i. And so Rust warns:
|
||||
|
||||
```text
|
||||
> cargo build
|
||||
Compiling myprogram v0.1.0 (file:///projects/myprogram)
|
||||
warning: unused variable: `i`
|
||||
--> src\main.rs:4:9
|
||||
|
|
||||
4 | for i in 1..100 {
|
||||
| ^ help: consider using `_i` instead
|
||||
|
|
||||
= note: #[warn(unused_variables)] on by default
|
||||
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.50s
|
||||
```
|
||||
|
||||
See how it suggests that we use `_i` as a name instead? We can automatically
|
||||
apply that suggestion with cargo fix:
|
||||
|
||||
```console
|
||||
> cargo fix
|
||||
Checking myprogram v0.1.0 (file:///projects/myprogram)
|
||||
Fixing src\main.rs (1 fix)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.59s
|
||||
```
|
||||
|
||||
If we look at `src\main.rs` again, we’ll see that the code has changed:
|
||||
|
||||
```rust
|
||||
fn do_something() {}
|
||||
|
||||
fn main() {
|
||||
for _i in 0..100 {
|
||||
do_something();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We’re now using `_i`, and the warning will no longer appear.
|
||||
|
||||
`cargo fix` can also be used to transition your code between different editions
|
||||
of Rust. Editions are covered in Appendix H.
|
||||
|
||||
## More lints with `clippy`
|
||||
|
||||
`clippy` is a bunch of lints to catch common mistakes and improve your Rust
|
||||
code.
|
||||
|
||||
`clippy` is not at 1.0 yet, but a preview is available for you to use in the
|
||||
meantime. Please give it a try and let us know how it goes!
|
||||
|
||||
To install `clippy`:
|
||||
|
||||
```shell
|
||||
$ rustup component add clippy-preview
|
||||
```
|
||||
|
||||
To take any Cargo project and run clippy's lints on it:
|
||||
|
||||
```shell
|
||||
$ cargo clippy
|
||||
```
|
||||
|
||||
## IDE integration with the Rust Language Server
|
||||
|
||||
To help IDE integration, the Rust project distributes `rls`, the Rust
|
||||
|
58
src/doc/book/2018-edition/src/appendix-08-editions.md
Normal file
58
src/doc/book/2018-edition/src/appendix-08-editions.md
Normal file
@ -0,0 +1,58 @@
|
||||
# Appendix H - Editions
|
||||
|
||||
Way back in Chapter 1, we saw that `cargo new` adds a bit of metadata to your
|
||||
`Cargo.toml` about an `edition`. We can finally talk about what that means!
|
||||
|
||||
In Appendix F, we talked about Rust's six-week release cycle. This means that
|
||||
users get a constant stream of new features. This is much faster than updates
|
||||
for other languages, but this also means that each update is smaller. After a
|
||||
while, all of those tiny changes add up. But, from release to release, it can
|
||||
be hard to look back and say "Wow, between Rust 1.10 and Rust 1.31, Rust has
|
||||
changed a lot!"
|
||||
|
||||
Every two or three years, the Rust team produces a new *edition* of Rust.
|
||||
Each edition brings together the features that have landed into a clear
|
||||
package, with fully updated documentation and tooling. New editions ship
|
||||
through the usual release process.
|
||||
|
||||
This serves different purposes for different people:
|
||||
|
||||
* For active Rust users, it brings together incremental changes into an
|
||||
easy-to-understand package.
|
||||
* For non-users, it signals that some major advancements have landed, which
|
||||
might make Rust worth another look.
|
||||
* For those developing Rust itself, it provides a rallying point for the
|
||||
project as a whole.
|
||||
|
||||
At the time of writing, there are two editions: Rust 2015, and Rust 2018.
|
||||
This book assumes Rust 2018; see the "second edition" for Rust 2015 specific
|
||||
details.
|
||||
|
||||
## Compatibility
|
||||
|
||||
Speaking of there being multiple editions, the `edition = "2018"` key in
|
||||
`Cargo.toml` indicates which edition your code should be compiled under. If
|
||||
the key does not exist, it defaults to `2015`, for backwards compatibility
|
||||
reasons.
|
||||
|
||||
This opt in enables editions to contain incompatible changes, like adding a
|
||||
new keyword that might conflict with identifiers in code, or turning warnings
|
||||
into errors. A Rust compiler will support all editions that existed prior to
|
||||
the compiler's release, and can link crates of any supported editions
|
||||
together. Edition changes only affect the way the compiler initially parses
|
||||
the code. Therefore, if you're using Rust 2015, and one of your dependencies
|
||||
uses Rust 2018, it all works just fine. The opposite situation works as well.
|
||||
|
||||
Just to be clear: most features will be available on all editions. People
|
||||
using any edition of Rust will continue to see improvements as new stable
|
||||
releases are made. In some cases however, mainly when new keywords are added,
|
||||
but sometimes for other reasons, there may be new features that are only
|
||||
available in later editions. You only need to upgrade if you want to take
|
||||
advantage of such features.
|
||||
|
||||
## Read More
|
||||
|
||||
For more details, the [Edition
|
||||
Guide](https://rust-lang-nursery.github.io/edition-guide/) is a complete
|
||||
book about editions, including how to automatically upgrade your code to
|
||||
a new edition via `cargo fix`.
|
@ -162,18 +162,29 @@ 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.
|
||||
|
||||
<span id="ferris"></span>
|
||||
|
||||
An important part of the process of learning Rust is learning how to read the
|
||||
error messages the compiler displays: these will guide you toward working code.
|
||||
As such, we’ll provide many examples of code that doesn’t compile along with
|
||||
the error message the compiler will show you in each situation. Know that if
|
||||
you enter and run a random example, it may not compile! Make sure you read the
|
||||
surrounding text to see whether the example you’re trying to run is meant to
|
||||
error. In most situations, we’ll lead you to the correct version of any code
|
||||
that doesn’t compile.
|
||||
error. Ferris will also help you distinguish code that isn't meant to work:
|
||||
|
||||
| Ferris | Meaning |
|
||||
|------------------------------------------------------------------------|--------------------------------------------------|
|
||||
| <img src="img/ferris/does_not_compile.svg" class="ferris-explain"> | This code does not compile! |
|
||||
| <img src="img/ferris/panics.svg" class="ferris-explain"> | This code panics! |
|
||||
| <img src="img/ferris/unsafe.svg" class="ferris-explain"> | This code block contains unsafe code. |
|
||||
| <img src="img/ferris/not_desired_behavior.svg" class="ferris-explain"> | This code does not produce the desired behavior. |
|
||||
|
||||
In most situations, we’ll lead you to the correct version of any code that
|
||||
doesn’t 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/second-edition/src
|
||||
[book]: https://github.com/rust-lang/book/tree/master/2018-edition/src
|
||||
|
@ -60,6 +60,7 @@ code in Listing 1-2.
|
||||
name = "hello_cargo"
|
||||
version = "0.1.0"
|
||||
authors = ["Your Name <you@example.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
```
|
||||
@ -76,10 +77,11 @@ The first line, `[package]`, is a section heading that indicates that the
|
||||
following statements are configuring a package. As we add more information to
|
||||
this file, we’ll add other sections.
|
||||
|
||||
The next three lines set the configuration information Cargo needs to compile
|
||||
The next four lines set the configuration information Cargo needs to compile
|
||||
your program: the name, the version, and who wrote it. Cargo gets your name and
|
||||
email information from your environment, so if that information is not correct,
|
||||
fix the information now and then save the file.
|
||||
fix the information now and then save the file. We'll talk about the `edition`
|
||||
key in Appendix H.
|
||||
|
||||
The last line, `[dependencies]`, is the start of a section for you to list any
|
||||
of your project’s dependencies. In Rust, packages of code are referred to as
|
||||
|
@ -360,9 +360,10 @@ library. However, the Rust team does provide a [`rand` crate][randcrate].
|
||||
|
||||
### Using a Crate to Get More Functionality
|
||||
|
||||
Remember that a crate is a package of Rust code. The project we’ve been
|
||||
building is a *binary crate*, which is an executable. The `rand` crate is a
|
||||
*library crate*, which contains code intended to be used in other programs.
|
||||
Remember that a crate is a collection of Rust source code files.
|
||||
The project we’ve been building is a *binary crate*, which is an executable.
|
||||
The `rand` crate is a *library crate*, which contains code intended to be
|
||||
used in other programs.
|
||||
|
||||
Cargo’s use of external crates is where it really shines. Before we can write
|
||||
code that uses `rand`, we need to modify the *Cargo.toml* file to include the
|
||||
@ -603,7 +604,7 @@ will explain.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
extern crate rand;
|
||||
|
||||
use std::io;
|
||||
|
@ -10,12 +10,46 @@ Specifically, you’ll learn about variables, basic types, functions, comments,
|
||||
and control flow. These foundations will be in every Rust program, and learning
|
||||
them early will give you a strong core to start from.
|
||||
|
||||
> ### 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 you’ll be using them to do various tasks in your Rust
|
||||
> programs; a few have no current functionality associated with them but have
|
||||
> been reserved for functionality that might be added to Rust in the future. You
|
||||
> can find a list of the keywords in Appendix A.
|
||||
## 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 you’ll be using them to do various tasks in your Rust
|
||||
programs; a few have no current functionality associated with them but have
|
||||
been reserved for functionality that might be added to Rust in the future. You
|
||||
can find a list of the keywords in Appendix A.
|
||||
|
||||
## Identifiers
|
||||
|
||||
We're going to be explaining a bunch of concepts in this book: variables,
|
||||
functions, structs, lots of things. All of these things need names. A name
|
||||
in Rust is called an "identifier," and can be made up of any nonempty ASCII
|
||||
string, with some restrictions:
|
||||
|
||||
Either:
|
||||
|
||||
* The first character is a letter.
|
||||
* The remaining characters are alphanumeric or _.
|
||||
|
||||
or:
|
||||
|
||||
* The first character is _.
|
||||
* The identifier is more than one character. _ alone is not an identifier.
|
||||
* The remaining characters are alphanumeric or _.
|
||||
|
||||
### Raw identifiers
|
||||
|
||||
Sometimes, you may need to use a name that's a keyword for another purpose.
|
||||
Maybe you need to call a function named *match* that is coming from a C
|
||||
library, where 'match' is not a keyword. To do this, you can use a "raw identifier."
|
||||
Raw identifiers start with `#r`:
|
||||
|
||||
```rust,ignore
|
||||
let r#fn = "this variable is named 'fn' even though that's a keyword";
|
||||
|
||||
// call a function named 'match'
|
||||
r#match();
|
||||
```
|
||||
|
||||
You won't need raw identifiers often, but when you do, you *really* need them.
|
@ -16,7 +16,7 @@ code with the following code that won’t compile just yet:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
let x = 5;
|
||||
println!("The value of x is: {}", x);
|
||||
@ -207,7 +207,7 @@ 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, we’ll get a compile-time error:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
let mut spaces = " ";
|
||||
spaces = spaces.len();
|
||||
```
|
||||
|
@ -362,7 +362,7 @@ compile but exit with an error when it runs:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,panics
|
||||
fn main() {
|
||||
let a = [1, 2, 3, 4, 5];
|
||||
let index = 10;
|
||||
|
@ -170,7 +170,7 @@ to another variable, as the following code tries to do; you’ll get an error:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
let x = (let y = 6);
|
||||
}
|
||||
@ -308,7 +308,7 @@ expression to a statement, we’ll get an error.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
let x = plus_one(5);
|
||||
|
||||
|
@ -78,7 +78,7 @@ the condition isn’t a `bool`, we’ll get an error. For example:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
let number = 3;
|
||||
|
||||
@ -212,7 +212,7 @@ example, we’ll get an error:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
let condition = true;
|
||||
|
||||
|
@ -319,7 +319,7 @@ considers `s1` to no longer be valid and, therefore, Rust doesn’t need to free
|
||||
anything when `s1` goes out of scope. Check out what happens when you try to
|
||||
use `s1` after `s2` is created; it won’t work:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
let s1 = String::from("hello");
|
||||
let s2 = s1;
|
||||
|
||||
|
@ -83,7 +83,7 @@ Listing 4-6. Spoiler alert: it doesn’t work!
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
let s = String::from("hello");
|
||||
|
||||
@ -140,25 +140,27 @@ fail:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
let mut s = String::from("hello");
|
||||
|
||||
let r1 = &mut s;
|
||||
let r2 = &mut s;
|
||||
|
||||
println!("{}, {}", r1, r2);
|
||||
```
|
||||
|
||||
Here’s the error:
|
||||
|
||||
```text
|
||||
error[E0499]: cannot borrow `s` as mutable more than once at a time
|
||||
--> borrow_twice.rs:5:19
|
||||
--> src/main.rs:5:10
|
||||
|
|
||||
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
|
||||
4 | let r1 = &mut s;
|
||||
| ------ first mutable borrow occurs here
|
||||
5 | let r2 = &mut s;
|
||||
| ^^^^^^ second mutable borrow occurs here
|
||||
6 | println!("{}, {}", r1, r2);
|
||||
| -- borrow later used here
|
||||
```
|
||||
|
||||
This restriction allows for mutation but in a very controlled fashion. It’s
|
||||
@ -194,28 +196,30 @@ let r2 = &mut s;
|
||||
A similar rule exists for combining mutable and immutable references. This code
|
||||
results in an error:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
let mut s = String::from("hello");
|
||||
|
||||
let r1 = &s; // no problem
|
||||
let r2 = &s; // no problem
|
||||
let r3 = &mut s; // BIG PROBLEM
|
||||
|
||||
println!("{}, {}, and {}", r1, r2, r3);
|
||||
```
|
||||
|
||||
Here’s the error:
|
||||
|
||||
```text
|
||||
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as
|
||||
immutable
|
||||
--> borrow_thrice.rs:6:19
|
||||
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
|
||||
--> src/main.rs:6:10
|
||||
|
|
||||
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
|
||||
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 |
|
||||
8 | println!("{}, {}, and {}", r1, r2, r3);
|
||||
| -- borrow later used here
|
||||
```
|
||||
|
||||
Whew! We *also* cannot have a mutable reference while we have an immutable one.
|
||||
@ -244,7 +248,7 @@ compile-time error:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
let reference_to_nothing = dangle();
|
||||
}
|
||||
|
@ -265,13 +265,15 @@ compile time error:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
let mut s = String::from("hello world");
|
||||
|
||||
let word = first_word(&s);
|
||||
|
||||
s.clear(); // Error!
|
||||
|
||||
println!("the first word is: {}", word);
|
||||
}
|
||||
```
|
||||
|
||||
@ -279,15 +281,16 @@ Here’s 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
|
||||
--> src/main.rs:10:5
|
||||
|
|
||||
8 | let word = first_word(&s);
|
||||
| -- immutable borrow occurs here
|
||||
9 |
|
||||
10 | s.clear(); // Error!
|
||||
| ^^^^^^^^^ mutable borrow occurs here
|
||||
11 |
|
||||
12 | println!("the first word is: {}", word);
|
||||
| ---- borrow later used here
|
||||
```
|
||||
|
||||
Recall from the borrowing rules that if we have an immutable reference to
|
||||
|
@ -271,7 +271,7 @@ itself. We’ll discuss traits in Chapter 10.
|
||||
>
|
||||
> <span class="filename">Filename: src/main.rs</span>
|
||||
>
|
||||
> ```rust,ignore
|
||||
> ```rust,ignore,does_not_compile
|
||||
> struct User {
|
||||
> username: &str,
|
||||
> email: &str,
|
||||
|
@ -148,7 +148,7 @@ work, however:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
height: u32,
|
||||
|
@ -339,7 +339,7 @@ types, the compiler won’t let us use an `Option<T>` value as if it were
|
||||
definitely a valid value. For example, this code won’t compile because it’s
|
||||
trying to add an `i8` to an `Option<i8>`:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
let x: i8 = 5;
|
||||
let y: Option<i8> = Some(5);
|
||||
|
||||
|
@ -239,7 +239,7 @@ consistently a user favorite.
|
||||
There’s one other aspect of `match` we need to discuss. Consider this version
|
||||
of our `plus_one` function that has a bug and won’t compile:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn plus_one(x: Option<i32>) -> Option<i32> {
|
||||
match x {
|
||||
Some(i) => Some(i + 1),
|
||||
|
@ -1,24 +0,0 @@
|
||||
# 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, you’ll 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). Here’s 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 it’s easier to refer to them.
|
||||
|
||||
We’ll look at each of these parts to see how they fit into the whole.
|
@ -0,0 +1,15 @@
|
||||
# Packages, Crates, and Modules
|
||||
|
||||
A key question when writing programs is scope: what names do I know about?
|
||||
What functions am I allowed to call? What does this variable refer to?
|
||||
|
||||
Rust has a number of features related to scopes. This is sometimes called
|
||||
"the module system", but it encompases more than just modules:
|
||||
|
||||
* A *path* is a way of naming something.
|
||||
* *Modules* and the *use keyword* let you control the scope and privacy of paths.
|
||||
* *Crates* are a tree of modules that produce a library or executable.
|
||||
* *Packages* are a Cargo feature that let you build, test, and share crates.
|
||||
|
||||
This chapter will cover all of these concepts. You'll be importing and
|
||||
exporting things like a pro soon!
|
@ -1,480 +0,0 @@
|
||||
## `mod` and the Filesystem
|
||||
|
||||
We’ll start our module example by making a new project with Cargo, but instead
|
||||
of creating a binary crate, we’ll 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.
|
||||
|
||||
We’ll create a skeleton of a library that provides some general networking
|
||||
functionality; we’ll concentrate on the organization of the modules and
|
||||
functions, but we won’t worry about what code goes in the function bodies.
|
||||
We’ll call our library `communicator`. To create a library, pass the `--lib`
|
||||
option:
|
||||
|
||||
```text
|
||||
$ cargo new communicator --lib
|
||||
$ cd communicator
|
||||
```
|
||||
|
||||
Notice that Cargo generated *src/lib.rs* instead of *src/main.rs*. Inside
|
||||
*src/lib.rs* we’ll 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. We’ll
|
||||
look at the `#[]` and `mod tests` syntax in the “Using `super` to Access a
|
||||
Parent Module” section later in this chapter, but for now, leave this code at
|
||||
the bottom of *src/lib.rs*.
|
||||
|
||||
Because we don’t have a *src/main.rs* file, there’s nothing for Cargo to
|
||||
execute with the `cargo run` command. Therefore, we’ll use the `cargo build`
|
||||
command to compile our library crate’s code.
|
||||
|
||||
We’ll look at different options for organizing your library’s code that will be
|
||||
suitable in a variety of situations, depending on the intent of the code.
|
||||
|
||||
### Module Definitions
|
||||
|
||||
For our `communicator` networking library, we’ll 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 they’re in different modules.
|
||||
|
||||
In this case, because we’re 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, there’s nothing special about *src/lib.rs*. We could also
|
||||
create modules in *src/main.rs* for a binary crate in the same way as we’re
|
||||
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 don’t conflict
|
||||
with each other because they’re in different namespaces.
|
||||
|
||||
In this way, modules form a hierarchy. The contents of *src/lib.rs* are at the
|
||||
topmost level, and the submodules are at lower levels. Here’s what the
|
||||
organization of our example in Listing 7-1 looks like when thought of as a
|
||||
hierarchy:
|
||||
|
||||
```text
|
||||
communicator
|
||||
├── network
|
||||
└── client
|
||||
```
|
||||
|
||||
And here’s 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 they’ll 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 library’s users think about your project’s 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 you’re used to: filesystems! We can use Rust’s module system along with
|
||||
multiple files to split up Rust projects so not everything lives in
|
||||
*src/lib.rs* or *src/main.rs*. For this example, let’s start with the code in
|
||||
Listing 7-3:
|
||||
|
||||
<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, let’s replace the `client` module code with only the declaration of the
|
||||
`client` module so that *src/lib.rs* looks like code shown in Listing 7-4:
|
||||
|
||||
<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>
|
||||
|
||||
We’re still *declaring* the `client` module here, but by replacing the block
|
||||
with a semicolon, we’re 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 don’t 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,
|
||||
we’d be giving the `client` module its own submodule named `client`!
|
||||
|
||||
Rust only knows to look in *src/lib.rs* by default. If we want to add more
|
||||
files to our project, we need to tell Rust in *src/lib.rs* to look in other
|
||||
files; this is why `mod client` needs to be defined in *src/lib.rs* and can’t
|
||||
be defined in *src/client.rs*.
|
||||
|
||||
Now the project should compile successfully, although you’ll 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. Don’t worry
|
||||
about these warnings for now; we’ll address them later in this chapter in the
|
||||
“Controlling Visibility with `pub`” section. The good news is that they’re just
|
||||
warnings; our project built successfully!
|
||||
|
||||
Next, let’s 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 it’s a submodule—that is, a module within a module—our current tactic
|
||||
of extracting a module into a file named after that module won’t work. We’ll
|
||||
try anyway so you can see the error. First, change *src/network.rs* to have
|
||||
`mod server;` instead of the `server` module’s 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`, we’ll 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 haven’t yet talked about doing:
|
||||
|
||||
```text
|
||||
note: maybe move this module `network` to its own directory via
|
||||
`network/mod.rs`
|
||||
```
|
||||
|
||||
Instead of continuing to follow the same file-naming pattern we used
|
||||
previously, we can do what the note suggests:
|
||||
|
||||
1. Make a new *directory* named *network*, the parent module’s name.
|
||||
2. Move the *src/network.rs* file into the new *network* directory and
|
||||
rename it *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 (we’ll 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 couldn’t we just extract the `network::server`
|
||||
module into *src/server.rs*? The reason is that Rust wouldn’t 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 Rust’s behavior here,
|
||||
let’s consider a different example with the following module hierarchy, where
|
||||
all the definitions are in *src/lib.rs*:
|
||||
|
||||
```text
|
||||
communicator
|
||||
├── client
|
||||
└── network
|
||||
└── client
|
||||
```
|
||||
|
||||
In this example, we have three modules again: `client`, `network`, and
|
||||
`network::client`. 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 wouldn’t be
|
||||
able to extract the `network::client` module into a *src/client.rs* file
|
||||
because that already exists for the top-level `client` module! If we could put
|
||||
the code for *both* the `client` and `network::client` modules in the
|
||||
*src/client.rs* file, Rust wouldn’t 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
|
||||
|
||||
Let’s 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 module’s file using the `mod`
|
||||
keyword.
|
||||
|
||||
Next, we’ll talk about the `pub` keyword and get rid of those warnings!
|
@ -0,0 +1,46 @@
|
||||
# Packages and crates for making libraries and executables
|
||||
|
||||
Let's talk about *packages* and *crates*. Here's a summary:
|
||||
|
||||
* A "crate" is a binary or library.
|
||||
* The "crate root" is a source file that is used to build a crate.
|
||||
* A "package" has a Cargo.toml that describes how to build one or more crates.
|
||||
At most one crate can be a library.
|
||||
|
||||
So when we type `cargo new`, we're creating a package:
|
||||
|
||||
```console
|
||||
> cargo new foo
|
||||
> ls foo
|
||||
src
|
||||
.gitignore
|
||||
Cargo.toml
|
||||
> ls foo/src
|
||||
main.rs
|
||||
```
|
||||
|
||||
There's a `Cargo.toml`, that checks out. And while there's no *description*
|
||||
of `main.rs` inside of it, by convention, if you have a `src/main.rs` in the
|
||||
same directory as a package's `Cargo.toml`, Cargo understands that to be a
|
||||
*binary* crate with the same name as the package. Likewise, with `src/lib.rs`,
|
||||
Cargo knows that's a *library* crate with the same name as the package.
|
||||
|
||||
What exactly is a crate in this case? Well, we call the `main.rs` or `lib.rs`
|
||||
file the "crate root", that is, the source file that corresponds to the
|
||||
crate. This file is passed by Cargo to `rustc` in order to actually build
|
||||
the library or binary.
|
||||
|
||||
A package can have:
|
||||
|
||||
* Zero or one library crates
|
||||
* As many binary crates as it would like
|
||||
* There must be at least one crate
|
||||
|
||||
If we have both `src/main.rs` and `src/lib.rs`, then our package has two
|
||||
crates: a library and a binary, both with the same name. If we only had one
|
||||
of the two, we'd have either a single library or binary. But what about more
|
||||
than one binary? We'll talk about that more in Chapter 14, "More about Cargo
|
||||
and Crates.io."
|
||||
|
||||
That's all we'll say about packages until then. And to learn more about crates,
|
||||
we need to understand "modules." Read on to find out more!
|
@ -1,288 +0,0 @@
|
||||
## 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, we’re building a library
|
||||
with functions that are intended to be used by our *users*, not necessarily by
|
||||
us within our own project, so it shouldn’t matter that these `connect`
|
||||
functions go unused. The point of creating them is that they will be used by
|
||||
another project, not our own.
|
||||
|
||||
To understand why this program invokes these warnings, let’s try using the
|
||||
`communicator` library from another project, calling it externally. To do that,
|
||||
we’ll create a binary crate in the same directory as our library crate by
|
||||
making a *src/main.rs* file containing this code:
|
||||
|
||||
<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 it’s a nice separation of concerns.
|
||||
|
||||
From the point of view of a crate outside the `communicator` library looking
|
||||
in, all the modules we’ve been creating are within a module that has the same
|
||||
name as the crate, `communicator`. We call the top-level module of a crate the
|
||||
*root module*.
|
||||
|
||||
Also note that even if we’re using an external crate within a submodule of our
|
||||
project, the `extern crate` should go in our root module (so in *src/main.rs*
|
||||
or *src/lib.rs*). Then, in our submodules, we can refer to items from external
|
||||
crates as if the items are top-level modules.
|
||||
|
||||
Right now, our binary crate just calls our library’s `connect` function from
|
||||
the `client` module. However, invoking `cargo build` will now give us an error
|
||||
after the warnings:
|
||||
|
||||
```text
|
||||
error[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. It’s also the first time we’ve run into the concepts of
|
||||
*public* and *private* in the context of Rust. The default state of all code in
|
||||
Rust is private: no one else is allowed to use the code. If you don’t use a
|
||||
private function within your 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 that’s 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. We’ll 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`. Let’s 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
|
||||
let’s 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 don’t always indicate that an item in your code needs to
|
||||
be made public: if you *didn’t* want these functions to be part of your public
|
||||
API, unused code warnings could be alerting you to code you no longer 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
|
||||
crate’s public API, so let’s 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, we’re 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. We’re 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 parent’s child modules.
|
||||
|
||||
### Privacy Examples
|
||||
|
||||
Let’s look at a few more privacy examples to get some practice. Create a new
|
||||
library project and enter the code in Listing 7-6 into your new project’s
|
||||
*src/lib.rs*:
|
||||
|
||||
<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 you’re 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, let’s talk about bringing items into scope with the `use` keyword.
|
@ -0,0 +1,579 @@
|
||||
# Modules and use to control scope and privacy
|
||||
|
||||
Rust has a feature that's often referred to as "the module system," but
|
||||
it encompasses a few more features than only modules. In this section,
|
||||
we'll talk about:
|
||||
|
||||
* Modules, a way to control the privacy of paths
|
||||
* Paths, a way to name things
|
||||
* `use` a keyword to bring a path into scope
|
||||
* `pub`, a keyword to make things public
|
||||
* re-naming imports with `as`
|
||||
* Using external packages
|
||||
* Nested imports to clean up large import lists
|
||||
* "glob imports" with `*` to bring everything into scope
|
||||
* Splitting modules up into individual files
|
||||
|
||||
First up, modules. Here's an example of some code that uses modules:
|
||||
|
||||
```rust
|
||||
mod foo {
|
||||
fn bar() {
|
||||
// code goes here
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, we've defined two functions, `main` and `bar`. The `bar`
|
||||
function, however, is inside of a `mod` block. This block defines a module
|
||||
named `foo`. You can nest modules inside of other modules:
|
||||
|
||||
```rust
|
||||
mod branch1 {
|
||||
mod branch2 {
|
||||
mod branch4 {
|
||||
fn leaf() {
|
||||
// code goes here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod branch3 {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Remember in the last section, when we said that `main.rs` and `lib.rs` are
|
||||
considered "crate roots?" This is because the contents of either of these two
|
||||
files form a module named `crate`, at the root of the crate tree. So in this
|
||||
example, we have a module tree that looks like this:
|
||||
|
||||
```text
|
||||
crate
|
||||
└── branch1
|
||||
└── branch2
|
||||
└── branch4
|
||||
└── branch3
|
||||
```
|
||||
|
||||
This might remind you of the filesystem you have on your computer; this is
|
||||
a very apt comparison! The module system is similar to a filesystem in many
|
||||
ways; analogies to filesystems are usually very helpful, and we'll be making
|
||||
them in this chapter.
|
||||
|
||||
Just like directories on a filesystem, you place code inside whichever module
|
||||
you'd like. How should you split up your code into modules? What should you
|
||||
name those modules? In order to talk about that, we need to learn about
|
||||
`pub`. But before we get to `pub`, let's talk about a seemingly simple
|
||||
question: how can we call the `leaf` function?
|
||||
|
||||
## Paths for referring to something
|
||||
|
||||
If we want to call a function, we need to know its *path*. It's sort of
|
||||
a synonym for "name," but evokes that filesystem metaphor. Additionally,
|
||||
functions, structs, etc may have multiple paths that refer to the same
|
||||
place, so "name" feels slightly off.
|
||||
|
||||
A *path* can take two forms:
|
||||
|
||||
* An *absolute path* starts with a crate name, or a literal `crate`, to refer
|
||||
to the crate it's in.
|
||||
* A *relative path* starts with `self`, `super`, or an identifier in the
|
||||
current module.
|
||||
* Both kinds of paths are followed by one or more identifiers, separated by
|
||||
double colons (`::`).
|
||||
|
||||
What's the path of `leaf`? Let's simplify our code a bit:
|
||||
|
||||
```rust
|
||||
mod branch1 {
|
||||
mod branch2 {
|
||||
fn leaf() {
|
||||
// code goes here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// how do we call leaf?
|
||||
}
|
||||
```
|
||||
|
||||
If we wanted to call `leaf` from `main`, we can do it two ways:
|
||||
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
// absolute path
|
||||
crate::branch1::branch2::leaf();
|
||||
|
||||
// relative path
|
||||
branch1::branch2::leaf();
|
||||
}
|
||||
```
|
||||
|
||||
The former is an absolute path. Because `leaf` is defined in our crate,
|
||||
we use the `crate` keyword to start an absolute path, and then include
|
||||
each of the modules until we make our way to leaf. This is kind of like
|
||||
running `/branch1/branch2/leaf` as a program on your computer; the `crate`
|
||||
name is like starting the path with `/` in your shell.
|
||||
|
||||
The second one is a relative path; it starts with the name of `branch1`,
|
||||
a module that's at the same level of the module tree that we are. This is
|
||||
kind of like running `branch1/branch2/leaf` as a program on your computer;
|
||||
starting with a name means that the path is relative.
|
||||
|
||||
You may be thinking "wow, that's a long name. Look at how we had to repeat
|
||||
all of that `branch1::branch2` stuff just to call `leaf` twice." You're
|
||||
not wrong. But before we can talk about how to simplify this example,
|
||||
we have a problem: this example does not compile!
|
||||
|
||||
```console
|
||||
> cargo build
|
||||
Compiling sampleproject v0.1.0 (file:///projects/sampleproject)
|
||||
error[E0603]: module `branch2` is private
|
||||
--> src\main.rs:10:5
|
||||
|
|
||||
10 | crate::branch1::branch2::leaf();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0603]: module `branch2` is private
|
||||
--> src\main.rs:12:5
|
||||
|
|
||||
12 | branch1::branch2::leaf();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
```
|
||||
|
||||
While we have the correct path for `leaf`, we cannot call it, as it's private.
|
||||
It's time to learn about `pub`!
|
||||
|
||||
## `pub` to make paths public
|
||||
|
||||
Earlier, we talked about the syntax of modules, but we didn't really talk about
|
||||
*why* they exist. Modules are the *privacy boundary* in Rust. In other words,
|
||||
if you want to make something private, you put it in a module. Here's the
|
||||
privacy rules:
|
||||
|
||||
* Everything is private by default.
|
||||
* You can use the `pub` keyword to make something public.
|
||||
* You are not allowed to use private code inside of children modules.
|
||||
* You are allowed to use any code inside of parent modules or the current module.
|
||||
|
||||
In other words, privacy works "down" the module tree, but is public "up" the tree.
|
||||
Again, think of a filesystem: if a directory is private, you cannot look into it,
|
||||
but you can look inside the current directory or any parent directories.
|
||||
|
||||
Our error said that `branch2` was private. Let's fix that:
|
||||
|
||||
```rust,ignore,does_not_compile
|
||||
mod branch1 {
|
||||
pub mod branch2 {
|
||||
fn leaf() {
|
||||
// code goes here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// absolute path
|
||||
crate::branch1::branch2::leaf();
|
||||
|
||||
// relative path
|
||||
branch1::branch2::leaf();
|
||||
}
|
||||
```
|
||||
|
||||
Adding the `pub` keyword in front of `mod branch2` makes the module public.
|
||||
This means that, if we're allowed to access `branch1`, we can access
|
||||
`branch2`. The contents of `branch2` are still private; that is, making the
|
||||
module public does not make its contents public. It purely lets code in its
|
||||
parent refer to it.
|
||||
|
||||
We still have an error, though:
|
||||
|
||||
```console
|
||||
> cargo build
|
||||
Compiling sampleproject v0.1.0 (file:///projects/sampleproject)
|
||||
error[E0603]: function `leaf` is private
|
||||
--> src\main.rs:10:5
|
||||
|
|
||||
10 | crate::branch1::branch2::leaf();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0603]: function `leaf` is private
|
||||
--> src\main.rs:12:5
|
||||
|
|
||||
12 | branch1::branch2::leaf();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
```
|
||||
|
||||
You can use `pub` on more than only modules; you can use it on structs,
|
||||
enums, and functions as well.
|
||||
|
||||
Let's make `leaf` public as well:
|
||||
|
||||
```rust,ignore
|
||||
mod branch1 {
|
||||
pub mod branch2 {
|
||||
pub fn leaf() {
|
||||
// code goes here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// absolute path
|
||||
crate::branch1::branch2::leaf();
|
||||
|
||||
// relative path
|
||||
branch1::branch2::leaf();
|
||||
}
|
||||
```
|
||||
|
||||
This will now compile! Let's look at both paths and double check why this
|
||||
works.
|
||||
|
||||
In the absolute path case, we start with `crate`, the root of our crate. From
|
||||
there, we have `branch1`, and it is a module that exists. It's not public,
|
||||
but because we're in the same module as it's defined, we're allowed to refer
|
||||
to it. Next is `branch2`, which is `pub`, so that's fine. Finally, `leaf`,
|
||||
which is also `pub`, so we're good!
|
||||
|
||||
In the relative path case, it's the exact same, without the first step.
|
||||
`branch1` is in the same module as us, so we're fine. `branch2` and `leaf`
|
||||
are `pub`. Everything checks out!
|
||||
|
||||
You can also construct relative paths using `super`. This is like `..` in a
|
||||
filesytem; that is, it says to start looking in the *parent* module, rather
|
||||
than the current module.
|
||||
|
||||
```rust,ignore
|
||||
mod foo {
|
||||
fn bar() {
|
||||
super::baz();
|
||||
}
|
||||
}
|
||||
|
||||
fn baz() {
|
||||
// code goes here
|
||||
}
|
||||
```
|
||||
|
||||
`bar` is in the `foo` module, so we can use `super` to go to its parent
|
||||
module, which in this case is `crate`, the root. From there, we look for
|
||||
`baz`, and find it. Success!
|
||||
|
||||
If you use `pub` on a struct, you can make the struct public, and also its
|
||||
members on a case-by-case basis:
|
||||
|
||||
```rust
|
||||
// this struct is public...
|
||||
pub struct Point {
|
||||
// ... and so is x ...
|
||||
pub x: i32,
|
||||
// ... but y is private
|
||||
y: i32,
|
||||
}
|
||||
```
|
||||
|
||||
If you make a public enum, all of its variants are public, so you only need
|
||||
the `pub` next to `enum`:
|
||||
|
||||
```rust
|
||||
pub enum ThisOrThat {
|
||||
This,
|
||||
That,
|
||||
}
|
||||
```
|
||||
|
||||
There's one more way to use `pub` that we haven't covered, and that's using it
|
||||
along with our last module system feature: `use`.
|
||||
|
||||
## `use` to bring paths into scope
|
||||
|
||||
If we look at our code, even though we only call `leaf` twice, there's a lot of
|
||||
duplication by specifying the whole path every time:
|
||||
|
||||
```rust,ignore
|
||||
mod branch1 {
|
||||
pub mod branch2 {
|
||||
pub fn leaf() {
|
||||
// code goes here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// here
|
||||
crate::branch1::branch2::leaf();
|
||||
|
||||
// and here
|
||||
branch1::branch2::leaf();
|
||||
}
|
||||
```
|
||||
|
||||
We can use the `use` keyword to fix this:
|
||||
|
||||
```rust,ignore
|
||||
|
||||
mod branch1 {
|
||||
pub mod branch2 {
|
||||
pub fn leaf() {
|
||||
// code goes here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use crate::branch1::branch2;
|
||||
|
||||
fn main() {
|
||||
// we can now do this!
|
||||
branch2::leaf();
|
||||
|
||||
// this still works too
|
||||
branch1::branch2::leaf();
|
||||
}
|
||||
```
|
||||
|
||||
If we say `use` and then a path, it's like creating a symlink in the
|
||||
filesystem. `branch2` is now a valid name in this module, just like any
|
||||
other. We can now reach it through the older, full paths, or this new path
|
||||
that we've created with `use`. `use` also checks privacy, like any other
|
||||
path.
|
||||
|
||||
If you want to use `use` with a relative path, there's a small wart: instead
|
||||
of being able to use a name in the current scope, you must prefix it with
|
||||
`self`:
|
||||
|
||||
```rust,ignore
|
||||
use self::branch1::branch2;
|
||||
```
|
||||
|
||||
This may not be neccesary in the future, but it's something to keep in mind
|
||||
currently. Your authors rarely use `self`, preferring to always use `crate`
|
||||
and absolute paths. This way, when you move code around, the imports it needs
|
||||
don't change. Up to you!
|
||||
|
||||
A brief note about idioms:
|
||||
|
||||
```rust,ignore
|
||||
// idiomatic import
|
||||
use crate::branch1::branch2;
|
||||
|
||||
// idiomatic call
|
||||
branch2::leaf();
|
||||
|
||||
// unidiomatic import
|
||||
use crate::branch1::branch2::leaf;
|
||||
|
||||
// unidiomatic call
|
||||
leaf();
|
||||
```
|
||||
|
||||
For functions, it's considered idiomatic to `use` the parent module, and
|
||||
use it to call the function that way. This makes it clear that it's not
|
||||
locally defined, while still minimizing boilerplate.
|
||||
|
||||
For structs, enums, and other things, importing them directly is idiomatic
|
||||
For example:
|
||||
|
||||
```rust,ignore
|
||||
// idiomatic
|
||||
use std::collections::HashMap;
|
||||
let map = HashMap::new();
|
||||
|
||||
// not idiomatic
|
||||
use std::collections;
|
||||
let map = collections::HashMap::new();
|
||||
```
|
||||
|
||||
The exception is if the names would clash:
|
||||
|
||||
```rust,ignore
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
|
||||
fn foo() -> fmt::Result<()> {
|
||||
fn foo() -> io::Result<()> {
|
||||
```
|
||||
|
||||
We couldn't bring both `Result`s into the same scope, or their names would
|
||||
clash.
|
||||
|
||||
## Making an import public with `pub use`
|
||||
|
||||
When you `use` something, it brings that name into scope, but it's private.
|
||||
If you want it to be public, you can combine `pub` and `use`:
|
||||
|
||||
```rust,ignore
|
||||
mod branch1 {
|
||||
use self::branch2::leaf;
|
||||
|
||||
mod branch2 {
|
||||
pub fn leaf() {
|
||||
// code goes here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this won't work
|
||||
use branch1::leaf;
|
||||
```
|
||||
|
||||
Here, while we can access `branch1` because it's in the same module, and
|
||||
`leaf` does exist inside of `branch1` thanks to `use`, it's private.
|
||||
|
||||
If we change it to `pub use self::branch2::leaf`, it would now be public
|
||||
and that line works!
|
||||
|
||||
`pub use` is sometimes nicknamed a "re-export", since you're both bringing
|
||||
something into scope, but also making it available for others to bring into
|
||||
their scope.
|
||||
|
||||
## Re-naming imports with `as`
|
||||
|
||||
Speaking of clashing names, we *could* solve this another way:
|
||||
|
||||
```rust,ignore
|
||||
use std::fmt::Result as FmtResult;
|
||||
use std::io::Result as IoResult;
|
||||
|
||||
fn foo() -> FmtResult<()> {
|
||||
fn foo() -> IoResult<()> {
|
||||
```
|
||||
|
||||
In other words, `as` lets us pick a differnet final name for this path. It
|
||||
will still refer to the original definition, but under a different name.
|
||||
Sometimes this can be a good way to avoid conflicts.
|
||||
|
||||
## Using external packages
|
||||
|
||||
If you read Chapter 2, you programmed a guessing game. That project used an
|
||||
external package, `rand`, to get random numbers. To use `rand` in your own
|
||||
project, you add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
rand = "0.5.5"
|
||||
```
|
||||
|
||||
And now, you can use `use` with the name of the crate, `rand`, to bring stuff into
|
||||
scope:
|
||||
|
||||
```rust,ignore
|
||||
use rand::Rng;
|
||||
|
||||
// Rng can now be used.
|
||||
```
|
||||
|
||||
It's that easy!
|
||||
|
||||
Note that the standard library is a crate, and that means it's external to your crate.
|
||||
You don't need to change `Cargo.toml` to include `std`, but you can refer to it in
|
||||
`use`:
|
||||
|
||||
```rust
|
||||
use std::collections::HashMap;
|
||||
```
|
||||
|
||||
This is an absolute path, starting with the name of the crate: `std`.
|
||||
|
||||
## Nested imports for cleaning up large import lists
|
||||
|
||||
The guessing game project also had multiple imports with a common
|
||||
prefix, like this:
|
||||
|
||||
```rust
|
||||
use std::io;
|
||||
use std::cmp::Ordering;
|
||||
```
|
||||
|
||||
We can use 'nested paths' to make this a bit shorter:
|
||||
|
||||
```rust
|
||||
use std::{
|
||||
io,
|
||||
cmp::Ordering,
|
||||
};
|
||||
```
|
||||
|
||||
Additionally, if we want to say, de-duplicate this:
|
||||
|
||||
```rust
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
```
|
||||
|
||||
We can use `self` in the nested path:
|
||||
|
||||
```rust
|
||||
use std::io::{self, Write};
|
||||
```
|
||||
|
||||
This brings both `std::io` and `std::io::Write` into scope.
|
||||
|
||||
## Glob imports with `*`
|
||||
|
||||
If you'd like to bring *all* public items into scope, you can use a glob
|
||||
import:
|
||||
|
||||
```rust
|
||||
use std::collections::*;
|
||||
```
|
||||
|
||||
Be careful with this! This makes it a little harder to tell what names are in
|
||||
scope.
|
||||
|
||||
Glob imports are often used when testing; we'll talk about that in Chapter
|
||||
11. They're also sometimes used as part of the "prelude pattern", see [the
|
||||
standard library documentation](../../std/prelude/index.html#other-preludes)
|
||||
for more.
|
||||
|
||||
## Putting modules in different files
|
||||
|
||||
Finally, you don't have to write all of your modules in the same file!
|
||||
Instead of writing this:
|
||||
|
||||
```rust
|
||||
mod branch1 {
|
||||
fn leaf() {
|
||||
// code goes here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can create a new file, `src/branch1.rs`, with this in it:
|
||||
|
||||
```rust
|
||||
fn leaf() {
|
||||
// code goes here
|
||||
}
|
||||
```
|
||||
|
||||
And then modify your `lib.rs` or `main.rs` like this:
|
||||
|
||||
```rust,ignore
|
||||
mod branch1;
|
||||
```
|
||||
|
||||
Using a `;` instead of a block tells Rust to load the contents of the module
|
||||
from another file. If we wanted to continue with our example, and put a
|
||||
sub-module inside of `src/branch1.rs`:
|
||||
|
||||
```rust,ignore
|
||||
mod branch2;
|
||||
```
|
||||
|
||||
We would need to create a sub-folder, and a file inside of it. They would be
|
||||
named `src/branch1/branch2.rs`. If `branch2` has any `mod` declarations inside
|
||||
of it, you'd keep going, making sub-folders as appropriate.
|
@ -1,304 +0,0 @@
|
||||
## Referring to Names in Different Modules
|
||||
|
||||
We’ve covered how to call functions defined within a module using the module
|
||||
name as part of the call, as in the call to the `nested_modules` function shown
|
||||
here in Listing 7-7:
|
||||
|
||||
<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 module’s 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
|
||||
|
||||
Rust’s `use` keyword shortens lengthy function calls by bringing the modules of
|
||||
the function you want to call into scope. Here’s an example of bringing the
|
||||
`a::series::of` module into a binary crate’s 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 we’ve specified into scope: it does not
|
||||
bring children of modules into scope. That’s 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
|
||||
enum’s variants into scope with `use` as well. For any kind of `use` statement,
|
||||
if you’re 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;
|
||||
}
|
||||
```
|
||||
|
||||
We’re still specifying the `TrafficLight` namespace for the `Green` variant
|
||||
because we didn’t include `Green` in the `use` statement.
|
||||
|
||||
#### Nested groups in `use` declarations
|
||||
|
||||
If you have a complex module tree with many different submodules and you need
|
||||
to import a few items from each one, it might be useful to group all the
|
||||
imports in the same declaration to keep your code clean and avoid repeating the
|
||||
base modules’ name.
|
||||
|
||||
The `use` declaration supports nesting to help you in those cases, both with
|
||||
simple imports and glob ones. For example this snippets imports `bar`, `Foo`,
|
||||
all the items in `baz` and `Bar`:
|
||||
|
||||
```rust
|
||||
# #![allow(unused_imports, dead_code)]
|
||||
#
|
||||
# mod foo {
|
||||
# pub mod bar {
|
||||
# pub type Foo = ();
|
||||
# }
|
||||
# pub mod baz {
|
||||
# pub mod quux {
|
||||
# pub type Bar = ();
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
#
|
||||
use foo::{
|
||||
bar::{self, Foo},
|
||||
baz::{*, quux::Bar},
|
||||
};
|
||||
#
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
### Bringing All Names into Scope with a Glob
|
||||
|
||||
To bring all the items in a namespace into scope at once, we can use the `*`
|
||||
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. Let’s 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 let’s try to call our
|
||||
`client::connect` function from this `it_works` function, even though we won’t
|
||||
be checking any functionality right now. This won’t 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 don’t 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 don’t look that different in this example, but if you’re
|
||||
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 you’ve specified the path from the
|
||||
root in many places in your code and then rearrange your modules by moving a
|
||||
subtree to another place, you’ll 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 you’ve
|
||||
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, we’ll look at some collection data structures in the standard library
|
||||
that you can use in your nice, neat code.
|
@ -136,7 +136,7 @@ element for. As an example, let’s see what a program will do if it has a vecto
|
||||
that holds five elements and then tries to access an element at index 100, as
|
||||
shown in Listing 8-7:
|
||||
|
||||
```rust,should_panic
|
||||
```rust,should_panic,panics
|
||||
let v = vec![1, 2, 3, 4, 5];
|
||||
|
||||
let does_not_exist = &v[100];
|
||||
@ -169,12 +169,14 @@ scope. That rule applies in Listing 8-8, where we hold an immutable reference to
|
||||
the first element in a vector and try to add an element to the end, which won’t
|
||||
work:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
let mut v = vec![1, 2, 3, 4, 5];
|
||||
|
||||
let first = &v[0];
|
||||
|
||||
v.push(6);
|
||||
|
||||
println!("The first element is: {}", first);
|
||||
```
|
||||
|
||||
<span class="caption">Listing 8-8: Attempting to add an element to a vector
|
||||
@ -184,16 +186,16 @@ Compiling this code will result in this error:
|
||||
|
||||
```text
|
||||
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
|
||||
-->
|
||||
|
|
||||
4 | let first = &v[0];
|
||||
| - immutable borrow occurs here
|
||||
5 |
|
||||
6 | v.push(6);
|
||||
| ^ mutable borrow occurs here
|
||||
7 |
|
||||
8 | }
|
||||
| - immutable borrow ends here
|
||||
--> src/main.rs:10:5
|
||||
|
|
||||
8 | let first = &v[0];
|
||||
| - immutable borrow occurs here
|
||||
9 |
|
||||
10 | v.push(6);
|
||||
| ^^^^^^^^^ mutable borrow occurs here
|
||||
11 |
|
||||
12 | println!("The first element is: {}", first);
|
||||
| ----- borrow later used here
|
||||
```
|
||||
|
||||
The code in Listing 8-8 might look like it should work: why should a reference
|
||||
|
@ -250,7 +250,7 @@ string by referencing them by index is a valid and common operation. However,
|
||||
if you try to access parts of a `String` using indexing syntax in Rust, you’ll
|
||||
get an error. Consider the invalid code in Listing 8-19:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
let s1 = String::from("hello");
|
||||
let h = s1[0];
|
||||
```
|
||||
@ -298,7 +298,7 @@ each Unicode scalar value in that string takes 2 bytes of storage. Therefore,
|
||||
an index into the string’s bytes will not always correlate to a valid Unicode
|
||||
scalar value. To demonstrate, consider this invalid Rust code:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
let hello = "Здравствуйте";
|
||||
let answer = &hello[0];
|
||||
```
|
||||
|
@ -261,7 +261,7 @@ loop, so all of these changes are safe and allowed by the borrowing rules.
|
||||
|
||||
### Hashing Functions
|
||||
|
||||
By default, `HashMap` uses a cryptographically secure hashing function that can
|
||||
By default, `HashMap` uses a "cryptographically strong"[^siphash] hashing function that can
|
||||
provide resistance to Denial of Service (DoS) attacks. This is not the fastest
|
||||
hashing algorithm available, but the trade-off for better security that comes
|
||||
with the drop in performance is worth it. If you profile your code and find
|
||||
@ -273,6 +273,8 @@ hasher from scratch; [crates.io](https://crates.io) has libraries shared by
|
||||
other Rust users that provide hashers implementing many common hashing
|
||||
algorithms.
|
||||
|
||||
[^siphash]: [https://www.131002.net/siphash/siphash.pdf](https://www.131002.net/siphash/siphash.pdf)
|
||||
|
||||
## Summary
|
||||
|
||||
Vectors, strings, and hash maps will provide a large amount of functionality
|
||||
|
@ -28,7 +28,7 @@ Let’s try calling `panic!` in a simple program:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,should_panic
|
||||
```rust,should_panic,panics
|
||||
fn main() {
|
||||
panic!("crash and burn");
|
||||
}
|
||||
@ -68,7 +68,7 @@ element by index in a vector:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,should_panic
|
||||
```rust,should_panic,panics
|
||||
fn main() {
|
||||
let v = vec![1, 2, 3];
|
||||
|
||||
|
@ -451,7 +451,6 @@ shorter:
|
||||
|
||||
```rust
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::fs;
|
||||
|
||||
fn read_username_from_file() -> Result<String, io::Error> {
|
||||
@ -490,25 +489,37 @@ fn main() {
|
||||
When we compile this code, we get the following error message:
|
||||
|
||||
```text
|
||||
error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
|
||||
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
|
||||
--> src/main.rs:4:13
|
||||
|
|
||||
4 | let f = File::open("hello.txt")?;
|
||||
| ------------------------
|
||||
| |
|
||||
| the `?` operator can only be used in a function that returns
|
||||
`Result` (or another type that implements `std::ops::Try`)
|
||||
| in this macro invocation
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
||||
|
|
||||
= help: the trait `std::ops::Try` is not implemented for `()`
|
||||
= note: required by `std::ops::Try::from_error`
|
||||
```
|
||||
|
||||
This error points out that we’re only allowed to use `?` in a function that
|
||||
returns `Result`. In functions that don’t return `Result`, when you call other
|
||||
functions that return `Result`, you’ll need to use a `match` or one of the
|
||||
`Result` methods to handle the `Result` instead of using `?` to potentially
|
||||
propagate the error to the calling code.
|
||||
returns `Result<T, E>`. In functions that don’t return `Result<T, E>`, when
|
||||
you call other functions that return `Result<T, E>`, you’ll need to use a
|
||||
`match` or one of the `Result<T, E>` methods to handle the `Result<T, E>`
|
||||
instead of using `?` to potentially propagate the error to the calling code.
|
||||
|
||||
However, the `main` function can return a `Result<T, E>`:
|
||||
|
||||
```rust,ignore
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let f = File::open("hello.txt")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
The `Box<dyn Error>` is called a "trait object", which we'll talk about in Chapter 17.
|
||||
For now, you can read `Box<dyn Error>` to mean "any kind of error."
|
||||
|
||||
Now that we’ve discussed the details of calling `panic!` or returning `Result`,
|
||||
let’s return to the topic of how to decide which is appropriate to use in which
|
||||
|
@ -163,7 +163,7 @@ tedious (and might impact performance).
|
||||
Instead, we can make a new type and put the validations in a function to create
|
||||
an instance of the type rather than repeating the validations everywhere. That
|
||||
way, it’s safe for functions to use the new type in their signatures and
|
||||
confidently use the values they receive. Listing 9-9 shows one way to define a
|
||||
confidently use the values they receive. Listing 9-10 shows one way to define a
|
||||
`Guess` type that will only create an instance of `Guess` if the `new` function
|
||||
receives a value between 1 and 100:
|
||||
|
||||
|
@ -94,7 +94,7 @@ compile yet, but we’ll fix it later in this chapter.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn largest<T>(list: &[T]) -> T {
|
||||
let mut largest = list[0];
|
||||
|
||||
@ -182,7 +182,7 @@ Listing 10-7, our code won’t compile.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
struct Point<T> {
|
||||
x: T,
|
||||
y: T,
|
||||
|
@ -301,18 +301,29 @@ say we wanted to take two things that implement `Summary`:
|
||||
|
||||
```rust,ignore
|
||||
pub fn notify(item1: impl Summary, item2: impl Summary) {
|
||||
```
|
||||
|
||||
This would work well if `item1` and `item2` were allowed to have diferent types
|
||||
(as long as both implement `Summary`). But what if you wanted to force both to
|
||||
have the exact same type? That is only possible if you use a trait bound:
|
||||
|
||||
```rust,ignore
|
||||
pub fn notify<T: Summary>(item1: T, item2: T) {
|
||||
```
|
||||
|
||||
The version with the bound is a bit easier. In general, you should use whatever
|
||||
form makes your code the most understandable.
|
||||
#### Specify multiple traits with `+`
|
||||
|
||||
##### Multiple trait bounds with `+`
|
||||
If `notify` needed to display formatting on `item`, as well as use the `summarize`
|
||||
method, then `item` would need to implement two different traits at the same time:
|
||||
`Display` and `Summary`. This can be done using the `+` syntax:
|
||||
|
||||
We can specify multiple trait bounds on a generic type using the `+` syntax.
|
||||
For example, to use display formatting on the type `T` in a function as well as
|
||||
the `summarize` method, we can use `T: Summary + Display` to say `T` can be any
|
||||
type that implements `Summary` and `Display`. This can grow quite complex!
|
||||
```rust,ignore
|
||||
pub fn notify(item: impl Summary + Display) {
|
||||
```
|
||||
This syntax is also valid with trait bounds on generic types:
|
||||
```rust,ignore
|
||||
pub fn notify<T: Summary + Display>(item: T) {
|
||||
```
|
||||
|
||||
#### `where` clauses for clearer code
|
||||
|
||||
@ -369,7 +380,7 @@ needing to write out a really long type.
|
||||
This only works if you have a single type that you're returning, however.
|
||||
For example, this would *not* work:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn returns_summarizable(switch: bool) -> impl Summary {
|
||||
if switch {
|
||||
NewsArticle {
|
||||
|
@ -23,7 +23,7 @@ program to reference data other than the data it’s intended to reference.
|
||||
Consider the program in Listing 10-17, which has an outer scope and an inner
|
||||
scope.
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
{
|
||||
let r;
|
||||
|
||||
@ -80,7 +80,7 @@ The Rust compiler has a *borrow checker* that compares scopes to determine
|
||||
whether all borrows are valid. Listing 10-18 shows the same code as Listing
|
||||
10-17 but with annotations showing the lifetimes of the variables.
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
{
|
||||
let r; // ---------+-- 'a
|
||||
// |
|
||||
@ -165,7 +165,7 @@ won’t compile.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn longest(x: &str, y: &str) -> &str {
|
||||
if x.len() > y.len() {
|
||||
x
|
||||
@ -345,7 +345,7 @@ compile.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
let string1 = String::from("long string is long");
|
||||
let result;
|
||||
@ -423,7 +423,7 @@ this attempted implementation of the `longest` function that won’t compile:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn longest<'a>(x: &str, y: &str) -> &'a str {
|
||||
let result = String::from("really long string");
|
||||
result.as_str()
|
||||
@ -576,6 +576,8 @@ and the second and third rules apply to output lifetimes. If the compiler gets
|
||||
to the end of the three rules and there are still references for which it can’t
|
||||
figure out lifetimes, the compiler will stop with an error.
|
||||
|
||||
These rules apply to `fn` definitions, as well as `impl` blocks.
|
||||
|
||||
The first rule is that each parameter that is a reference gets its own lifetime
|
||||
parameter. In other words, a function with one parameter gets one lifetime
|
||||
parameter: `fn foo<'a>(x: &'a i32)`; a function with two parameters gets two
|
||||
|
@ -157,7 +157,7 @@ which is to call the `panic!` macro. Enter the new test, `another`, so your
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
```rust
|
||||
```rust,panics
|
||||
# fn main() {}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
@ -340,7 +340,7 @@ introduce a bug in our code. Let’s change the implementation of the `can_hold`
|
||||
method by replacing the greater-than sign with a less-than sign when it
|
||||
compares the lengths:
|
||||
|
||||
```rust
|
||||
```rust,not_desired_behavior
|
||||
# fn main() {}
|
||||
# #[derive(Debug)]
|
||||
# pub struct Rectangle {
|
||||
@ -436,7 +436,7 @@ Let’s introduce a bug into our code to see what it looks like when a test that
|
||||
uses `assert_eq!` fails. Change the implementation of the `add_two` function to
|
||||
instead add `3`:
|
||||
|
||||
```rust
|
||||
```rust,not_desired_behavior
|
||||
# fn main() {}
|
||||
pub fn add_two(a: i32) -> i32 {
|
||||
a + 3
|
||||
@ -544,7 +544,7 @@ input parameter.
|
||||
Let’s introduce a bug into this code by changing `greeting` to not include
|
||||
`name` to see what this test failure looks like:
|
||||
|
||||
```rust
|
||||
```rust,not_desired_behavior
|
||||
# fn main() {}
|
||||
pub fn greeting(name: &str) -> String {
|
||||
String::from("Hello!")
|
||||
@ -602,7 +602,7 @@ debug what happened instead of what we were expecting to happen.
|
||||
In addition to checking that our code returns the correct values we expect,
|
||||
it’s also important to check that our code handles error conditions as we
|
||||
expect. For example, consider the `Guess` type that we created in Chapter 9,
|
||||
Listing 9-9. Other code that uses `Guess` depends on the guarantee that `Guess`
|
||||
Listing 9-10. Other code that uses `Guess` depends on the guarantee that `Guess`
|
||||
instances will contain only values between 1 and 100. We can write a test that
|
||||
ensures that attempting to create a `Guess` instance with a value outside that
|
||||
range panics.
|
||||
@ -663,7 +663,7 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
|
||||
Looks good! Now let’s introduce a bug in our code by removing the condition
|
||||
that the `new` function will panic if the value is greater than 100:
|
||||
|
||||
```rust
|
||||
```rust,not_desired_behavior
|
||||
# fn main() {}
|
||||
# pub struct Guess {
|
||||
# value: i32,
|
||||
@ -766,7 +766,7 @@ To see what happens when a `should_panic` test with an `expected` message
|
||||
fails, let’s again introduce a bug into our code by swapping the bodies of the
|
||||
`if value < 1` and the `else if value > 100` blocks:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,not_desired_behavior
|
||||
if value < 1 {
|
||||
panic!("Guess value must be less than or equal to 100, got {}.", value);
|
||||
} else if value > 100 {
|
||||
|
@ -61,7 +61,7 @@ parameter and returns 10, as well as a test that passes and a test that fails.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
```rust
|
||||
```rust,panics
|
||||
fn prints_and_returns_10(a: i32) -> i32 {
|
||||
println!("I got the value {}", a);
|
||||
10
|
||||
|
@ -58,7 +58,7 @@ First, we add another `use` statement to bring in a relevant part of the
|
||||
standard library: we need `std::fs` to handle files.
|
||||
|
||||
In `main`, we’ve added a new statement: `fs::read_to_string` will take the
|
||||
`filename`, open that file, and then produce a new `String` with its contents.
|
||||
`filename`, open that file, and then return `Result<String>` with its contents.
|
||||
|
||||
After that line, we’ve again added a temporary `println!` statement that
|
||||
prints the value of `contents` after the file is read, so we can check that the
|
||||
|
@ -306,7 +306,7 @@ fn new(args: &[String]) -> Config {
|
||||
<span class="caption">Listing 12-8: Adding a check for the number of
|
||||
arguments</span>
|
||||
|
||||
This code is similar to the `Guess::new` function we wrote in Listing 9-9, where
|
||||
This code is similar to the `Guess::new` function we wrote in Listing 9-10, where
|
||||
we called `panic!` when the `value` argument was out of the range of valid
|
||||
values. Instead of checking for a range of values here, we’re checking that the
|
||||
length of `args` is at least `3` and the rest of the function can operate under
|
||||
@ -328,7 +328,7 @@ note: Run with `RUST_BACKTRACE=1` for a backtrace.
|
||||
|
||||
This output is better: we now have a reasonable error message. However, we also
|
||||
have extraneous information we don’t want to give to our users. Perhaps using
|
||||
the technique we used in Listing 9-9 isn’t the best to use here: a call to
|
||||
the technique we used in Listing 9-10 isn’t the best to use here: a call to
|
||||
`panic!` is more appropriate for a programming problem rather than a usage
|
||||
problem, as discussed in Chapter 9. Instead, we can use the other technique you
|
||||
learned about in Chapter 9—returning a `Result` that indicates either success
|
||||
@ -669,4 +669,4 @@ modular. Almost all of our work will be done in *src/lib.rs* from here on out.
|
||||
|
||||
Let’s take advantage of this newfound modularity by doing something that would
|
||||
have been difficult with the old code but is easy with the new code: we’ll
|
||||
write some tests!
|
||||
write some tests!
|
@ -384,7 +384,7 @@ first time and a `u32` the second time, we’ll get an error.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
let example_closure = |x| x;
|
||||
|
||||
let s = example_closure(String::from("hello"));
|
||||
@ -634,7 +634,7 @@ The first problem is that a `Cacher` instance assumes it will always get the
|
||||
same value for the parameter `arg` to the `value` method. That is, this test of
|
||||
`Cacher` will fail:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,panics
|
||||
#[test]
|
||||
fn call_with_different_values() {
|
||||
let mut c = Cacher::new(|a| a);
|
||||
@ -714,7 +714,7 @@ code won’t compile:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
let x = 4;
|
||||
|
||||
@ -780,7 +780,7 @@ yet compile.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
let x = vec![1, 2, 3];
|
||||
|
||||
|
@ -168,7 +168,7 @@ incremented by 1. However, this code produces a warning:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
```rust,not_desired_behavior
|
||||
let v1: Vec<i32> = vec![1, 2, 3];
|
||||
|
||||
v1.iter().map(|x| x + 1);
|
||||
|
@ -106,7 +106,7 @@ we’ll demonstrate.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
enum List {
|
||||
Cons(i32, List),
|
||||
Nil,
|
||||
|
@ -131,7 +131,7 @@ code in Listing 15-9 won’t compile because Rust doesn’t know how to derefere
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = MyBox::new(x);
|
||||
|
@ -95,7 +95,7 @@ compiler error:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
let c = CustomSmartPointer { data: String::from("some data") };
|
||||
println!("CustomSmartPointer created.");
|
||||
|
@ -50,7 +50,7 @@ won’t work, as shown in Listing 15-17:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
enum List {
|
||||
Cons(i32, Box<List>),
|
||||
Nil,
|
||||
|
@ -77,7 +77,7 @@ examine how it’s possible.
|
||||
A consequence of the borrowing rules is that when you have an immutable value,
|
||||
you can’t borrow it mutably. For example, this code won’t compile:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = &mut x;
|
||||
@ -195,7 +195,7 @@ implement a mock object to do just that, but the borrow checker won’t allow it
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
```rust
|
||||
```rust,does_not_compile
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -353,7 +353,7 @@ at runtime.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,panics
|
||||
impl Messenger for MockMessenger {
|
||||
fn send(&self, message: &str) {
|
||||
let mut one_borrow = self.sent_messages.borrow_mut();
|
||||
|
@ -254,7 +254,7 @@ thread. However, this won’t yet work, as you’ll see in a moment.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
@ -303,7 +303,7 @@ that won’t be valid:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
|
@ -169,7 +169,7 @@ this code isn't allowed:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
use std::thread;
|
||||
use std::sync::mpsc;
|
||||
|
||||
|
@ -109,7 +109,7 @@ starting example:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
use std::sync::Mutex;
|
||||
use std::thread;
|
||||
|
||||
@ -187,7 +187,7 @@ Let’s figure this out by simplifying the program. Instead of making 10 threads
|
||||
in a `for` loop, let’s just make two threads without a loop and see what
|
||||
happens. Replace the first `for` loop in Listing 16-13 with this code instead:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
use std::sync::Mutex;
|
||||
use std::thread;
|
||||
|
||||
@ -269,7 +269,7 @@ errors, we’ll also switch back to using the `for` loop, and we’ll keep the
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
use std::rc::Rc;
|
||||
use std::sync::Mutex;
|
||||
use std::thread;
|
||||
|
@ -295,7 +295,7 @@ with a `String` as a component:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
extern crate gui;
|
||||
use gui::Screen;
|
||||
|
||||
@ -396,7 +396,7 @@ rules of object safety in regard to trait objects. For example, let’s say we
|
||||
tried to implement the `Screen` struct in Listing 17-4 to hold types that
|
||||
implement the `Clone` trait instead of the `Draw` trait, like this:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
pub struct Screen {
|
||||
pub components: Vec<Box<dyn Clone>>,
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ in the tuple, the overall type won’t match and we’ll get a compiler error. F
|
||||
example, Listing 18-5 shows an attempt to destructure a tuple with three
|
||||
elements into two variables, which won’t work.
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
let (x, y) = (1, 2, 3);
|
||||
```
|
||||
|
||||
|
@ -26,7 +26,7 @@ where Rust requires an irrefutable pattern and vice versa. Listing 18-8 shows a
|
||||
`let` statement, but for the pattern we’ve specified `Some(x)`, a refutable
|
||||
pattern. As you might expect, this code will not compile.
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
let Some(x) = some_option_value;
|
||||
```
|
||||
|
||||
@ -71,7 +71,7 @@ cannot use an irrefutable pattern without receiving an error. If we give `if
|
||||
let` a pattern that will always match, such as `x`, as shown in Listing 18-10,
|
||||
it will not compile.
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
if let x = 5 {
|
||||
println!("{}", x);
|
||||
};
|
||||
|
@ -579,7 +579,7 @@ that starts with an underscore. The syntax `_x` still binds the value to the
|
||||
variable, whereas `_` doesn’t bind at all. To show a case where this
|
||||
distinction matters, Listing 18-21 will provide us with an error.
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
let s = Some(String::from("Hello!"));
|
||||
|
||||
if let Some(_s) = s {
|
||||
@ -674,7 +674,7 @@ compile.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
let numbers = (2, 4, 8, 16, 32);
|
||||
|
||||
|
@ -126,7 +126,7 @@ Recall that we can create raw pointers in safe code, but we can’t *dereference
|
||||
raw pointers and read the data being pointed to. In Listing 19-3, we use the
|
||||
dereference operator `*` on a raw pointer that requires an `unsafe` block.
|
||||
|
||||
```rust
|
||||
```rust,unsafe
|
||||
let mut num = 5;
|
||||
|
||||
let r1 = &num as *const i32;
|
||||
@ -174,7 +174,7 @@ responsibility for upholding the function’s contracts.
|
||||
Here is an unsafe function named `dangerous` that doesn’t do anything in its
|
||||
body:
|
||||
|
||||
```rust
|
||||
```rust,unsafe
|
||||
unsafe fn dangerous() {}
|
||||
|
||||
unsafe {
|
||||
@ -231,7 +231,7 @@ something like Listing 19-5, which won’t compile. For simplicity, we’ll
|
||||
implement `split_at_mut` as a function rather than a method and only for slices
|
||||
of `i32` values rather than for a generic type `T`.
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
|
||||
let len = slice.len();
|
||||
|
||||
@ -278,7 +278,7 @@ know code is okay, but Rust doesn’t, it’s time to reach for unsafe code.
|
||||
Listing 19-6 shows how to use an `unsafe` block, a raw pointer, and some calls
|
||||
to unsafe functions to make the implementation of `split_at_mut` work.
|
||||
|
||||
```rust
|
||||
```rust,unsafe
|
||||
use std::slice;
|
||||
|
||||
fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
|
||||
@ -332,7 +332,7 @@ In contrast, the use of `slice::from_raw_parts_mut` in Listing 19-7 would
|
||||
likely crash when the slice is used. This code takes an arbitrary memory
|
||||
location and creates a slice 10,000 items long.
|
||||
|
||||
```rust
|
||||
```rust,unsafe
|
||||
use std::slice;
|
||||
|
||||
let address = 0x01234usize;
|
||||
@ -370,7 +370,7 @@ responsibility falls on the programmer to ensure safety.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
```rust,unsafe
|
||||
extern "C" {
|
||||
fn abs(input: i32) -> i32;
|
||||
}
|
||||
@ -459,7 +459,7 @@ static variable named `COUNTER`.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
```rust,unsafe
|
||||
static mut COUNTER: u32 = 0;
|
||||
|
||||
fn add_to_count(inc: u32) {
|
||||
@ -500,7 +500,7 @@ compiler can’t verify. We can declare that a trait is `unsafe` by adding the
|
||||
`unsafe` keyword before `trait` and marking the implementation of the trait as
|
||||
`unsafe` too, as shown in Listing 19-11.
|
||||
|
||||
```rust
|
||||
```rust,unsafe
|
||||
unsafe trait Foo {
|
||||
// methods go here
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ have the required lifetime annotations, so it won’t compile.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
struct Context(&str);
|
||||
|
||||
struct Parser {
|
||||
@ -100,7 +100,7 @@ returns. This code doesn’t quite work.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn parse_context(context: Context) -> Result<(), &str> {
|
||||
Parser { context: &context }.parse()
|
||||
}
|
||||
@ -214,7 +214,7 @@ sufficient when we try to compile.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
struct Context<'s>(&'s str);
|
||||
|
||||
struct Parser<'c, 's> {
|
||||
@ -317,7 +317,7 @@ struct is shown in Listing 19-16, without lifetime bounds for now.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
struct Ref<'a, T>(&'a T);
|
||||
```
|
||||
|
||||
|
@ -429,7 +429,7 @@ Listing 19-28, we’ll get a compilation error.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn main() {
|
||||
println!("A baby dog is called a {}", Animal::baby_name());
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ At the time, we skipped over some details in this code. In Chapter 6 in “The
|
||||
`match` Control Flow Operator” section, we discussed that `match` arms must all
|
||||
return the same type. So, for example, the following code doesn’t work:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
let guess = match guess.trim().parse() {
|
||||
Ok(_) => 5,
|
||||
Err(_) => "hello",
|
||||
@ -273,7 +273,7 @@ its own, is a DST. We can’t know how long the string is until runtime, meaning
|
||||
we can’t create a variable of type `str`, nor can we take an argument of type
|
||||
`str`. Consider the following code, which does not work:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
let s1: str = "Hello there!";
|
||||
let s2: str = "How's it going?";
|
||||
```
|
||||
|
@ -83,6 +83,25 @@ named `to_string`. Here, we’re using the `to_string` function defined in the
|
||||
`ToString` trait, which the standard library has implemented for any type that
|
||||
implements `Display`.
|
||||
|
||||
Another useful pattern exploits an implementation detail of tuple structs and
|
||||
tuple-struct enum variants. These items use `()` as initialiser syntax, which
|
||||
looks like a function call, and they're actually implemented as functions
|
||||
returning an instance constructed from their arguments. They can also be called
|
||||
as a function pointer implementing the closure traits, and so can be used
|
||||
similarly to the above:
|
||||
|
||||
```rust
|
||||
enum Status {
|
||||
Value(u32),
|
||||
Stop,
|
||||
}
|
||||
|
||||
let list_of_statuses: Vec<Status> =
|
||||
(0u32..20)
|
||||
.map(Status::Value)
|
||||
.collect();
|
||||
```
|
||||
|
||||
Some people prefer this style, and some people prefer to use closures. They end
|
||||
up compiling to the same code, so use whichever style is clearer to you.
|
||||
|
||||
@ -97,7 +116,7 @@ pointer `fn` as a return type, for example.
|
||||
|
||||
The following code tries to return a closure directly, but it won’t compile:
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
fn returns_closure() -> Fn(i32) -> i32 {
|
||||
|x| x + 1
|
||||
}
|
||||
|
528
src/doc/book/2018-edition/src/ch19-06-macros.md
Normal file
528
src/doc/book/2018-edition/src/ch19-06-macros.md
Normal file
@ -0,0 +1,528 @@
|
||||
## Macros
|
||||
|
||||
We’ve used macros like `println!` throughout this book but haven’t fully
|
||||
explored what a macro is and how it works. There's a lot more to them,
|
||||
though; "macros" refer to a family of different features in Rust:
|
||||
|
||||
* *Declarative* macros with `macro_rules`
|
||||
* *Procedural*, which have three sub-kinds:
|
||||
* Custom `#[derive]`s
|
||||
* Attribute-like macros
|
||||
* Function-like macros
|
||||
|
||||
We'll talk about each of these in turn, but first, why do we even
|
||||
need macros when we already have functions?
|
||||
|
||||
### The Difference Between Macros and Functions
|
||||
|
||||
Fundamentally, macros are a way of writing code that writes other code, which
|
||||
is known as *metaprogramming*. In Appendix C, we discussed the `derive`
|
||||
attribute, which generates an implementation of various traits for you. We’ve
|
||||
also used the `println!` and `vec!` macros throughout the book. All of these
|
||||
macros *expand* to produce more code than the code you’ve written manually.
|
||||
|
||||
Metaprogramming is useful for reducing the amount of code you have to write and
|
||||
maintain, which is also one of the roles of functions. However, macros have
|
||||
some additional powers that functions don’t have.
|
||||
|
||||
A function signature must declare the number and type of parameters the
|
||||
function has. Macros, on the other hand, can take a variable number of
|
||||
parameters: we can call `println!("hello")` with one argument or
|
||||
`println!("hello {}", name)` with two arguments. Also, macros are expanded
|
||||
before the compiler interprets the meaning of the code, so a macro can, for
|
||||
example, implement a trait on a given type. A function can’t, because it gets
|
||||
called at runtime and a trait needs to be implemented at compile time.
|
||||
|
||||
The downside to implementing a macro instead of a function is that macro
|
||||
definitions are more complex than function definitions because you’re writing
|
||||
Rust code that writes Rust code. Due to this indirection, macro definitions are
|
||||
generally more difficult to read, understand, and maintain than function
|
||||
definitions.
|
||||
|
||||
There is one last important difference between macros and functions: you must
|
||||
define or bring macros into scope *before* you call them in a file, whereas you
|
||||
can define functions anywhere and call them anywhere.
|
||||
|
||||
### Declarative Macros with `macro_rules!` for General Metaprogramming
|
||||
|
||||
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; in this situation, the value is the literal Rust
|
||||
source code passed to the macro, the patterns are compared with the structure
|
||||
of that source code, and the code associated with each pattern is the code that
|
||||
replaces the code passed to the macro. This all happens during compilation.
|
||||
|
||||
To define a macro, you use the `macro_rules!` construct. Let’s explore how to
|
||||
use `macro_rules!` by looking at how the `vec!` macro is defined. Chapter 8
|
||||
covered how we can use the `vec!` macro to create a new vector with particular
|
||||
values. For example, the following macro creates a new vector with three
|
||||
integers inside:
|
||||
|
||||
```rust
|
||||
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 wouldn’t be able to use a function to do the same
|
||||
because we wouldn’t know the number or type of values up front.
|
||||
|
||||
Let’s look at a slightly simplified definition of the `vec!` macro in Listing
|
||||
D-1.
|
||||
|
||||
```rust
|
||||
#[macro_export]
|
||||
macro_rules! vec {
|
||||
( $( $x:expr ),* ) => {
|
||||
{
|
||||
let mut temp_vec = Vec::new();
|
||||
$(
|
||||
temp_vec.push($x);
|
||||
)*
|
||||
temp_vec
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing D-1: A simplified version of the `vec!` macro
|
||||
definition</span>
|
||||
|
||||
> Note: The actual definition of the `vec!` macro in the standard library
|
||||
> includes code to preallocate the correct amount of memory up front. That code
|
||||
> is an optimization that we don’t include here to make the example simpler.
|
||||
|
||||
The `#[macro_export]` annotation indicates that this macro should be made
|
||||
available whenever the crate in which we’re defining the macro is imported.
|
||||
Without this annotation, the macro can't be brought into scope.
|
||||
|
||||
We then start the macro definition with `macro_rules!` and the name of the
|
||||
macro we’re defining *without* the exclamation mark. The name, in this case
|
||||
`vec`, is followed by curly brackets denoting the body of the macro definition.
|
||||
|
||||
The structure in the `vec!` body is similar to the structure of a `match`
|
||||
expression. Here we have one arm with the pattern `( $( $x:expr ),* )`,
|
||||
followed by `=>` and the block of code associated with this pattern. If the
|
||||
pattern matches, the associated block of code will be emitted. Given that this
|
||||
is the only pattern in this macro, there is only one valid way to match; any
|
||||
other will be an error. More complex macros will have more than one arm.
|
||||
|
||||
Valid pattern syntax in macro definitions is different than the pattern syntax
|
||||
covered in Chapter 18 because macro patterns are matched against Rust code
|
||||
structure rather than values. Let’s walk through what the pieces of the pattern
|
||||
in Listing D-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 let’s look at the pattern in the body of the code associated with this arm:
|
||||
the `temp_vec.push()` code within the `$()*` part is generated for each part
|
||||
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 the following:
|
||||
|
||||
```rust,ignore
|
||||
let mut temp_vec = Vec::new();
|
||||
temp_vec.push(1);
|
||||
temp_vec.push(2);
|
||||
temp_vec.push(3);
|
||||
temp_vec
|
||||
```
|
||||
|
||||
We’ve defined a macro that can take any number of arguments of any type and can
|
||||
generate code to create a vector containing the specified elements.
|
||||
|
||||
There are some strange corners with `macro_rules!`. In the future, there
|
||||
will be a second kind of declarative macro, with the `macro` keyword, that
|
||||
will work in a similar fashion, but fix some of these edge cases. After that
|
||||
is done, `macro_rules` will be effectively deprecated. With this
|
||||
in mind, as well as the fact that most Rust programmers will *use* macros
|
||||
more than *write* macros, we won’t discuss `macro_rules!` any further. To
|
||||
learn more about how to write macros, consult the online documentation or
|
||||
other resources, such as [“The Little Book of Rust Macros”][tlborm].
|
||||
|
||||
[tlborm]: https://danielkeep.github.io/tlborm/book/index.html
|
||||
|
||||
## Procedural macros
|
||||
|
||||
The second form of macros is called *procedural macros* because they’re more
|
||||
like functions (which are a type of procedure). Procedural macros accept some
|
||||
Rust code as an input, operate on that code, and produce some Rust code as an
|
||||
output rather than matching against patterns and replacing the code with other
|
||||
code as declarative macros do.
|
||||
|
||||
While there are three kinds of procedural macros, they all work in a similar
|
||||
fashion. First, they must reside in their own crate, with a special crate type.
|
||||
This is for complex technical reasons that we hope to eliminate in the future,
|
||||
and so won't discuss here. Second, they all take a form like this:
|
||||
|
||||
```rust,ignore
|
||||
extern crate proc_macro;
|
||||
|
||||
#[some_attribute]
|
||||
pub fn some_name(input: TokenStream) -> TokenStream {
|
||||
}
|
||||
```
|
||||
|
||||
First, the `extern crate` line. `extern crate` is a holdover from the old
|
||||
Rust module system; for now, when defining a proc macro, you must add this
|
||||
line to your `src/lib.rs`. Someday, this will not be necessary.
|
||||
|
||||
Second, procedural macros consist of a function, which is how they get their
|
||||
name: "procedure" is a synonym for "function." Why not call them "functional
|
||||
macros"? Well, one of the types is "function-like", and that would get
|
||||
confusing. Anyway, the function takes a `TokenStream` as an input, and
|
||||
produces a `TokenStream` as an output. This is the core of the macro;
|
||||
the source that the macro is operating on makes up the input `TokenStream`,
|
||||
and the code we produce from our macro is the output `TokenStream`.
|
||||
We'll talk more about `TokenStream` when we actually build one of these
|
||||
things. Finally, the function has an attribute on it; this attribute
|
||||
says which kind of procedural macro we're creating. We can have multiple
|
||||
kinds of procedual macros in the same crate.
|
||||
|
||||
Given that the kinds of macros are so similar, we'll start with a custom
|
||||
derive macro, and then in the other sections, we'll explain the small
|
||||
differences that make the other forms different.
|
||||
|
||||
### Custom Derive
|
||||
|
||||
Let's create a crate named `hello_macro` that defines a trait named
|
||||
`HelloMacro` with one associated function named `hello_macro`. Rather than
|
||||
making our crate users implement the `HelloMacro` trait for each of their
|
||||
types, we’ll provide a procedural macro so users can annotate their type with
|
||||
`#[derive(HelloMacro)]` to get a default implementation of the `hello_macro`
|
||||
function. The default implementation will print `Hello, Macro! My name is
|
||||
TypeName!` where `TypeName` is the name of the type on which this trait has
|
||||
been defined. In other words, we’ll write a crate that enables another
|
||||
programmer to write code like Listing D-2 using our crate.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
use hello_macro::HelloMacro;
|
||||
|
||||
#[derive(HelloMacro)]
|
||||
struct Pancakes;
|
||||
|
||||
fn main() {
|
||||
Pancakes::hello_macro();
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing D-2: The code a user of our crate will be able to
|
||||
write when using our procedural macro</span>
|
||||
|
||||
This code will print `Hello, Macro! My name is Pancakes!` when we’re done. The
|
||||
first step is to make a new library crate, like this:
|
||||
|
||||
```text
|
||||
$ cargo new hello_macro --lib
|
||||
```
|
||||
|
||||
Next, we’ll 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, our crate user could implement
|
||||
the trait to achieve the desired functionality, like so:
|
||||
|
||||
```rust,ignore
|
||||
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 the implementation block for each type they
|
||||
wanted to use with `hello_macro`; we want to spare them from having to do this
|
||||
work.
|
||||
|
||||
Additionally, we can’t yet provide a default implementation for the
|
||||
`hello_macro` function that will print the name of the type the trait is
|
||||
implemented on: Rust doesn’t have reflection capabilities, so it can’t look up
|
||||
the type’s name at runtime. We need a macro to generate code at compile time.
|
||||
|
||||
The next step is to define the procedural macro. At the time of this writing,
|
||||
procedural macros need to be in their own crate. Eventually, this restriction
|
||||
might be lifted. The convention for structuring crates and macro crates is as
|
||||
follows: for a crate named `foo`, a custom derive procedural macro crate is
|
||||
called `foo_derive`. Let’s start a new crate called `hello_macro_derive` inside
|
||||
our `hello_macro` project:
|
||||
|
||||
```text
|
||||
$ cargo new hello_macro_derive --lib
|
||||
```
|
||||
|
||||
Our two crates are tightly related, so we create the procedural macro crate
|
||||
within the directory of our `hello_macro` crate. If we change the trait
|
||||
definition in `hello_macro`, we’ll have to change the implementation of the
|
||||
procedural macro in `hello_macro_derive` as well. The two crates will need to
|
||||
be published separately, and programmers using these crates will need to add
|
||||
both as dependencies and bring them both into scope. We could instead have the
|
||||
`hello_macro` crate use `hello_macro_derive` as a dependency and reexport the
|
||||
procedural macro code. But the way we’ve structured the project makes it
|
||||
possible for programmers to use `hello_macro` even if they don’t want the
|
||||
`derive` functionality.
|
||||
|
||||
We need to declare the `hello_macro_derive` crate as a procedural macro crate.
|
||||
We’ll also need functionality from the `syn` and `quote` crates, as you’ll see
|
||||
in a moment, so we need to add them as dependencies. Add the following to the
|
||||
*Cargo.toml* file for `hello_macro_derive`:
|
||||
|
||||
<span class="filename">Filename: hello_macro_derive/Cargo.toml</span>
|
||||
|
||||
```toml
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = "0.14.4"
|
||||
quote = "0.6.3"
|
||||
```
|
||||
|
||||
To start defining the procedural macro, place the code in Listing D-3 into your
|
||||
*src/lib.rs* file for the `hello_macro_derive` crate. Note that this code won’t
|
||||
compile until we add a definition for the `impl_hello_macro` function.
|
||||
|
||||
<span class="filename">Filename: hello_macro_derive/src/lib.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn;
|
||||
|
||||
#[proc_macro_derive(HelloMacro)]
|
||||
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
|
||||
// Construct a represntation of Rust code as a syntax tree
|
||||
// that we can manipulate
|
||||
let ast = syn::parse(input).unwrap();
|
||||
|
||||
// Build the trait implementation
|
||||
impl_hello_macro(&ast)
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing D-3: Code that most procedural macro crates will
|
||||
need to have for processing Rust code</span>
|
||||
|
||||
Notice the way we’ve split the functions in D-3; this will be the same for
|
||||
almost every procedural macro crate you see or create, because it makes writing
|
||||
a procedural macro more convenient. What you choose to do in the place where
|
||||
the `impl_hello_macro` function is called will be different depending on your
|
||||
procedural macro’s purpose.
|
||||
|
||||
We’ve introduced three new crates: `proc_macro`, [`syn`], and [`quote`]. The
|
||||
`proc_macro` crate comes with Rust, so we didn’t need to add that to the
|
||||
dependencies in *Cargo.toml*. The `proc_macro` crate is the compiler's API to
|
||||
be able to read and manipulate Rust code from our 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. The reason is that we’ve annotated
|
||||
the `hello_macro_derive` function here with `proc_macro_derive` and specified
|
||||
the name, `HelloMacro`, which matches our trait name; that’s the convention
|
||||
most procedural macros follow.
|
||||
|
||||
This function first converts the `input` from a `TokenStream` to a data
|
||||
structure that we can then interpret and perform operations on. This is where
|
||||
`syn` comes into play. The `parse` function in `syn` takes a `TokenStream` and
|
||||
returns a `DeriveInput` struct representing the parsed Rust code. The following
|
||||
code shows the relevant parts of the `DeriveInput` struct we get from parsing
|
||||
the string `struct Pancakes;`:
|
||||
|
||||
```rust,ignore
|
||||
DeriveInput {
|
||||
// --snip--
|
||||
|
||||
ident: Ident(
|
||||
"Pancakes"
|
||||
),
|
||||
body: Struct(
|
||||
Unit
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
The fields of this struct show that the Rust code we’ve parsed is a unit struct
|
||||
with the `ident` (identifier, meaning the name) of `Pancakes`. There are more
|
||||
fields on this struct for describing all sorts of Rust code; check the [`syn`
|
||||
documentation for `DeriveInput`][syn-docs] for more information.
|
||||
|
||||
[syn-docs]: https://docs.rs/syn/0.11.11/syn/struct.DeriveInput.html
|
||||
|
||||
At this point, we haven’t defined the `impl_hello_macro` function, which is
|
||||
where we’ll build the new Rust code we want to include. But before we do, note
|
||||
that its output is also a `TokenStream` which is added to the code that our
|
||||
crate users write, so when they compile their crate, they’ll get extra
|
||||
functionality that we provide.
|
||||
|
||||
You might have noticed that we’re calling `unwrap` to panic if the call to the
|
||||
`syn::parse`function fails here. Panicking on errors is necessary in procedural
|
||||
macro code because `proc_macro_derive` functions must return `TokenStream`
|
||||
rather than `Result` to conform to the procedural macro API. We’ve chosen to
|
||||
simplify this example by using `unwrap`; in production code, you should provide
|
||||
more specific error messages about what went wrong by using `panic!` or `expect`.
|
||||
|
||||
Now that we have the code to turn the annotated Rust code from a `TokenStream`
|
||||
into a `DeriveInput` instance, let’s generate the code that implements 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) -> TokenStream {
|
||||
let name = &ast.ident;
|
||||
let gen = quote! {
|
||||
impl HelloMacro for #name {
|
||||
fn hello_macro() {
|
||||
println!("Hello, Macro! My name is {}", stringify!(#name));
|
||||
}
|
||||
}
|
||||
};
|
||||
gen.into()
|
||||
}
|
||||
```
|
||||
|
||||
We get an `Ident` struct instance containing the name (identifier) of the
|
||||
annotated type using `ast.ident`. The code in Listing D-2 specifies that the
|
||||
`name` will be `Ident("Pancakes")`.
|
||||
|
||||
The `quote!` macro lets us write the Rust code that we want to return, but the
|
||||
direct result of its execution is not what is expected by the compiler and needs
|
||||
to be converted to a `TokenStream` by calling the `into` method. `into` consumes
|
||||
this intermediate representation and returns a value of the required type.
|
||||
|
||||
This macro also provides some very cool templating mechanics; we can write
|
||||
`#name`, and `quote!` will replace it with the value in the variable named
|
||||
`name`. You can even do some repetition similar
|
||||
to the way regular macros work. Check out [the `quote` crate’s docs][quote-docs]
|
||||
for a thorough introduction.
|
||||
|
||||
[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`. There is a possibility that the `#name` input might be an expression
|
||||
to print literally, so we use `stringify!`. Using `stringify!` also saves an
|
||||
allocation by converting `#name` to a string literal at compile time.
|
||||
|
||||
At this point, `cargo build` should complete successfully in both `hello_macro`
|
||||
and `hello_macro_derive`. Let’s hook up these crates to the code in Listing D-2
|
||||
to see the procedural macro in action! Create a new binary project in your
|
||||
*projects* directory using `cargo new pancakes`. We need to add
|
||||
`hello_macro` and `hello_macro_derive` as dependencies in the `pancakes`
|
||||
crate’s *Cargo.toml*. If you’re publishing your versions of `hello_macro` and
|
||||
`hello_macro_derive` to *https://crates.io/*, they would be regular
|
||||
dependencies; if not, you can specify them as `path` dependencies as follows:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
hello_macro = { path = "../hello_macro" }
|
||||
hello_macro_derive = { path = "../hello_macro/hello_macro_derive" }
|
||||
```
|
||||
|
||||
Put the code from Listing D-2 into *src/main.rs*, and run `cargo run`: it
|
||||
should print `Hello, Macro! My name is Pancakes!` The implementation of the
|
||||
`HelloMacro` trait from the procedural macro was included without the
|
||||
`pancakes` crate needing to implement it; the `#[derive(HelloMacro)]` added the
|
||||
trait implementation.
|
||||
|
||||
### Attribute-like macros
|
||||
|
||||
Attribute-like macros are similar to custom derive macros, but instead of
|
||||
generating code for `#[derive]`, they allow you to create new, custom
|
||||
attributes of your own. They're also more flexible; derive only works for
|
||||
structs and enums; attributes can go on other places as well, like functions.
|
||||
As an example of using an attribute-like macro, you might have something like
|
||||
this when using a web application framework:
|
||||
|
||||
```rust,ignore
|
||||
#[route(GET, "/")]
|
||||
fn index() {
|
||||
```
|
||||
|
||||
This `#[route]` attribute would be defined by the framework itself, as a
|
||||
procedural macro. Its signature would look like this:
|
||||
|
||||
```rust,ignore
|
||||
#[proc_macro_attribute]
|
||||
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
```
|
||||
|
||||
Here, we have two input `TokenStream`s; the first is for the contents of the
|
||||
attribute itself, that is, the `GET, "/"` stuff. The second is the body of
|
||||
the thing the attribute is attached to, in this case, `fn index() {}` and the
|
||||
rest of the function's body.
|
||||
|
||||
Other than that, they work the same way: create a crate with the `proc-macro`
|
||||
crate type, and you're good to go!
|
||||
|
||||
### Function-like macros
|
||||
|
||||
Finally, function-like macros define macros that look like function calls. For
|
||||
example, an `sql!` macro:
|
||||
|
||||
```rust,ignore
|
||||
let sql = sql!(SELECT * FROM posts WHERE id=1);
|
||||
```
|
||||
|
||||
This macro would parse the SQL statement inside of it and check that it's
|
||||
syntactically correct. This macro would be defined like this:
|
||||
|
||||
```rust,ignore
|
||||
#[proc_macro]
|
||||
pub fn sql(input: TokenStream) -> TokenStream {
|
||||
```
|
||||
|
||||
This is similar to the derive macro's signature: we get in the tokens that are
|
||||
inside of the parentheses, and return the code we wanted to generate.
|
@ -482,7 +482,7 @@ returned a `ThreadPool` instance containing them.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,not_desired_behavior
|
||||
use std::thread;
|
||||
|
||||
pub struct ThreadPool {
|
||||
@ -727,7 +727,7 @@ the closure. The code in Listing 20-17 won’t quite compile yet.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
impl ThreadPool {
|
||||
// --snip--
|
||||
pub fn new(size: usize) -> ThreadPool {
|
||||
@ -891,7 +891,7 @@ types shorter. Look at Listing 20-19.
|
||||
# use std::sync::mpsc;
|
||||
# struct Worker {}
|
||||
|
||||
type Job = Box<dyn FnOnce() + Send + 'static>;
|
||||
type Job = Box<FnOnce() + Send + 'static>;
|
||||
|
||||
impl ThreadPool {
|
||||
// --snip--
|
||||
@ -929,7 +929,7 @@ shown in Listing 20-20 to `Worker::new`.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
// --snip--
|
||||
|
||||
impl Worker {
|
||||
@ -995,11 +995,11 @@ the value inside the `Box<T>` will be: recall in Chapter 15 that we used
|
||||
to store in a `Box<T>` to get a value of a known size.
|
||||
|
||||
As you saw in Listing 17-15, we can write methods that use the syntax `self:
|
||||
Box<dyn Self>`, which allows the method to take ownership of a `Self` value stored
|
||||
Box<Self>`, which allows the method to take ownership of a `Self` value stored
|
||||
in a `Box<T>`. That’s exactly what we want to do here, but unfortunately Rust
|
||||
won’t let us: the part of Rust that implements behavior when a closure is
|
||||
called isn’t implemented using `self: Box<dyn Self>`. So Rust doesn’t yet
|
||||
understand that it could use `self: Box<dyn Self>` in this situation to take
|
||||
called isn’t implemented using `self: Box<Self>`. So Rust doesn’t yet
|
||||
understand that it could use `self: Box<Self>` in this situation to take
|
||||
ownership of the closure and move the closure out of the `Box<T>`.
|
||||
|
||||
Rust is still a work in progress with places where the compiler could be
|
||||
@ -1009,9 +1009,9 @@ finished this book, we would love for you to join in.
|
||||
|
||||
But for now, let’s work around this problem using a handy trick. We can tell
|
||||
Rust explicitly that in this case we can take ownership of the value inside the
|
||||
`Box<T>` using `self: Box<dyn Self>`; then, once we have ownership of the closure,
|
||||
`Box<T>` using `self: Box<Self>`; then, once we have ownership of the closure,
|
||||
we can call it. This involves defining a new trait `FnBox` with the method
|
||||
`call_box` that will use `self: Box<dyn Self>` in its signature, defining `FnBox`
|
||||
`call_box` that will use `self: Box<Self>` in its signature, defining `FnBox`
|
||||
for any type that implements `FnOnce()`, changing our type alias to use the new
|
||||
trait, and changing `Worker` to use the `call_box` method. These changes are
|
||||
shown in Listing 20-21.
|
||||
@ -1029,7 +1029,7 @@ impl<F: FnOnce()> FnBox for F {
|
||||
}
|
||||
}
|
||||
|
||||
type Job = Box<dyn FnBox + Send + 'static>;
|
||||
type Job = Box<FnBox + Send + 'static>;
|
||||
|
||||
// --snip--
|
||||
|
||||
@ -1054,11 +1054,11 @@ impl Worker {
|
||||
```
|
||||
|
||||
<span class="caption">Listing 20-21: Adding a new trait `FnBox` to work around
|
||||
the current limitations of `Box<dyn FnOnce()>`</span>
|
||||
the current limitations of `Box<FnOnce()>`</span>
|
||||
|
||||
First, we create a new trait named `FnBox`. This trait has the one method
|
||||
`call_box`, which is similar to the `call` methods on the other `Fn*` traits
|
||||
except that it takes `self: Box<dyn Self>` to take ownership of `self` and move the
|
||||
except that it takes `self: Box<Self>` to take ownership of `self` and move the
|
||||
value out of the `Box<T>`.
|
||||
|
||||
Next, we implement the `FnBox` trait for any type `F` that implements the
|
||||
@ -1136,7 +1136,7 @@ why we didn’t write the worker thread code as shown in Listing 20-22.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,not_desired_behavior
|
||||
// --snip--
|
||||
|
||||
impl Worker {
|
||||
|
@ -23,7 +23,7 @@ quite work yet.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
```rust,ignore,does_not_compile
|
||||
impl Drop for ThreadPool {
|
||||
fn drop(&mut self) {
|
||||
for worker in &mut self.workers {
|
||||
@ -59,7 +59,7 @@ The error tells us we can’t call `join` because we only have a mutable borrow
|
||||
of each `worker` and `join` takes ownership of its argument. To solve this
|
||||
issue, we need to move the thread out of the `Worker` instance that owns
|
||||
`thread` so `join` can consume the thread. We did this in Listing 17-15: if
|
||||
`Worker` holds an `Option<thread::JoinHandle<()>` instead, we can call the
|
||||
`Worker` holds an `Option<thread::JoinHandle<()>>` instead, we can call the
|
||||
`take` method on the `Option` to move the value out of the `Some` variant and
|
||||
leave a `None` variant in its place. In other words, a `Worker` that is running
|
||||
will have a `Some` variant in `thread`, and when we want to clean up a
|
||||
|
@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="1259px" height="847px" viewBox="0 0 1259 847" enable-background="new 0 0 1259 847" xml:space="preserve">
|
||||
<!--<rect fill="#FFFFFF" width="1259" height="847"/>-->
|
||||
<path fill="#8F1F1D" d="M706.403,338.05c-131.633,0-251.228,15.825-339.77,41.615v220.298
|
||||
c88.542,25.79,208.137,41.614,339.77,41.614c150.657,0,285.535-20.729,376.134-53.402V391.457
|
||||
C991.938,358.781,857.06,338.05,706.403,338.05"/>
|
||||
<path fill="#8F1F1D" d="M1088.423,537.442c-3.856-10.663-4.629-24.154-1.36-37.162c5.85-23.289,22.421-36.198,37.013-28.833
|
||||
c3.618,1.827,6.773,4.73,9.387,8.418c0.239-0.001,0.479,0,0.715,0.016c0,0,44.552,53.106,3.313,116.003
|
||||
c-0.896,3.569-76.534,91.718-94.043,94.524C1031.987,692.244,1058.338,600.41,1088.423,537.442"/>
|
||||
<path fill="#8F1F1D" d="M357.479,527.021c5.3-9.631,7.158-22.788,4.217-36.426c-5.266-24.416-23.91-41.109-41.642-37.285
|
||||
c-4.398,0.948-8.325,3.072-11.666,6.099c-0.282-0.059-0.564-0.113-0.845-0.153c0,0-56.292,41.952-12.057,113.924
|
||||
c0.805,3.741,83.851,108.838,104.311,115.764C413.188,693.475,388.55,596.418,357.479,527.021"/>
|
||||
<path fill="#E23A26" d="M280.467,535.066l0.007,0.015C280.659,535.226,280.831,535.357,280.467,535.066"/>
|
||||
<path fill="#E33B26" d="M1174.119,457.903c-0.88-3.064-1.756-6.126-2.662-9.162l30.683-44.451c3.13-4.522,3.771-10.398,1.73-15.555
|
||||
c-2.04-5.13-6.49-8.81-11.76-9.71l-51.887-8.805c-2.008-4.102-4.115-8.142-6.229-12.15l21.797-49.903
|
||||
c2.243-5.087,1.769-10.995-1.203-15.608c-2.961-4.636-7.99-7.344-13.349-7.133l-52.656,1.913c-2.727-3.55-5.496-7.068-8.322-10.521
|
||||
l12.102-53.49c1.225-5.433-0.322-11.118-4.104-15.064c-3.762-3.932-9.229-5.559-14.426-4.283l-51.289,12.608
|
||||
c-3.321-2.935-6.699-5.833-10.114-8.673l1.849-54.914c0.197-5.559-2.394-10.842-6.845-13.925
|
||||
c-4.445-3.104-10.093-3.573-14.955-1.266l-47.848,22.747c-3.854-2.21-7.728-4.4-11.644-6.517l-8.455-54.115
|
||||
c-0.857-5.483-4.386-10.139-9.326-12.266c-4.923-2.137-10.568-1.447-14.891,1.808l-42.659,32.007
|
||||
c-4.2-1.395-8.419-2.732-12.692-4.011l-18.386-51.316c-1.87-5.229-6.182-9.071-11.438-10.151c-5.238-1.072-10.63,0.742-14.263,4.802
|
||||
L764.97,100.97c-4.342-0.5-8.685-0.956-13.043-1.331l-27.723-46.713c-2.811-4.732-7.771-7.612-13.116-7.612
|
||||
c-5.334,0-10.304,2.88-13.09,7.612l-27.733,46.713c-4.358,0.375-8.722,0.831-13.056,1.331l-35.91-40.171
|
||||
c-3.636-4.06-9.047-5.874-14.268-4.802c-5.255,1.092-9.573,4.922-11.433,10.151l-18.402,51.316
|
||||
c-4.26,1.279-8.481,2.627-12.691,4.011l-42.644-32.007c-4.336-3.266-9.98-3.955-14.916-1.808c-4.919,2.127-8.461,6.783-9.313,12.266
|
||||
l-8.461,54.115c-3.914,2.117-7.789,4.294-11.653,6.517l-47.842-22.747c-4.858-2.316-10.529-1.838-14.954,1.266
|
||||
c-4.445,3.083-7.042,8.366-6.84,13.925l1.835,54.914c-3.405,2.84-6.774,5.738-10.112,8.673l-51.279-12.608
|
||||
c-5.211-1.265-10.67,0.351-14.441,4.283c-3.795,3.946-5.332,9.631-4.113,15.064l12.079,53.49c-2.802,3.467-5.575,6.971-8.293,10.521
|
||||
l-52.655-1.913c-5.314-0.157-10.386,2.497-13.356,7.133c-2.974,4.613-3.425,10.521-1.211,15.608l21.814,49.903
|
||||
c-2.119,4.008-4.224,8.048-6.249,12.15l-51.882,8.805c-5.271,0.888-9.715,4.566-11.765,9.71c-2.037,5.157-1.375,11.033,1.735,15.555
|
||||
l30.69,44.451c-0.236,0.784-0.455,1.576-0.69,2.364l-16.863,17.911l45.341,64.05c0,0,435.152,200.731,838.797,3.396
|
||||
C1163.372,528.189,1174.119,457.903,1174.119,457.903"/>
|
||||
<path d="M788.629,436.277c0,0,54.108-46.602,95.626,11.5c0,0,29.173,74.328-12.593,104.708c0,0-67.353,41.473-95.627-11.5
|
||||
C776.035,540.985,739.67,497.66,788.629,436.277"/>
|
||||
<path fill="#FFFFFF" d="M843.648,464.356c-2.452,20.385-16.456,35.467-31.276,33.684c-14.817-1.781-24.846-19.755-22.395-40.14
|
||||
c2.452-20.385,16.457-35.468,31.274-33.687C836.071,425.997,846.1,443.971,843.648,464.356"/>
|
||||
<path d="M572.949,399.315c0,0,86.384-26.449,99.021,57.297c0,0,12.086,97.294-79.356,91.705
|
||||
C592.613,548.317,479.508,512.09,572.949,399.315"/>
|
||||
<rect x="181" y="45" fill="none" width="1060" height="782"/>
|
||||
<path fill="#FFFFFF" d="M611.925,441.324c-2.528,21.021-16.969,36.581-32.257,34.742c-15.281-1.837-25.624-20.378-23.095-41.399
|
||||
c2.529-21.026,16.973-36.581,32.253-34.743C604.113,401.763,614.454,420.298,611.925,441.324"/>
|
||||
<path fill="#E33B26" d="M292.602,544.216c10.967-12.463,37.611-27.557,35.57-46.282c-3.653-33.526-31.456-57.999-62.099-54.658
|
||||
c-7.599,0.827-14.658,3.292-20.923,7.035c-0.463-0.106-0.925-0.211-1.388-0.294c0,0-103.632,50.873-44.564,152.657
|
||||
c0.557,5.137,117.847,155.668,150.787,167.131C371.544,777.307,330.074,641.165,292.602,544.216"/>
|
||||
<path fill="#E33B26" d="M1134.549,539.673c-12.692-10.7-46.162-20.418-46.92-39.238c-1.355-33.697,22.512-62.021,53.312-63.26
|
||||
c7.638-0.308,14.983,1.083,21.734,3.857c0.442-0.174,0.884-0.347,1.329-0.497c0,0,110.025,34.951,66.695,144.366
|
||||
c0.21,5.163-93.468,171.416-124.345,187.635C1086.146,783.151,1111.861,641.105,1134.549,539.673"/>
|
||||
<rect x="181.06" y="45.314" fill="none" width="1059.75" height="781.686"/>
|
||||
<path fill="#E33B26" d="M372.142,545.559c0,0-1.383,137.296,133.166,167.933l28.054-56.363c0,0-97.495,9.431-104.995-111.569
|
||||
H372.142"/>
|
||||
<rect x="181" y="45" fill="none" width="1060" height="782"/>
|
||||
<path fill="#E33B26" d="M1057.362,537.246c0,0,1.382,137.296-133.167,167.933l-28.055-56.363c0,0,97.495,9.431,104.995-111.569
|
||||
H1057.362"/>
|
||||
<path fill="#E33B26" d="M960.167,677.279c-20.25-48.941-85.595-68.373-145.951-43.399c-53.126,21.98-84.637,71.031-77.624,115.845
|
||||
c41.946-0.652,86.94-3.371,130.736-9.718c0,0-25.837,41.763-63.857,78.211c25.566,6.599,55.383,4.768,84.076-7.104
|
||||
C947.904,786.141,980.417,726.221,960.167,677.279"/>
|
||||
<path fill="#E33B26" d="M585.746,745.985c0,0,55.203,7.295,130.67,9.155c6.61-47.511-29.38-97.792-86.801-117.242
|
||||
c-63.438-21.488-128.989,2.792-146.414,54.231c-17.425,51.44,19.876,110.561,83.314,132.049
|
||||
c28.121,9.526,56.653,10.049,81.229,3.207C610.833,790.881,585.746,745.985,585.746,745.985"/>
|
||||
<rect x="181.06" y="45.314" fill="none" width="1059.75" height="781.686"/>
|
||||
<g>
|
||||
<path d="M92.314,318.146l0.072-12.563c-0.359-24.665,8.95-49.384,31.787-73.989c16.267-18.129,29.512-33.493,30.216-49.411
|
||||
c0.747-16.883-9.835-28.95-33.932-30.499c-15.918-0.704-35.468,4.231-48.394,12.359l-14.075-53.303
|
||||
c18.296-9.34,47.182-17.729,81.429-16.214c63.672,2.816,91.538,39.33,89.768,79.366c-1.621,36.659-25.84,59.753-45.066,79.202
|
||||
c-18.24,19.009-26.789,37.48-27.267,59.207l-0.384,8.683L92.314,318.146z M76.808,384.64c1.152-26.048,19.789-43.105,44.872-41.997
|
||||
c26.047,1.152,42.14,19.746,41.471,45.815c-1.109,25.083-18.824,43.148-45.353,41.975C92.232,429.303,75.698,409.723,76.808,384.64
|
||||
z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.6 KiB |
@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="1354px" height="819px" viewBox="0 0 1354 819" enable-background="new 0 0 1354 819" xml:space="preserve">
|
||||
<!--<rect fill="#FFFFFF" width="1354" height="819"/>-->
|
||||
<path fill="#8F1F1D" d="M803.403,312.05c-131.633,0-251.228,15.825-339.77,41.615v220.298
|
||||
c88.542,25.79,208.137,41.614,339.77,41.614c150.657,0,285.535-20.729,376.134-53.402V365.457
|
||||
C1088.938,332.781,954.06,312.05,803.403,312.05"/>
|
||||
<path fill="#8F1F1D" d="M1185.423,511.442c-3.856-10.663-4.629-24.154-1.36-37.162c5.85-23.289,22.421-36.198,37.013-28.833
|
||||
c3.618,1.827,6.773,4.73,9.387,8.418c0.239-0.001,0.479,0,0.715,0.016c0,0,44.552,53.106,3.313,116.003
|
||||
c-0.896,3.569-76.534,91.718-94.043,94.524C1128.987,666.244,1155.338,574.41,1185.423,511.442"/>
|
||||
<path fill="#8F1F1D" d="M454.479,501.021c5.3-9.631,7.158-22.788,4.217-36.426c-5.266-24.416-23.91-41.109-41.642-37.285
|
||||
c-4.398,0.948-8.325,3.072-11.666,6.099c-0.282-0.059-0.564-0.113-0.845-0.153c0,0-56.292,41.952-12.057,113.924
|
||||
c0.805,3.741,83.851,108.838,104.311,115.764C510.188,667.475,485.55,570.418,454.479,501.021"/>
|
||||
<path fill="#E23A26" d="M375.467,507.066l0.007,0.015C375.659,507.226,375.831,507.357,375.467,507.066"/>
|
||||
<path fill="#E33B26" d="M1271.119,431.903c-0.88-3.064-1.756-6.126-2.662-9.162l30.683-44.451c3.13-4.522,3.771-10.398,1.73-15.555
|
||||
c-2.04-5.13-6.49-8.81-11.76-9.71l-51.887-8.805c-2.008-4.102-4.115-8.142-6.229-12.15l21.797-49.903
|
||||
c2.243-5.087,1.769-10.995-1.203-15.608c-2.961-4.636-7.99-7.344-13.349-7.133l-52.656,1.913c-2.727-3.55-5.496-7.068-8.322-10.521
|
||||
l12.102-53.49c1.225-5.433-0.322-11.118-4.104-15.064c-3.762-3.932-9.229-5.559-14.426-4.283l-51.289,12.608
|
||||
c-3.321-2.935-6.699-5.833-10.114-8.673l1.849-54.914c0.197-5.559-2.394-10.842-6.845-13.925
|
||||
c-4.445-3.104-10.093-3.573-14.955-1.266l-47.848,22.747c-3.854-2.21-7.728-4.4-11.644-6.517l-8.455-54.115
|
||||
c-0.857-5.483-4.386-10.139-9.326-12.266c-4.923-2.137-10.568-1.447-14.891,1.808l-42.659,32.007
|
||||
c-4.2-1.395-8.419-2.732-12.692-4.011l-18.386-51.316c-1.87-5.229-6.182-9.071-11.438-10.151c-5.238-1.072-10.63,0.742-14.263,4.802
|
||||
L861.97,74.97c-4.342-0.5-8.685-0.956-13.043-1.331l-27.723-46.713c-2.811-4.732-7.771-7.612-13.116-7.612
|
||||
c-5.334,0-10.304,2.88-13.09,7.612l-27.733,46.713c-4.358,0.375-8.722,0.831-13.056,1.331l-35.91-40.171
|
||||
c-3.636-4.06-9.047-5.874-14.268-4.802c-5.255,1.092-9.573,4.922-11.433,10.151l-18.402,51.316
|
||||
c-4.26,1.279-8.481,2.627-12.691,4.011l-42.644-32.007c-4.336-3.266-9.98-3.955-14.916-1.808c-4.919,2.127-8.461,6.783-9.313,12.266
|
||||
l-8.461,54.115c-3.914,2.117-7.789,4.294-11.653,6.517l-47.842-22.747c-4.858-2.316-10.529-1.838-14.954,1.266
|
||||
c-4.445,3.083-7.042,8.366-6.84,13.925l1.835,54.914c-3.405,2.84-6.774,5.738-10.112,8.673l-51.279-12.608
|
||||
c-5.211-1.265-10.67,0.351-14.441,4.283c-3.795,3.946-5.332,9.631-4.113,15.064l12.079,53.49c-2.802,3.467-5.575,6.971-8.293,10.521
|
||||
l-52.655-1.913c-5.314-0.157-10.386,2.497-13.356,7.133c-2.974,4.613-3.425,10.521-1.211,15.608l21.814,49.903
|
||||
c-2.119,4.008-4.224,8.048-6.249,12.15l-51.882,8.805c-5.271,0.888-9.715,4.566-11.765,9.71c-2.037,5.157-1.375,11.033,1.735,15.555
|
||||
l30.69,44.451c-0.236,0.784-0.455,1.576-0.69,2.364l-16.863,17.911l45.341,64.05c0,0,435.152,200.731,838.797,3.396
|
||||
C1260.372,502.189,1271.119,431.903,1271.119,431.903"/>
|
||||
<path d="M886.303,395.759c0,0,48.157-52.729,96.315,0c0,0,37.84,70.312,0,105.463c0,0-61.917,49.218-96.315,0
|
||||
C886.303,501.222,845.024,462.55,886.303,395.759"/>
|
||||
<path fill="#FFFFFF" d="M942.057,415.32c0,20.532-12.103,37.179-27.029,37.179c-14.924,0-27.027-16.646-27.027-37.179
|
||||
s12.104-37.18,27.027-37.18C929.954,378.14,942.057,394.788,942.057,415.32"/>
|
||||
<path d="M671.365,381.361c0,0,82.608-36.576,105.154,45.062c0,0,23.618,95.154-67.837,100.525
|
||||
C708.682,526.948,592.06,504.486,671.365,381.361"/>
|
||||
<rect x="278" y="19" fill="none" width="1060" height="782"/>
|
||||
<g>
|
||||
<defs>
|
||||
<rect id="SVGID_1_" x="278.06" y="19.314" width="1059.75" height="781.686"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_2_">
|
||||
<use xlink:href="#SVGID_1_" overflow="visible"/>
|
||||
</clipPath>
|
||||
<path clip-path="url(#SVGID_2_)" fill="#FFFFFF" d="M712.855,416.668c0,21.173-12.48,38.346-27.877,38.346
|
||||
c-15.391,0-27.874-17.173-27.874-38.346c0-21.178,12.483-38.346,27.874-38.346C700.375,378.322,712.855,395.49,712.855,416.668"/>
|
||||
<path clip-path="url(#SVGID_2_)" fill="#E33B26" d="M389.602,518.216c10.967-12.463,37.611-27.557,35.57-46.282
|
||||
c-3.653-33.526-31.456-57.999-62.099-54.658c-7.599,0.827-14.658,3.292-20.923,7.035c-0.463-0.106-0.925-0.211-1.388-0.294
|
||||
c0,0-103.632,50.873-44.564,152.657c0.557,5.137,117.847,155.668,150.787,167.131C468.544,751.307,427.074,615.165,389.602,518.216
|
||||
"/>
|
||||
<path clip-path="url(#SVGID_2_)" fill="#E33B26" d="M1231.549,513.673c-12.692-10.7-46.162-20.418-46.92-39.238
|
||||
c-1.355-33.697,22.512-62.021,53.312-63.26c7.638-0.308,14.983,1.083,21.734,3.857c0.442-0.174,0.884-0.347,1.329-0.497
|
||||
c0,0,110.025,34.951,66.695,144.366c0.21,5.163-93.468,171.416-124.345,187.635
|
||||
C1183.146,757.151,1208.861,615.105,1231.549,513.673"/>
|
||||
</g>
|
||||
<rect x="278" y="19" fill="none" width="1060" height="782"/>
|
||||
<path fill="#E33B26" d="M1154.362,514.558c0,0,1.382,137.296-133.167,167.933l-28.055-56.363c0,0,97.495,9.431,104.995-111.569
|
||||
H1154.362"/>
|
||||
<path fill="#E33B26" d="M1057.167,654.591c-20.25-48.941-85.595-68.373-145.951-43.399c-53.126,21.98-84.637,71.031-77.624,115.845
|
||||
c41.946-0.652,86.94-3.371,130.736-9.718c0,0-25.837,41.763-63.857,78.211c25.566,6.599,55.383,4.768,84.076-7.104
|
||||
C1044.904,763.452,1077.417,703.532,1057.167,654.591"/>
|
||||
<g>
|
||||
<path fill="#E33B26" d="M396.635,512.763c0,0-120.426,65.951-210.88-38.262l36.479-51.313c0,0,37.649,90.426,147.893,39.991
|
||||
L396.635,512.763"/>
|
||||
<path fill="#E33B26" d="M144.038,392.655c0,0-46.915-29.995-114.487-63.65C3.436,369.241,14.735,430.034,58.509,471.979
|
||||
c48.361,46.34,118.025,52.115,155.601,12.901c37.576-39.214,28.833-108.569-19.528-154.908
|
||||
c-21.437-20.543-47.061-33.103-72.221-37.316C140.333,341.359,144.038,392.655,144.038,392.655"/>
|
||||
</g>
|
||||
<rect x="278.06" y="19.314" fill="none" width="1059.75" height="781.686"/>
|
||||
</svg>
|
After Width: | Height: | Size: 6.2 KiB |
70
src/doc/book/2018-edition/src/img/ferris/panics.svg
Normal file
70
src/doc/book/2018-edition/src/img/ferris/panics.svg
Normal file
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="1434.979px" height="947px" viewBox="0 0 1434.979 947" enable-background="new 0 0 1434.979 947" xml:space="preserve">
|
||||
<!--<rect fill="#FFFFFF" width="1434.979" height="947"/>-->
|
||||
<path fill="#8F1F1D" d="M712.827,368.579c-131.633,0-251.228,15.825-339.77,41.615v220.298
|
||||
c88.542,25.79,208.137,41.614,339.77,41.614c150.657,0,285.535-20.729,376.134-53.402V421.986
|
||||
C998.361,389.311,863.483,368.579,712.827,368.579"/>
|
||||
<path fill="#8F1F1D" d="M1094.847,567.972c-3.856-10.663-4.629-24.154-1.36-37.162c5.85-23.289,22.421-36.198,37.013-28.833
|
||||
c3.618,1.827,6.773,4.73,9.387,8.418c0.239-0.001,0.479,0,0.715,0.016c0,0,44.552,53.106,3.313,116.003
|
||||
c-0.896,3.569-76.534,91.718-94.043,94.524C1038.411,722.773,1064.762,630.939,1094.847,567.972"/>
|
||||
<path fill="#8F1F1D" d="M363.903,557.551c5.3-9.631,7.158-22.788,4.217-36.426c-5.266-24.416-23.91-41.109-41.642-37.285
|
||||
c-4.398,0.948-8.325,3.072-11.666,6.099c-0.282-0.059-0.564-0.113-0.845-0.153c0,0-56.292,41.952-12.057,113.924
|
||||
c0.805,3.741,83.851,108.838,104.311,115.764C419.612,724.004,394.974,626.947,363.903,557.551"/>
|
||||
<path fill="#E23A26" d="M284.891,563.596l0.007,0.015C285.083,563.755,285.255,563.887,284.891,563.596"/>
|
||||
<path fill="#E33B26" d="M1180.543,488.433c-0.88-3.064-1.756-6.126-2.662-9.162l30.683-44.451c3.13-4.522,3.771-10.398,1.73-15.555
|
||||
c-2.04-5.13-6.49-8.81-11.76-9.71l-51.887-8.805c-2.008-4.102-4.115-8.142-6.229-12.15l21.797-49.903
|
||||
c2.243-5.087,1.769-10.995-1.203-15.608c-2.961-4.636-7.99-7.344-13.349-7.133l-52.656,1.913c-2.727-3.55-5.496-7.068-8.322-10.521
|
||||
l12.102-53.49c1.225-5.433-0.322-11.118-4.104-15.064c-3.762-3.932-9.229-5.559-14.426-4.283l-51.289,12.608
|
||||
c-3.321-2.935-6.699-5.833-10.114-8.673l1.849-54.914c0.197-5.559-2.394-10.842-6.845-13.925
|
||||
c-4.445-3.104-10.093-3.573-14.955-1.266l-47.848,22.747c-3.854-2.21-7.728-4.4-11.644-6.517l-8.455-54.115
|
||||
c-0.857-5.483-4.386-10.139-9.326-12.266c-4.923-2.137-10.568-1.447-14.891,1.808l-42.659,32.007
|
||||
c-4.2-1.395-8.419-2.732-12.692-4.011l-18.386-51.316c-1.87-5.229-6.182-9.071-11.438-10.151c-5.238-1.072-10.63,0.742-14.263,4.802
|
||||
l-35.907,40.171c-4.342-0.5-8.685-0.956-13.043-1.331l-27.723-46.713c-2.811-4.732-7.771-7.612-13.116-7.612
|
||||
c-5.334,0-10.304,2.88-13.09,7.612l-27.733,46.713c-4.358,0.375-8.722,0.831-13.056,1.331l-35.91-40.171
|
||||
c-3.636-4.06-9.047-5.874-14.268-4.802c-5.255,1.092-9.573,4.922-11.433,10.151l-18.402,51.316
|
||||
c-4.26,1.279-8.481,2.627-12.691,4.011l-42.644-32.007c-4.336-3.266-9.98-3.955-14.916-1.808c-4.919,2.127-8.461,6.783-9.313,12.266
|
||||
l-8.461,54.115c-3.914,2.117-7.789,4.294-11.653,6.517L436.1,168.34c-4.858-2.316-10.529-1.838-14.954,1.266
|
||||
c-4.445,3.083-7.042,8.366-6.84,13.925l1.835,54.914c-3.405,2.84-6.774,5.738-10.112,8.673L354.75,234.51
|
||||
c-5.211-1.265-10.67,0.351-14.441,4.283c-3.795,3.946-5.332,9.631-4.113,15.064l12.079,53.49c-2.802,3.467-5.575,6.971-8.293,10.521
|
||||
l-52.655-1.913c-5.314-0.157-10.386,2.497-13.356,7.133c-2.974,4.613-3.425,10.521-1.211,15.608l21.814,49.903
|
||||
c-2.119,4.008-4.224,8.048-6.249,12.15l-51.882,8.805c-5.271,0.888-9.715,4.566-11.765,9.71c-2.037,5.157-1.375,11.033,1.735,15.555
|
||||
l30.69,44.451c-0.236,0.784-0.455,1.576-0.69,2.364l-16.863,17.911l45.341,64.05c0,0,435.152,200.731,838.797,3.396
|
||||
C1169.796,558.719,1180.543,488.433,1180.543,488.433"/>
|
||||
<path d="M795.716,446.557c0,0,48.162-52.734,96.324,0c0,0,37.844,70.318,0,105.473c0,0-61.922,49.223-96.324,0
|
||||
C795.716,552.029,754.434,513.354,795.716,446.557"/>
|
||||
<path fill="#FFFFFF" d="M855.154,481.097c0,19.782-11.66,35.82-26.041,35.82c-14.379,0-26.04-16.038-26.04-35.82
|
||||
c0-19.782,11.661-35.821,26.04-35.821C843.494,445.275,855.154,461.315,855.154,481.097"/>
|
||||
<path d="M578.401,430.129c0,0,84.436-37.385,107.481,46.059c0,0,24.141,97.261-69.339,102.751
|
||||
C616.543,578.939,497.34,555.98,578.401,430.129"/>
|
||||
<rect x="187.424" y="75.529" fill="none" width="1060" height="782"/>
|
||||
<path fill="#FFFFFF" d="M627.514,481.096c0,20.579-12.13,37.27-27.095,37.27c-14.959,0-27.092-16.69-27.092-37.27
|
||||
c0-20.583,12.133-37.27,27.092-37.27C615.384,443.826,627.514,460.513,627.514,481.096"/>
|
||||
<path fill="#E33B26" d="M299.026,574.745c10.967-12.463,37.611-27.557,35.57-46.282c-3.653-33.526-31.456-57.999-62.099-54.658
|
||||
c-7.599,0.827-14.658,3.292-20.923,7.035c-0.463-0.106-0.925-0.211-1.388-0.294c0,0-103.632,50.873-44.564,152.657
|
||||
c0.557,5.137,117.847,155.668,150.787,167.131C377.968,807.836,336.498,671.694,299.026,574.745"/>
|
||||
<path fill="#E33B26" d="M1140.973,570.202c-12.692-10.7-46.162-20.418-46.92-39.238c-1.355-33.697,22.512-62.021,53.312-63.26
|
||||
c7.638-0.308,14.983,1.083,21.734,3.857c0.442-0.174,0.884-0.347,1.329-0.497c0,0,110.025,34.951,66.695,144.366
|
||||
c0.21,5.163-93.468,171.416-124.345,187.635C1092.57,813.681,1118.285,671.635,1140.973,570.202"/>
|
||||
<rect x="187.484" y="75.843" fill="none" width="1059.75" height="781.686"/>
|
||||
<rect x="187.424" y="75.529" fill="none" width="1060" height="782"/>
|
||||
<g>
|
||||
<path fill="#E33B26" d="M283.144,565.511c0,0-137.214-4.942-161.62-140.761l57.596-25.427c0,0-13.912,96.957,106.615,110.022
|
||||
L283.144,565.511"/>
|
||||
<path fill="#E33B26" d="M127.552,333.083c0,0-24.965-49.774-65.807-113.261C18.721,241.035-2.671,299.05,13.482,357.484
|
||||
c17.846,64.558,74.749,105.16,127.097,90.69s80.318-78.535,62.471-143.092c-7.909-28.618-23.501-52.519-42.963-69.011
|
||||
C150.611,287.113,127.552,333.083,127.552,333.083"/>
|
||||
</g>
|
||||
<rect x="187.484" y="75.843" fill="none" width="1059.75" height="781.686"/>
|
||||
<g>
|
||||
<path fill="#E33B26" d="M1148.012,565.511c0,0,137.214-4.942,161.62-140.761l-57.596-25.428c0,0,13.912,96.957-106.615,110.022
|
||||
L1148.012,565.511"/>
|
||||
<path fill="#E33B26" d="M1303.604,333.083c0,0,24.966-49.774,65.808-113.261c43.023,21.212,64.416,79.228,48.262,137.662
|
||||
c-17.846,64.558-74.748,105.16-127.096,90.689c-52.348-14.47-80.318-78.534-62.472-143.091
|
||||
c7.909-28.618,23.501-52.519,42.964-69.011C1280.544,287.113,1303.604,333.083,1303.604,333.083"/>
|
||||
</g>
|
||||
<path d="M807.895,626.942c-7.131-58.735-72.193-61.431-72.193-61.431c-50.936,11.227-59.183,47.369-57.392,75.104L807.895,626.942z"
|
||||
/>
|
||||
</svg>
|
After Width: | Height: | Size: 6.1 KiB |
291
src/doc/book/2018-edition/src/img/ferris/unsafe.svg
Normal file
291
src/doc/book/2018-edition/src/img/ferris/unsafe.svg
Normal file
@ -0,0 +1,291 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="1240.298px" height="811.376px" viewBox="0 0 1240.298 811.376" enable-background="new 0 0 1240.298 811.376"
|
||||
xml:space="preserve">
|
||||
<!--<rect fill="#FFFFFF" width="1240.298" height="811.376"/>-->
|
||||
<rect x="303.062" y="408.688" fill="#E33D27" width="440" height="322.312"/>
|
||||
<polygon fill="#F37056" points="548.062,459 543.062,491 595.48,475 631.558,487 620.149,516.493 673.576,524.134 713.745,584
|
||||
700.062,644.844 753.914,671 780.201,542.318 678.062,433.837 "/>
|
||||
<ellipse fill="#FFFFFF" cx="456.505" cy="603.308" rx="20.83" ry="41.536"/>
|
||||
<ellipse fill="#FFFFFF" cx="613.519" cy="599.293" rx="18.039" ry="25.608"/>
|
||||
<path d="M426.848,565.302c76.475-36.052,82.274,92.731,23.019,92.075C407.91,656.909,399.502,592.939,426.848,565.302z
|
||||
M472.886,588.319c-3.647-13.308-14.517-15.274-25.896-8.632C411.107,600.633,485.029,632.633,472.886,588.319z"/>
|
||||
<path d="M593.734,565.302c63.543-6.768,43.711,98.739,0,97.828C549.726,662.215,539.183,571.111,593.734,565.302z M616.753,614.216
|
||||
c8.869-6.019,6.418-24.879,0-31.65C586.653,575.41,587.316,620.858,616.753,614.216z"/>
|
||||
<path fill="#E33D27" d="M1218.119,680.395c7.154,1.962-4.255,8.762-5.754,11.51c-40.783-1.407-71.586-8.146-97.83,5.754
|
||||
c-14.517-1.252-39.852-13.043-46.037,2.878c14.931,25.351,67.049,13.519,89.197,31.651c-12.87,18.54-39.345,5.012-57.547,5.754
|
||||
c-10.099,0.416-19.838,5.935-28.774,5.755c-49.039-0.988-101.843-22.372-152.498-23.019c42.625,23.559,115.104,17.253,155.376,43.16
|
||||
c-67.472,4.49-120.696-26.278-187.028-17.264c-6.34,0.861-6.592,6.33-11.509,5.754c-13.465-1.579-23.525-15.382-40.283-5.754
|
||||
c-6.26,5.23,6.261,17.787,0,23.018c-15.253-0.503-14.684-1.859-28.772,0c8.165-6.89,2.844-10.598,2.877-23.018
|
||||
c-13.752,2.551-9.706,22.902-25.896,23.018c-10.812-10.287-27.408-14.791-37.405-25.896c-12.972,3.333-5.671,26.937-17.265,31.65
|
||||
c-14.173-3.091-17.477-17.048-23.019-28.772c-3.136,10.441-20.8,16.528-28.773,5.754c-2.085,8.801,4.968,8.464,2.878,17.264
|
||||
c-18.137,3.755-22.952-5.821-37.406-5.754c0.949-12.456-3.963-19.055-11.51-23.019c4.176,9.359,9.97,28.835,2.877,40.283
|
||||
c58.823,6.435-102.298,3.786-184.15,5.755c-4.103-3.839-4.103-16.305,0-20.142c-3.242-3.983-16.786,6.063-25.896,5.754
|
||||
c-3.692-3.776-3.692-10.61,0-14.387c-22.912,6.714-41.991-16.95-51.792,2.878c-22.355-21.002-38.624,9.456-63.301,11.509
|
||||
c-0.208-9.795,8.463-10.717,14.387-14.387c-1.225-5.487-8.217-5.209-5.754-14.387c-21.833-0.735-30.381,11.819-48.916,14.387
|
||||
c-6.676-6.637,5.328-9.278,2.878-20.142c-14.78-4.791-23.536,24.911-43.161,14.387c2.484-8.068,14.983-6.119,20.142-11.509
|
||||
c-4.107-7.834-13.948-3.709-28.773-5.756c5.839-11.424,18.647-15.887,28.773-23.018c-16.19-14.891-50.252,8.151-86.32,0
|
||||
c-5.632-5.376-0.888-10.538,0-17.264c-26.711,2.744-56.57-2.806-92.075,0c2.416-3.342,3.799-7.716,2.877-14.388
|
||||
c21.001-2.978,57.323,9.365,57.547-14.387c13.15,2.023,39.985,15.118,48.916,2.878c-41.733-18.691-93.205-27.639-132.358-48.915
|
||||
c46.858-1.271,84.578,2.139,123.726-2.877c-14.836-7.225-29.161-14.957-51.792-14.387c-1.995-9.515-8.025-14.992-14.387-20.142
|
||||
c14.393,0.544,26.632,3.115,37.406-11.511c-28.684-5.917-66.629-11.896-103.584-17.264c-0.489-8.162,9.733-5.614,5.754-17.264
|
||||
c44.335,1.66,97.286,27.155,149.623,20.142c-19.613-10.115-54.625-4.845-74.811-14.387c8.817-3.917,31.875,2.574,48.915,0
|
||||
c-28.055-9.265-51.18-14.974-74.811-23.02c-1.147-10.739,2.299-16.882,11.509-17.264c-27.891-14.312-72.805-11.593-92.075-34.528
|
||||
c67.275,12.083,131.448,13.792,198.537,25.897c-37.895-23.488-109.193-13.576-135.235-48.916
|
||||
c17.298,3.808,38.108,4.095,51.792,11.509c5.26-4.333,6.772-12.414,11.51-17.263c-8.29-12.375-29.769-25.14-28.774-37.406
|
||||
c-10.126,8.26-21.226,0.57-11.509-8.633c-6.558-0.802-10.812,0.695-11.509,5.755c-11.38-14.192-41.548-24.578-69.057-37.406
|
||||
c13.712-22.602,48.516,23.597,60.424-8.632c37.523,18.628,73.715,39.315,117.971,57.547c7.57,0.851,2.265-11.164,11.509-8.631
|
||||
c-30.864-42.024-97.425-48.358-123.726-94.953c55.422,11.463,96.745,35.034,138.113,48.915
|
||||
c-18.522-26.558-67.382-47.704-100.707-69.056c16.719-7.501,46.628,10.534,66.179,25.896c17.062,0.757,22.496-4.753,28.773,5.755
|
||||
c3.467-3.249,5.215-8.211,14.387-5.755c-2.417-17.223-41.047-27.381-34.528-34.528c-2.821-5.753-23.592,3.166-17.264-5.753
|
||||
c17.021-8.622,52.713,19.045,71.934,34.528c8.856,2.143,5.53-7.898,14.386-5.755c-17.477-41.028-62.902-54.108-94.952-80.565
|
||||
c16.101-2.625,34.859,16.896,48.915,25.896c-13.454-30.673-60.846-52.319-83.443-83.443c14.331-9.428,31.427,3.026,34.529,14.387
|
||||
c41.625-17.209,41.851,53.044,83.443,54.67c0.135-9.789-20.698-23.374-23.019-40.283c55.417,21.313,74.771,78.69,120.848,109.339
|
||||
c-9.694-14.366-16-28.587-25.896-40.283c-2.906-3.435-12.078-6.455-14.387-11.509c-5.181-11.351,2.501-24.23,0-37.405
|
||||
c-8.834-46.596-59.648-77.024-71.934-126.604c60.424,23.635,64.139,87.271,120.849,112.217c3.502,9.927,9.508,17.348,17.264,23.019
|
||||
c-6.501-27.068-24.469-42.668-31.65-69.057c13.105,16.627,22.53,36.939,34.528,54.669c7.923-3.45,12.021-6.249,20.142-2.877
|
||||
c14.933,25.514,12.746,62.473,31.65,77.688c1.545-27.312-19.079-81.817-48.914-103.585c4.917-13.311,16.061,0.944,23.018,2.877
|
||||
c-2.382-36.073-48.858-95.548-25.896-138.113c33.685,45.919,52.119,107.102,80.565,158.254c18.647-22.846-6.754-63.077-5.753-77.689
|
||||
c24.345-6.629,23.125,36.008,34.528,51.793c-11.323,15.779-18.107,69.924,0,80.566c6.732-22.835,27.025-70.625,2.877-89.198
|
||||
c11.532-27.307-11.375-85.412,5.754-115.095c2.333,0.547,2.873,2.886,5.755,2.878c11.375,8.951,6.991,52.885,14.387,74.811
|
||||
c15.883-26.322,11.335-73.067,43.161-83.443c40.395,56.191,5.844,157.535,17.264,230.188c16.882-26.091,6.238-92.451,8.633-123.726
|
||||
c12.835,6.351,2.354,36.013,5.753,51.792c9.999-29.156,17.749-76.621,8.633-100.707c31.206-12.896,6.732-68.573,40.283-74.811
|
||||
c20.208,50.773-20.771,115.566,0,158.254c28.183-15.123,24.883-76.587,63.301-71.935c17.348-27.735,18.337-71.821,40.283-94.952
|
||||
c11.599,6.23,6.939,20.636,5.755,28.774c-5.469,37.506-37.496,79.328-28.774,129.48c16.079,3.051,12.233-12.965,17.264-20.141
|
||||
c22.969-32.747,53.524-54.615,63.303-97.83c9.093-4.339,13.37-13.492,23.02-17.264c2.972,30.808-14.271,66.28-31.652,86.321
|
||||
c20.782,9.806,6.621,42.072,8.633,66.179c27.801-28.788,45.97-67.206,69.056-100.707c0.631-10.526,3.957-11.038,0-20.142
|
||||
c9.694-4.023,12.285-19.592,25.896-11.51c-3.187,35.176-19.389,57.343-31.651,83.443c19.602,34.369-25.643,69.83-37.405,100.707
|
||||
c36.49-22.017,56.587-60.427,83.443-92.075c15.522-3.715,22.333-31.311,37.406-25.896c10.121,10.746-15.416,33.993-28.774,40.283
|
||||
c-15.814,24.466-37.271,43.289-54.67,66.18c20.4,0.253,19.901-20.384,34.528-25.897c-12.431,22.11-46.615,47.365-60.424,77.689
|
||||
c19.49-10.264,44.7-39.687,60.424-63.302c5.48-5.392,7.232-0.313,14.388,0c31.863-23.788,69.443-45.422,60.423-94.952
|
||||
c14.787-1.359,17.266,9.59,17.266,23.019c15.977-2.248,21.776-14.675,34.528-20.142c3.883,23.099-35.67,27.604-40.283,51.792
|
||||
c7.024,7.731,17.86-5.038,23.019,5.755c-7.003,16.976-35.265,12.69-37.405,34.528c24.951,8.02,57.99-55.858,74.812-20.141
|
||||
c-44.948,23.148-94.257,41.938-112.217,92.075c20.916,4.567,33.337-24.18,57.547-25.896c-15.781,11.964-9.128,30.528-25.896,43.16
|
||||
c26.053-8.69,38.445-45.669,66.179-43.16c-21.068,16.015-36.569,16.525-51.792,48.915c22.496-2.73,53.81-20.786,80.566-28.773
|
||||
c8.664,33.895-29.656,44.938-48.916,60.423c15.141,15.86,42.425,2.503,48.916-14.386c30.661,0.964,54.5-11.661,83.442-20.142
|
||||
c-10.476,28.857-79.555,24.02-86.32,66.18c-17.449,3.649-25.379,16.821-43.161,20.142c22.188,0.098,49.978-19.061,77.689-23.019
|
||||
c-21.384,16.979-53.405,23.318-74.812,40.283c4.153,13.752,14.089,3.931,23.02,0c18.343,0.12,34.905-1.545,43.159-11.51
|
||||
c16.557,5.654,32.235-1.677,43.16-5.754c20.85,6.545,35.652,3.21,60.425,2.876c-9.054,14.494-47.628,12.643-51.792,40.283
|
||||
c-15.404-1.017-20.782,7.991-31.651,11.509c-11.448-10.902-70.523-0.736-77.688,11.51c20.973,8.533,70.854-24.019,83.442,2.878
|
||||
c-2.158,15.103-23.418,11.11-34.528,17.264c-0.917,7.632,16.124-2.691,11.509,8.632c-37.73-11.667-80.526,5.513-117.971,11.51
|
||||
c54.85,5.668,118.797-17.455,166.887-11.51c-0.691,5.061-4.951,6.559-11.51,5.755c-1.102,9.736,12.739,4.527,8.633,17.264
|
||||
c21.59,0.281,47.278-13.782,60.423,2.878c0.013,17.277-34.746-0.219-28.772,23.02c-36.653,4.706-80.122-7.428-103.584,14.386
|
||||
c23.209,21.063,84.387-7.378,112.217,8.633c-10.348,14.589-38.198,11.672-60.425,14.387c-12.038,20.624-38.479,13.604-63.303,17.264
|
||||
c16.473,25.356,71.062,17.585,94.953,20.142c3.191,5.446,3.67,13.594,5.755,20.141c-27.801,2.769-47.735,0.492-69.057,5.755
|
||||
c37.866,18.388,83.977,14.851,135.235,28.774C1214.787,675.751,1214.787,688.616,1218.119,680.395z M550.575,202.755
|
||||
c-2.799-24.018,5.136-64.358-2.877-74.811C546.247,154.524,529.809,185.218,550.575,202.755z M320.386,191.246
|
||||
c-1,14.109,7.149,22.259,17.264,17.264C336.083,198.98,328.187,185.549,320.386,191.246z M662.79,266.057
|
||||
c12.775-7.608,29.892-34.197,17.266-48.915C675.722,234.869,668.423,249.626,662.79,266.057z M349.16,243.038
|
||||
c-8.98-2.527,0.106-23.126-11.51-23.019C336.487,230.921,344.479,247.532,349.16,243.038z M795.148,251.67
|
||||
c3.984-9.588,28.605-22.207,14.388-31.651C805.719,229.717,784.224,236.792,795.148,251.67z M947.648,225.773
|
||||
c-30.661,17.531-60.307,50.434-83.442,74.811c-7.183,7.567-21.355,17.894-17.266,25.897c33.73-34.37,81.348-54.849,106.463-97.831
|
||||
C952.769,226.41,950.992,225.304,947.648,225.773z M524.678,300.584c-0.634-10.877,2.928-25.946-8.631-25.896
|
||||
C510.319,282.514,512.819,301.348,524.678,300.584z M380.811,306.34c-8.363-6.98-10.779-19.912-20.142-25.896
|
||||
C363.551,291.078,372.235,310.964,380.811,306.34z M766.376,355.254c11.79-17.008,36.512-36.346,37.405-54.67
|
||||
C788.394,313.993,771.743,341.409,766.376,355.254z M228.311,335.113c-0.893-9.655-9.621-11.475-17.264-14.387
|
||||
C208.473,333.853,220.511,332.365,228.311,335.113z M881.47,375.396c27.255-1.815,43.564-28.929,63.301-28.773
|
||||
c-5.726-10.979,16.68-14.906,8.633-25.897C933.627,343.149,899.886,351.612,881.47,375.396z M950.526,340.868
|
||||
c10.267-2.201,17.517-7.421,23.019-14.386C963.276,328.683,956.028,333.901,950.526,340.868z M832.554,366.763
|
||||
c7.29-8.131,29.083-16.858,23.02-28.773C848.684,346.513,827.743,356.104,832.554,366.763z M513.169,378.273
|
||||
c6.395-9.208,0.152-25.671-8.633-28.774C495.556,361.294,510.111,369.446,513.169,378.273z M259.962,407.046
|
||||
c-0.961-12.467-15.933-10.918-23.019-17.264C239.416,400.739,247.216,406.369,259.962,407.046z M406.706,407.046
|
||||
c-4.265-2.445-6.186-7.242-5.754-14.387C380.946,392.85,404.992,412.555,406.706,407.046z M1091.516,427.188
|
||||
c18.889,1.254,40.199,5.823,51.792-5.755C1125.139,417.853,1105.779,418.069,1091.516,427.188z M861.328,467.471
|
||||
c-4.401,8.843,18.793,8.843,14.387,0C874.979,460.736,863.076,465.812,861.328,467.471z M553.451,484.735
|
||||
c9.801,0.208,10.718-8.465,14.388-14.387c-3.676-0.158-3.984-3.69-8.633-2.878C560.589,476.523,555.109,478.72,553.451,484.735z
|
||||
M510.292,484.735c-7.593,9.672-6.013,28.515-25.897,25.896c-3.776-8.931,0.782-8.211,0-20.142
|
||||
c-7.199,0.358-9.008,5.49-11.509-2.878c8.092-0.539,12.262-5.004,11.509-14.386c-10.543-0.954-15.988,3.191-23.019,5.753
|
||||
c0.934,17.233,0.995,33.607-17.264,31.652c-5.686-6.537,3.063-16.076,0-28.774c-15.24-4.692-12.396,8.7-17.264,14.387
|
||||
c-3.395-4.271-2.49-12.855-11.509-11.509c0,7.673,0,15.345,0,23.019c8.081,3.429,18.343,4.676,17.264,17.265
|
||||
c-9.845-5.036-17.826,1.259-28.772,2.877c-0.647,5.439,3.242,6.348,2.876,11.509c-20.781,5.638-38.186-2.139-57.546-5.755
|
||||
c8.283,14.739,31.661,14.379,37.406,31.652c-13.758,2.137-24.104-14.115-31.652-8.633c6.193,2.438,10.178,7.086,8.633,17.264
|
||||
c-3.839,4.105-16.303,4.105-20.142,0c0.674,11.893,17.865,8.978,8.631,23.02c4.182,1.572,14.877-3.364,14.388,2.877
|
||||
c-2.182,13.162-31.05-0.356-37.406,8.632c6.896,11.329,28.565,7.881,37.406,17.264c-1.878,14.427-12.533,20.074-25.897,23.02
|
||||
c1.326,9.228,13.067,8.036,14.387,17.264c14.871,0.481,13.296-15.479,28.774-14.387c0.54,14.764-11.595,19.113,2.877,25.897
|
||||
c-10.492,13.175-11.23,19.033-23.019,28.772c22.805,2.664,28.874-11.409,40.283-20.142c-2.058,7.814,13.571-2.061,11.509,5.755
|
||||
c-4.952,7.767,3.175,22.35,5.755,31.65c7.086-14.639,24.575-52.949,43.159-28.772c2.435,10.239-8.327,17.241,2.878,20.14
|
||||
c2.192-22.945,23.323-8.991,34.528-2.876c4.166-5.435,6.43-12.758,17.264-11.51c5.384,4.21,3.394,15.786,14.388,14.386
|
||||
c3.618-14.832,3.551-27.433,14.387-28.772c4.794,3.839,0.961,16.303,5.753,20.142c16.855-0.546,24.453,8.159,31.652,17.264
|
||||
c2.821-3.894,9.7-3.729,11.509-8.633c2.332-13.834-12.622-10.39-8.631-25.895c9.053-1.377,11.25,4.096,17.264,5.755
|
||||
c4.94-10.819,8.486-8.065,14.387-14.388c23.979,18.039,41.816,11.808,71.934,17.264c-1.113-10.39-15.786-7.231-11.509-23.018
|
||||
c-8.464-3.046-19.064-3.957-25.897-8.633c1.4-3.4,3.068-6.524,5.755-8.631c13.47,3.31,44.986,19.467,46.037-5.756
|
||||
c-11.807,0.298-23.492,0.473-28.773-5.755c2.439-10.267,7.086-0.345,17.265-2.878c-9.649-13.283,1.758-10.46,2.877-25.895
|
||||
c-6.166-9.521-26.475-2.203-31.652-5.756c9.24-13.779,34.226-11.812,43.161-25.896c-16.157-11.033-31.026-7.625-40.283,5.755
|
||||
c-19.838-8.728,13.825-22.618,8.633-34.527c-14.173,4.068-22.277-8.931-40.283,0c-1.231-5.479-6.198-7.233-5.755-14.387
|
||||
c1.288-8.303,12.381-6.804,14.386-14.387c-16.583-9.897-36.613,11.937-63.301,2.876c8.783-16.153,25.53-24.347,34.528-40.281
|
||||
c-15.843,5.749-25.424,31.454-43.161,25.896c10.914-8.452,5.266-19.028,14.388-31.65c-17.888,18.046-29.702,12.679-51.794,17.264
|
||||
c0.013-2.885-2.332-3.422-2.876-5.755c-1.933-10.729,11.671-20.717,5.754-25.896C532.046,477.715,525.325,485.381,510.292,484.735z
|
||||
M631.14,510.632c14.477,0.96,28.762-13.325,23.019-23.02C649.742,498.537,634.281,498.427,631.14,510.632z M1028.215,527.896
|
||||
c25.193,7.943,70.354,6.553,80.564-17.264C1089.977,513.287,1039.848,508.571,1028.215,527.896z M717.46,576.811
|
||||
c9.773-4.619,26.661-2.113,31.651-11.509C737.562,568.133,719.702,564.66,717.46,576.811z M705.951,640.111
|
||||
C728.937,657.017,720.579,623.069,705.951,640.111L705.951,640.111z M1056.987,651.621c1.242-6.434,14.185-1.166,20.142-2.877
|
||||
C1071.016,638.734,1006.465,648.215,1056.987,651.621z M1005.195,697.658c3.08,7.52,25.159,3.198,37.406,0
|
||||
C1032.368,694.931,1003.976,694.675,1005.195,697.658z M544.819,769.592c-5.058-0.693-6.558-4.95-5.755-11.509
|
||||
c-19.191,0.495-6.963,14.534-20.142,20.142c15.348,0,30.695,0,46.038,0c0.989-12.499-2.175-20.844-11.51-23.02
|
||||
C554.02,763.444,553.811,770.91,544.819,769.592z M593.734,781.103c10.633-1.839,28.667,3.726,34.528-2.878
|
||||
c-10.676-3.709-10.682-18.09-25.895-17.264C605.396,773.579,592.638,770.41,593.734,781.103z M484.395,781.103
|
||||
c9.594,0,19.187,0,28.774,0C511.691,769.374,485.497,769.412,484.395,781.103z"/>
|
||||
<rect x="477.335" y="335.988" fill="#E33D27" width="60.604" height="58.978"/>
|
||||
<rect x="346.712" y="365.477" fill="#E33D27" width="64.323" height="59.871"/>
|
||||
<rect x="841.76" y="436.07" fill="#E33D27" width="55.402" height="80.423"/>
|
||||
<rect x="490.15" y="254.548" fill="#E33D27" width="47.789" height="54.634"/>
|
||||
<rect x="221.61" y="365.477" fill="#E33D27" width="37.53" height="50.935"/>
|
||||
<g>
|
||||
<path fill="#F37056" d="M960.874,342.508c-7.183,7.57-21.354,17.894-17.264,25.897c23.211-23.649,52.995-40.722,77.5-63.077
|
||||
c-13.034,5.459-25.59,10.327-36.366,12.113C976.251,326.146,968.231,334.759,960.874,342.508z"/>
|
||||
<path fill="#F37056" d="M982.291,286.56c2.111-6.42,4.772-12.605,11.396-17.626c-4.429,0.314-8.461,1.536-12.223,3.29
|
||||
c-15.054,16.66-34.13,35.084-43.608,55.898C951.605,320.884,968.188,304.103,982.291,286.56z"/>
|
||||
<path fill="#F37056" d="M1032.808,336.755c0.142,0.03,0.276,0.044,0.414,0.069c16.913-10.348,33.999-22.228,30.24-44.329
|
||||
C1050.207,304.209,1039.396,318.372,1032.808,336.755z"/>
|
||||
<path fill="#F37056" d="M1189.346,404.169c-9.241,0.124-17.092,0.667-24.393,0.958c-3.92,4.524-6.771,9.897-8.097,16.427
|
||||
C1169.379,415.4,1184.175,412.447,1189.346,404.169z"/>
|
||||
<path fill="#F37056" d="M1093.542,331.732c-5.376,1.275-10.857,2.256-16.521,2.836c-2.233,6.923-5.04,13.786-12.562,19.45
|
||||
C1075.991,350.17,1084.845,340.787,1093.542,331.732z"/>
|
||||
<path fill="#F37056" d="M929.224,408.688c7.288-8.133,29.083-16.855,23.02-28.774C945.354,388.439,924.413,398.027,929.224,408.688
|
||||
z"/>
|
||||
<path fill="#F37056" d="M503.376,448.97c-4.265-2.443-6.188-7.237-5.755-14.386C477.616,434.775,501.662,454.479,503.376,448.97z"
|
||||
/>
|
||||
<path fill="#F37056" d="M759.46,307.98c12.773-7.604,29.892-34.197,17.264-48.915C772.392,276.796,765.091,291.553,759.46,307.98z"
|
||||
/>
|
||||
<path fill="#F37056" d="M890.099,290.81c0.45,0.896,1.015,1.823,1.72,2.784c1.44-3.468,5.58-7.331,9.607-11.299
|
||||
C897.672,285.156,893.89,287.984,890.099,290.81z"/>
|
||||
<path fill="#F37056" d="M863.046,397.178c4.893-7.058,12.008-14.521,18.729-22.142c1.233-1.57,2.54-3.068,3.899-4.512
|
||||
c7.834-9.309,14.325-18.791,14.776-28.016C885.063,355.918,868.411,383.337,863.046,397.178z"/>
|
||||
<path fill="#F37056" d="M1048.356,202.755c-2.375-5.043-5.084-8.048-8.039-9.602c-6.688,7.37-15.63,14.047-21.896,16.997
|
||||
c-2.716,4.204-5.642,8.197-8.64,12.116C1022.446,215.568,1035.576,209.336,1048.356,202.755z"/>
|
||||
<path fill="#F37056" d="M900.451,236.047c4.218-4.366,8.189-8.975,12.015-13.735c-4.415-1.273-6.41-3.791-10.855,0.584
|
||||
c-0.362,0.545-0.758,1.11-1.132,1.661C900.215,228.505,900.145,232.372,900.451,236.047z"/>
|
||||
<path fill="#F37056" d="M609.837,420.197c6.396-9.205,0.152-25.672-8.631-28.773C592.226,403.22,606.78,411.374,609.837,420.197z"
|
||||
/>
|
||||
<path fill="#F37056" d="M1194.9,524.134c-7.083,1.752-15.417,2.252-21.102,5.402c-0.141,1.167,0.173,1.88,0.733,2.349
|
||||
C1182.579,530.562,1193.381,531.989,1194.9,524.134z"/>
|
||||
<path fill="#F37056" d="M1139.644,437.292c2.543-5.611,6.859-9.652,11.949-12.835c-14.169,4.826-22.213,15.774-38.219,18.758
|
||||
C1121.475,443.252,1130.327,440.713,1139.644,437.292z"/>
|
||||
<path fill="#F37056" d="M1127.288,506.742c-1.045,0.868-1.879,1.754-2.405,2.652c2.51,1.021,5.441,1.441,8.66,1.458
|
||||
C1131.681,509.263,1128.91,508.577,1127.288,506.742z"/>
|
||||
<path fill="#F37056" d="M1047.196,382.792c5.236-1.121,9.68-3.037,13.516-5.561c0.651-2.398,1.516-4.628,2.575-6.71
|
||||
C1056.552,373.24,1051.367,377.512,1047.196,382.792z"/>
|
||||
<path fill="#F37056" d="M978.138,417.319c27.257-1.815,43.566-28.924,63.303-28.772c-5.726-10.976,16.68-14.905,8.631-25.897
|
||||
C1030.297,385.073,996.555,393.537,978.138,417.319z"/>
|
||||
<path fill="#F37056" d="M957.997,509.395c-4.4,8.846,18.792,8.846,14.388,0c-0.067-0.618-0.256-1.104-0.495-1.534
|
||||
c-0.405-0.039-0.817-0.064-1.223-0.106c0.352-0.057,0.709-0.121,1.062-0.181C969.09,503.774,959.548,507.923,957.997,509.395z"/>
|
||||
<path fill="#F37056" d="M1174.96,568.179c-11.15-6.416-27.655-5.69-44.926-3.878c-2.112,1.585-3.874,3.4-5.151,5.519
|
||||
c12.32,3.887,29.403,5.526,44.851,3.417C1171.755,571.834,1173.537,570.185,1174.96,568.179z"/>
|
||||
<path fill="#F37056" d="M1078.151,550.431c16.431-5.851,37.288-4.484,58.229-4.133c9.858-1.38,19.687-2.915,29.369-4.328
|
||||
c-0.368-3.449,0.435-5.734,1.99-7.261c-33.084-3.223-68.665,9.885-100.404,14.969
|
||||
C1070.905,550.046,1074.514,550.288,1078.151,550.431z"/>
|
||||
<path fill="#F37056" d="M519.384,275.245c-5.662-14.417-13.493-28.914-22.875-40.615c-0.964,3.086-1.932,6.056-2.847,8.863
|
||||
c1.231,0.242,2.518,0.587,3.958,1.187c14.932,25.513,12.746,62.474,31.652,77.687c0.477-8.462-1.174-19.539-4.568-31.442
|
||||
c-0.057,3.267-0.203,6.626-0.026,9.66c-11.858,0.762-14.358-18.07-8.631-25.896C517.35,274.683,518.437,274.894,519.384,275.245z"
|
||||
/>
|
||||
<path fill="#F37056" d="M267.434,218.783c1.495-0.619,2.919-1.093,4.31-1.493c-11.518-10.683-24.522-19.877-40.555-26.044
|
||||
c0.562,4.085,2.214,7.972,4.381,11.664C249.279,196.5,264.522,208.122,267.434,218.783z"/>
|
||||
<path fill="#F37056" d="M208.169,401.292c-6.071-1.665-5.877,2.939-7.165,6.057c28.852,14.916,58.187,30.438,92.325,44.498
|
||||
c7.57,0.854,2.265-11.161,11.509-8.632c-11.596-15.786-28.231-26.537-45.874-36.275c-9.229-0.704-15.755-4.112-19.403-10.394
|
||||
c-23.185-12.392-45.614-25.54-58.449-48.283c55.423,11.464,96.746,35.034,138.113,48.914
|
||||
c-16.806-24.092-58.581-43.732-91.072-63.115c0.056,0.345,0.123,0.682,0.157,1.05c-7.8-2.748-19.838-1.262-17.264-14.387
|
||||
c4.555,1.734,9.483,3.094,12.92,5.942c17.211-2.379,43.146,13.536,60.73,27.35c17.062,0.757,22.497-4.75,28.774,5.754
|
||||
c3.467-3.249,5.214-8.21,14.386-5.754c-2.416-17.22-41.047-27.381-34.528-34.529c-2.821-5.754-23.592,3.17-17.264-5.754
|
||||
c17.022-8.621,52.714,19.045,71.935,34.528c8.856,2.146,5.53-7.896,14.386-5.755c-17.479-41.024-62.903-54.107-94.953-80.565
|
||||
c16.1-2.625,34.86,16.897,48.915,25.896c-10.372-23.648-40.91-41.933-64.713-63.33c1.58,2.518,2.603,4.867,2.571,7.02
|
||||
c-41.592-1.626-41.817-71.881-83.443-54.67c-3.102-11.36-20.198-23.813-34.529-14.387c22.598,31.125,69.99,52.771,83.443,83.443
|
||||
c-14.055-9-32.814-28.521-48.915-25.896c32.05,26.456,77.475,39.538,94.952,80.565c-8.856-2.143-5.53,7.898-14.386,5.755
|
||||
c-19.22-15.482-54.912-43.15-71.934-34.528c-6.329,8.921,14.442,0,17.264,5.753c-6.519,7.146,32.111,17.307,34.528,34.528
|
||||
c-9.172-2.458-10.919,2.506-14.387,5.755c-6.278-10.506-11.712-5-28.773-5.755c-19.551-15.362-49.46-33.396-66.179-25.896
|
||||
c33.325,21.353,82.185,42.5,100.707,69.056c-41.368-13.88-82.69-37.453-138.113-48.915
|
||||
C110.744,352.937,177.305,359.27,208.169,401.292z"/>
|
||||
<path fill="#F37056" d="M309.93,240.203c3.794,5.699,7.626,11.627,11.979,16.89c1.75,1.079,3.316,2.125,4.232,3.209
|
||||
c1.371,1.622,2.664,3.302,3.917,5.013c5.709,4.648,12.412,7.81,20.818,8.138c0.135-9.784-20.697-23.373-23.019-40.283
|
||||
c5.356,2.061,10.369,4.466,15.109,7.143c-3.299-4.795-6.03-13.607-5.317-20.292c11.616-0.107,2.53,20.492,11.51,23.019
|
||||
c-0.256,0.247-0.529,0.405-0.802,0.529c40.576,25.857,60.456,72.41,100.348,98.942c-9.693-14.363-15.999-28.583-25.895-40.283
|
||||
c-2.907-3.433-12.078-6.451-14.388-11.509c-5.18-11.346,2.502-24.227,0-37.406c-3.431-18.093-13.198-33.747-24.575-49.033
|
||||
c-0.958,0.433-1.958,0.885-3.037,1.354c-5.465-8.079-10.4-16.69-15.39-25.247c-6.822-8.953-13.355-18.146-18.698-27.976
|
||||
c7.436,25.506,24.83,41.049,31.21,67.609c-7.756-5.673-13.762-13.092-17.264-23.019c-56.71-24.946-60.425-88.582-120.849-112.217
|
||||
c12.285,49.581,63.099,80.007,71.934,126.604C313.643,221.337,309.731,231.121,309.93,240.203z M320.386,191.246
|
||||
c7.801-5.695,15.697,7.736,17.264,17.264C327.535,213.503,319.386,205.354,320.386,191.246z"/>
|
||||
<path fill="#F37056" d="M390.342,171.301c18.823,25.289,33.874,53.051,66.997,67.624c3.5,9.93,9.508,17.348,17.264,23.019
|
||||
c-6.502-27.065-24.469-42.667-31.652-69.057c13.106,16.628,22.53,36.938,34.529,54.669c1.955-0.851,3.672-1.661,5.28-2.349
|
||||
c-7.824-18.554-2.404-55.13,6.276-69.523c-5.993-14.727-12.288-30.299-15.581-45.543c-3.897-6.521-9.289-10.278-17.834-7.952
|
||||
c-1.001,14.612,24.4,54.842,5.753,77.689c-28.446-51.154-46.88-112.335-80.565-158.254
|
||||
c-22.962,42.564,23.513,102.04,25.896,138.113C402.079,178.449,395.608,171.753,390.342,171.301z"/>
|
||||
<path fill="#F37056" d="M307.717,362.65c-2.574,13.127,9.463,11.639,17.264,14.386C324.087,367.382,315.359,365.561,307.717,362.65
|
||||
z"/>
|
||||
<path fill="#F37056" d="M422.181,231.992c2.706,6.736,4.949,13.468,6.649,19.912c1.728-0.054,3.573-0.523,5.49-1.47
|
||||
C433.1,243.018,428.039,233.279,422.181,231.992z"/>
|
||||
<path fill="#F37056" d="M445.829,284.961c-8.981-2.523,0.107-23.125-11.509-23.018
|
||||
C433.156,272.845,441.148,289.458,445.829,284.961z"/>
|
||||
<path fill="#F37056" d="M258.801,736.706c-4.395,0.452-8.885,0.662-13.462,0.742c1.256,0.752,2.302,1.819,3.113,3.371
|
||||
c-5.159,5.39-17.657,3.44-20.142,11.509c12.687,6.804,20.833-3.199,28.999-9.835C257.897,740.678,258.528,738.765,258.801,736.706z
|
||||
"/>
|
||||
<path fill="#F37056" d="M266.762,755.276c0.264,0.874,0.81,1.79,1.832,2.807c3.484-0.483,6.612-1.317,9.545-2.352
|
||||
C274.396,755.826,270.598,755.697,266.762,755.276z"/>
|
||||
<path fill="#F37056" d="M87.321,398.415c0.697-5.061,4.951-6.556,11.509-5.755c-9.717,9.203,1.383,16.893,11.509,8.633
|
||||
c-0.995,12.268,20.484,25.031,28.774,37.406c-4.737,4.849-6.25,12.93-11.51,17.263c-13.684-7.414-34.494-7.701-51.792-11.509
|
||||
c25.82,35.04,96.11,25.613,134.24,48.339c5.202,1.239,10.045,2.832,14.222,5.095c5.26-4.334,6.771-12.415,11.509-17.264
|
||||
c-8.289-12.375-29.768-25.138-28.773-37.406c-10.127,8.261-21.226,0.574-11.509-8.632c-6.559-0.797-10.813,0.698-11.51,5.755
|
||||
c-11.38-14.19-41.547-24.576-69.056-37.406c12.836-21.153,44.149,17.963,57.867-3.383c-33.871-15.463-63.552-32.002-94.112-47.173
|
||||
c-11.909,32.229-46.712-13.968-60.424,8.632C45.773,373.837,75.941,384.222,87.321,398.415z"/>
|
||||
<path fill="#F37056" d="M558.045,241.802c18.647-22.845-6.755-63.077-5.755-77.688c16.821-4.578,21.438,14.355,26.444,31.704
|
||||
c3.859-55.909,10.377-113.72-16.651-151.317c-31.825,10.377-27.278,57.123-43.161,83.443c-7.396-21.926-3.011-65.862-14.387-74.811
|
||||
c-2.882,0.008-3.421-2.33-5.755-2.878c-8.584,14.876-7.112,36.892-4.959,58.59C517.875,150.519,534.557,199.568,558.045,241.802z
|
||||
M547.697,127.944c8.013,10.453,0.078,50.795,2.877,74.811C529.809,185.218,546.247,154.523,547.697,127.944z"/>
|
||||
<path fill="#F37056" d="M345.122,753.97c-6.598-6.066-16.163-5.833-27.619-3.981c1.346,3.273,4.917,4.318,5.761,8.095
|
||||
c-5.923,3.67-14.595,4.592-14.387,14.387c5.249-0.438,10.112-2.163,14.741-4.403C329.979,762.56,338.159,758.873,345.122,753.97z"
|
||||
/>
|
||||
<path fill="#F37056" d="M248.452,712.046c-0.542,0.382-1.118,0.733-1.677,1.101c11.644,3.148,23.822,5.156,29.29-2.338
|
||||
c-32.949-14.757-71.948-23.459-106.184-36.933c-11.934,1.41-29.524-6.348-39.401-7.868c-0.224,23.752-36.545,11.409-57.547,14.387
|
||||
c0.922,6.672-0.461,11.046-2.877,14.388c35.505-2.806,65.364,2.744,92.075,0c-0.888,6.726-5.632,11.888,0,17.264
|
||||
C198.2,720.197,232.262,697.155,248.452,712.046z"/>
|
||||
<path fill="#F37056" d="M93.076,519.263c23.631,8.046,46.756,13.755,74.811,23.02c-17.04,2.574-40.098-3.917-48.915,0
|
||||
c18.857,8.913,50.641,4.909,70.734,12.585c0.714-6.782,4.347-10.647,11.549-10.944c-27.892-14.313-72.805-11.594-92.075-34.528
|
||||
c67.275,12.082,131.448,13.792,198.538,25.896c-37.479-23.228-107.606-13.814-134.334-47.8
|
||||
c-53.725-7.24-106.279-10.213-160.873-20.021c19.271,22.936,64.184,20.216,92.075,34.528
|
||||
C95.375,502.381,91.929,508.523,93.076,519.263z"/>
|
||||
<path fill="#F37056" d="M47.038,619.971c33.711,18.32,76.542,27.512,114.439,41.641c38.881-0.242,71.881,1.775,105.957-2.594
|
||||
c-14.836-7.222-29.162-14.954-51.792-14.387c-1.996-9.515-8.026-14.989-14.387-20.142c14.393,0.546,26.632,3.118,37.405-11.511
|
||||
c-28.683-5.918-66.628-11.896-103.584-17.264c-0.488-8.159,9.733-5.614,5.755-17.264c44.334,1.663,97.285,27.155,149.622,20.141
|
||||
c-19.612-10.115-54.624-4.844-74.81-14.386c8.817-3.917,31.875,2.574,48.914,0c-28.054-9.262-51.179-14.971-74.811-23.02
|
||||
c-0.152-1.431-0.21-2.767-0.196-4.032c-50.952,5.159-102.247-19.012-145.388-20.627c3.979,11.649-6.243,9.102-5.754,17.264
|
||||
c36.956,5.367,74.9,11.347,103.584,17.264c-10.773,14.626-23.013,12.055-37.406,11.511c6.362,5.149,12.392,10.627,14.387,20.142
|
||||
c22.631-0.57,36.957,7.162,51.792,14.387C131.616,622.109,93.896,618.7,47.038,619.971z"/>
|
||||
<path fill="#F37056" d="M1083.058,351.613c23.241-13.143,56.156-17.439,63.128-36.642c-15.511,4.544-29.56,10.265-43.976,14.46
|
||||
C1095.478,334.435,1089.207,340.808,1083.058,351.613z"/>
|
||||
<path fill="#F37056" d="M503.376,221.66c-0.172-2.607-0.598-5.354-1.188-8.191c-0.486,2.327-1.028,4.651-1.613,6.958
|
||||
C501.561,220.979,502.502,221.418,503.376,221.66z"/>
|
||||
<path fill="#F37056" d="M333.613,431.706c2.473,10.96,10.272,16.589,23.018,17.264C355.67,436.506,340.699,438.051,333.613,431.706
|
||||
z"/>
|
||||
<path fill="#F37056" d="M457.339,322.367c2.882,10.638,11.565,30.522,20.142,25.897
|
||||
C469.118,341.283,466.702,328.352,457.339,322.367z"/>
|
||||
<path fill="#F37056" d="M612.715,316.613c-5.726,7.828-3.226,26.66,8.633,25.895C620.713,331.634,624.276,316.567,612.715,316.613z
|
||||
"/>
|
||||
<path fill="#F37056" d="M675.856,231.276c1.558-4.553,2.999-9.222,4.199-14.134c8.91,10.386,3.006,26.675-5.728,38.041
|
||||
c-1.132,21.552-1.289,42.471,1.689,61.431c16.882-26.089,6.238-92.453,8.631-123.727c12.837,6.35,2.355,36.018,5.755,51.793
|
||||
c9.998-29.156,17.747-76.622,8.632-100.708c31.207-12.892,6.733-68.573,40.283-74.812c1.399,3.519,2.481,7.109,3.336,10.751
|
||||
c4.207-11.24,7.807-22.055,9.335-32.533c1.185-8.138,5.844-22.544-5.755-28.774c-21.946,23.131-22.936,67.216-40.283,94.952
|
||||
c-14.696-1.781-23.28,6.128-29.863,17.402C681.301,161.274,678.35,196.469,675.856,231.276z"/>
|
||||
<path fill="#F37056" d="M579.348,274.688c-1.434-9.114-2.142-18.679-2.366-28.551c-3.036,20.503-1.369,43.75,9.838,50.334
|
||||
c6.732-22.834,27.025-70.625,2.876-89.199c5.542-13.125,3.13-33.365,1.032-54.141c-0.779-0.859-1.652-1.627-2.747-2.169
|
||||
C585.586,182.237,596.23,248.598,579.348,274.688z"/>
|
||||
<path fill="#F37056" d="M642.368,184.844c-4.242,22.451-12.071,45.527,4.875,59.835c-2.124-18.231,1.93-45.861,0.506-62.69
|
||||
c-1.584,1.338-3.273,2.521-5.099,3.502C642.546,185.28,642.469,185.058,642.368,184.844z"/>
|
||||
<path fill="#F37056" d="M735.584,171.567c-3.144,20.468-4.104,39.732,3.734,55.847c28.184-15.123,24.885-76.587,63.302-71.934
|
||||
c1.431-2.284,2.714-4.715,3.945-7.202c-0.443-9.034-3.183-16.45-11.417-20.335c17.382-20.041,34.624-55.513,31.652-86.321
|
||||
c-9.649,3.774-13.927,12.925-23.02,17.264c-9.778,43.213-40.334,65.083-63.303,97.83
|
||||
C737.782,160.567,737.619,166.937,735.584,171.567z"/>
|
||||
<path fill="#F37056" d="M615.593,169.868c13.074-21.664,12.321-57.153,29.395-74.822c3.894-23.297,6.041-46.757-2.338-67.809
|
||||
c-32.509,6.044-10.543,58.502-37.533,73.487C611.578,115.878,609.23,151.007,615.593,169.868z"/>
|
||||
<path fill="#F37056" d="M989.466,132.274c-6.629,20.231-17.129,36.588-25.714,54.857c19.602,34.371-25.643,69.833-37.405,100.708
|
||||
c8.093-4.883,15.348-10.604,22.084-16.849c5.897-8.486,12.911-15.855,20.705-22.443c7.69-9.467,14.92-19.396,22.237-29.24
|
||||
c-6.167,3.535-12.203,5.396-17.828,3.588c2.141-21.838,30.402-17.553,37.405-34.528c-5.158-10.793-15.994,1.975-23.019-5.755
|
||||
c4.613-24.188,44.166-28.692,40.283-51.792c-12.752,5.465-18.552,17.894-34.528,20.142
|
||||
C993.687,143.325,992.877,136.5,989.466,132.274z"/>
|
||||
<path fill="#F37056" d="M913.12,153.84c-5.465,6.44-10.646,13.165-15.746,19.968c4.431,4.585,5.854,11.127,5.926,18.638
|
||||
c6.564-7.66,12.868-15.579,18.452-24.219c13.358-6.291,38.896-29.535,28.774-40.283C935.453,122.529,928.643,150.125,913.12,153.84
|
||||
z"/>
|
||||
<path fill="#F37056" d="M822.007,172.346c-3.472,14.691-4.96,30.12-2.122,46.437c16.079,3.051,12.233-12.965,17.264-20.142
|
||||
c10.699-15.258,23.033-28.164,34.16-41.958c-0.713-3.833-2.051-7.663-4.227-11.476c12.263-26.102,28.465-48.266,31.651-83.443
|
||||
c-13.611-8.084-16.202,7.488-25.896,11.51c3.957,9.104,0.631,9.615,0,20.142C855.191,119.025,840.405,147.489,822.007,172.346z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 30 KiB |
9
src/doc/book/2018-edition/src/theme/2018-edition.css
Normal file
9
src/doc/book/2018-edition/src/theme/2018-edition.css
Normal file
@ -0,0 +1,9 @@
|
||||
span.caption {
|
||||
font-size: .8em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
span.caption code {
|
||||
font-size: 0.875em;
|
||||
font-weight: 400;
|
||||
}
|
@ -236,14 +236,14 @@ method, which are repeated here in Listing 11-5. Let’s put this code in the
|
||||
```rust
|
||||
# fn main() {}
|
||||
#[derive(Debug)]
|
||||
pub struct Rectangle {
|
||||
length: u32,
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl Rectangle {
|
||||
pub fn can_hold(&self, other: &Rectangle) -> bool {
|
||||
self.length > other.length && self.width > other.width
|
||||
fn can_hold(&self, other: &Rectangle) -> bool {
|
||||
self.width > other.width && self.height > other.height
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -253,9 +253,9 @@ impl Rectangle {
|
||||
|
||||
The `can_hold` method returns a Boolean, which means it’s a perfect use case
|
||||
for the `assert!` macro. In Listing 11-6, we write a test that exercises the
|
||||
`can_hold` method by creating a `Rectangle` instance that has a length of 8 and
|
||||
a width of 7 and asserting that it can hold another `Rectangle` instance that
|
||||
has a length of 5 and a width of 1.
|
||||
`can_hold` method by creating a `Rectangle` instance that has a width of 8 and
|
||||
a height of 7 and asserting that it can hold another `Rectangle` instance that
|
||||
has a width of 5 and a height of 1.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
@ -267,8 +267,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn larger_can_hold_smaller() {
|
||||
let larger = Rectangle { length: 8, width: 7 };
|
||||
let smaller = Rectangle { length: 5, width: 1 };
|
||||
let larger = Rectangle { width: 8, height: 7 };
|
||||
let smaller = Rectangle { width: 5, height: 1 };
|
||||
|
||||
assert!(larger.can_hold(&smaller));
|
||||
}
|
||||
@ -315,8 +315,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn smaller_cannot_hold_larger() {
|
||||
let larger = Rectangle { length: 8, width: 7 };
|
||||
let smaller = Rectangle { length: 5, width: 1 };
|
||||
let larger = Rectangle { width: 8, height: 7 };
|
||||
let smaller = Rectangle { width: 5, height: 1 };
|
||||
|
||||
assert!(!smaller.can_hold(&larger));
|
||||
}
|
||||
@ -338,20 +338,20 @@ test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
|
||||
Two tests that pass! Now let’s see what happens to our test results when we
|
||||
introduce a bug in our code. Let’s change the implementation of the `can_hold`
|
||||
method by replacing the greater than sign with a less than sign when it
|
||||
compares the lengths:
|
||||
compares the widths:
|
||||
|
||||
```rust
|
||||
# fn main() {}
|
||||
# #[derive(Debug)]
|
||||
# pub struct Rectangle {
|
||||
# length: u32,
|
||||
# struct Rectangle {
|
||||
# width: u32,
|
||||
# height: u32,
|
||||
# }
|
||||
// --snip--
|
||||
|
||||
impl Rectangle {
|
||||
pub fn can_hold(&self, other: &Rectangle) -> bool {
|
||||
self.length < other.length && self.width > other.width
|
||||
fn can_hold(&self, other: &Rectangle) -> bool {
|
||||
self.width < other.width && self.height > other.height
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -376,8 +376,8 @@ failures:
|
||||
test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
|
||||
```
|
||||
|
||||
Our tests caught the bug! Because `larger.length` is 8 and `smaller.length` is
|
||||
5, the comparison of the lengths in `can_hold` now returns `false`: 8 is not
|
||||
Our tests caught the bug! Because `larger.width` is 8 and `smaller.width` is
|
||||
5, the comparison of the widths in `can_hold` now returns `false`: 8 is not
|
||||
less than 5.
|
||||
|
||||
### Testing Equality with the `assert_eq!` and `assert_ne!` Macros
|
||||
|
@ -59,7 +59,7 @@ The error tells us we can’t call `join` because we only have a mutable borrow
|
||||
of each `worker` and `join` takes ownership of its argument. To solve this
|
||||
issue, we need to move the thread out of the `Worker` instance that owns
|
||||
`thread` so `join` can consume the thread. We did this in Listing 17-15: if
|
||||
`Worker` holds an `Option<thread::JoinHandle<()>` instead, we can call the
|
||||
`Worker` holds an `Option<thread::JoinHandle<()>>` instead, we can call the
|
||||
`take` method on the `Option` to move the value out of the `Some` variant and
|
||||
leave a `None` variant in its place. In other words, a `Worker` that is running
|
||||
will have a `Some` variant in `thread`, and when we want to clean up a
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user