From 1077625d0af38925086d1f561e6d5e0448caae5e Mon Sep 17 00:00:00 2001 From: Nick Hahn Date: Tue, 23 May 2017 19:32:59 +0200 Subject: [PATCH 1/3] Update trpl-Book sources --- trpl/README.md | 18 +- trpl/SUMMARY.md | 15 +- trpl/associated-types.md | 8 +- trpl/attributes.md | 4 +- trpl/bibliography.md | 6 +- trpl/borrow-and-asref.md | 14 +- trpl/casting-between-types.md | 43 ++- trpl/chapter_1.md | 1 + trpl/choosing-your-guarantees.md | 38 +-- trpl/closures.md | 62 ++-- trpl/comments.md | 4 +- trpl/concurrency.md | 28 +- trpl/conditional-compilation.md | 7 +- trpl/const-and-static.md | 4 +- trpl/crates-and-modules.md | 31 +- trpl/deref-coercions.md | 22 +- trpl/documentation.md | 38 +-- trpl/drop.md | 10 +- trpl/effective-rust.md | 2 +- trpl/enums.md | 4 +- trpl/error-handling.md | 142 ++++----- trpl/ffi.md | 116 ++++--- trpl/functions.md | 27 +- trpl/generics.md | 52 +++- trpl/getting-started.md | 209 +++++-------- trpl/glossary.md | 4 +- trpl/guessing-game.md | 126 ++++---- trpl/if-let.md | 8 +- trpl/if.md | 2 +- trpl/iterators.md | 17 +- trpl/lifetimes.md | 131 ++++++-- trpl/loops.md | 27 +- trpl/macros.md | 58 ++-- trpl/match.md | 4 +- trpl/method-syntax.md | 2 +- trpl/mutability.md | 18 +- trpl/operators-and-overloading.md | 8 +- trpl/ownership.md | 16 +- trpl/patterns.md | 33 +- trpl/primitive-types.md | 50 +-- trpl/procedural-macros.md | 286 ++++++++++++++++++ trpl/raw-pointers.md | 8 +- trpl/references-and-borrowing.md | 36 +-- trpl/release-channels.md | 2 +- trpl/strings.md | 16 +- trpl/structs.md | 41 ++- trpl/syntax-and-semantics.md | 2 +- trpl/syntax-index.md | 21 +- trpl/testing.md | 206 ++++++++++--- trpl/the-stack-and-the-heap.md | 8 +- trpl/trait-objects.md | 29 +- trpl/traits.md | 102 ++++--- trpl/type-aliases.md | 4 +- trpl/ufcs.md | 2 +- trpl/unsafe.md | 8 +- trpl/unsized-types.md | 2 +- ...using-rust-without-the-standard-library.md | 14 +- trpl/variable-bindings.md | 28 +- trpl/vectors.md | 16 +- 59 files changed, 1384 insertions(+), 856 deletions(-) create mode 100644 trpl/chapter_1.md create mode 100644 trpl/procedural-macros.md diff --git a/trpl/README.md b/trpl/README.md index 9f9b6a9..8580048 100644 --- a/trpl/README.md +++ b/trpl/README.md @@ -1,4 +1,4 @@ -% The Rust Programming Language +# The Rust Programming Language Welcome! This book will teach you about the [Rust Programming Language][rust]. Rust is a systems programming language focused on three goals: safety, speed, @@ -21,7 +21,6 @@ is the first. After this: * [Tutorial: Guessing Game][gg] - Learn some Rust with a small project. * [Syntax and Semantics][ss] - Each bit of Rust, broken down into small chunks. * [Effective Rust][er] - Higher-level concepts for writing excellent Rust code. -* [Nightly Rust][nr] - Cutting-edge features that aren’t in stable builds yet. * [Glossary][gl] - A reference of terms used in the book. * [Bibliography][bi] - Background on Rust's influences, papers about Rust. @@ -29,7 +28,6 @@ is the first. After this: [gg]: guessing-game.html [er]: effective-rust.html [ss]: syntax-and-semantics.html -[nr]: nightly-rust.html [gl]: glossary.html [bi]: bibliography.html @@ -38,4 +36,16 @@ is the first. After this: The source files from which this book is generated can be found on [GitHub][book]. -[book]: https://github.com/rust-lang/rust/tree/master/src/doc/book +### Second edition of this book + +There are two editions of "The Rust Programming Language", this being the +[first edition][first-edition]. + +The [second edition][second-edition] is a complete re-write. It is still under +construction, though it is far enough along to learn most of Rust. We suggest +reading the second edition and then checking out the first edition later to pick +up some of the more esoteric parts of the language. + +[book]: https://github.com/rust-lang/book/tree/master/first-edition/src +[first-edition]: first-edition/index.html +[second-edition]: second-edition/index.html diff --git a/trpl/SUMMARY.md b/trpl/SUMMARY.md index 18aa9f2..c3763cd 100644 --- a/trpl/SUMMARY.md +++ b/trpl/SUMMARY.md @@ -1,5 +1,7 @@ # Summary +[Introduction](README.md) + * [Getting Started](getting-started.md) * [Tutorial: Guessing Game](guessing-game.md) * [Syntax and Semantics](syntax-and-semantics.md) @@ -52,18 +54,7 @@ * [Borrow and AsRef](borrow-and-asref.md) * [Release Channels](release-channels.md) * [Using Rust without the standard library](using-rust-without-the-standard-library.md) -* [Nightly Rust](nightly-rust.md) - * [Compiler Plugins](compiler-plugins.md) - * [Inline Assembly](inline-assembly.md) - * [No stdlib](no-stdlib.md) - * [Intrinsics](intrinsics.md) - * [Lang items](lang-items.md) - * [Advanced linking](advanced-linking.md) - * [Benchmark Tests](benchmark-tests.md) - * [Box Syntax and Patterns](box-syntax-and-patterns.md) - * [Slice Patterns](slice-patterns.md) - * [Associated Constants](associated-constants.md) - * [Custom Allocators](custom-allocators.md) + * [Procedural Macros (and custom derive)](procedural-macros.md) * [Glossary](glossary.md) * [Syntax Index](syntax-index.md) * [Bibliography](bibliography.md) diff --git a/trpl/associated-types.md b/trpl/associated-types.md index cb54ac2..4db2b9e 100644 --- a/trpl/associated-types.md +++ b/trpl/associated-types.md @@ -1,4 +1,4 @@ -% Associated Types +# Associated Types Associated types are a powerful part of Rust’s type system. They’re related to the idea of a ‘type family’, in other words, grouping multiple types together. That @@ -11,7 +11,7 @@ this: trait Graph { fn has_edge(&self, &N, &N) -> bool; fn edges(&self, &N) -> Vec; - // etc + // Etc. } ``` @@ -36,7 +36,7 @@ trait Graph { fn has_edge(&self, &Self::N, &Self::N) -> bool; fn edges(&self, &Self::N) -> Vec; - // etc + // Etc. } ``` @@ -67,7 +67,7 @@ trait Graph { Simple enough. Associated types use the `type` keyword, and go inside the body of the trait, with the functions. -These `type` declarations can have all the same thing as functions do. For example, +These type declarations work the same way as those for functions. For example, if we wanted our `N` type to implement `Display`, so we can print the nodes out, we could do this: diff --git a/trpl/attributes.md b/trpl/attributes.md index 6349647..49ac9b2 100644 --- a/trpl/attributes.md +++ b/trpl/attributes.md @@ -1,4 +1,4 @@ -% Attributes +# Attributes Declarations can be annotated with ‘attributes’ in Rust. They look like this: @@ -67,4 +67,4 @@ Rust attributes are used for a number of different things. There is a full list of attributes [in the reference][reference]. Currently, you are not allowed to create your own attributes, the Rust compiler defines them. -[reference]: ../reference.html#attributes +[reference]: ../../reference/attributes.html diff --git a/trpl/bibliography.md b/trpl/bibliography.md index 6f6f51d..3a624b5 100644 --- a/trpl/bibliography.md +++ b/trpl/bibliography.md @@ -1,4 +1,4 @@ -% Bibliography +# Bibliography This is a reading list of material relevant to Rust. It includes prior research that has - at one time or another - influenced the design of @@ -61,8 +61,7 @@ Language](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf). Early GPU work Rust](http://scialex.github.io/reenix.pdf). Undergrad paper by Alex Light. * [Evaluation of performance and productivity metrics of potential - programming languages in the HPC environment] - (http://octarineparrot.com/assets/mrfloya-thesis-ba.pdf). + programming languages in the HPC environment](http://octarineparrot.com/assets/mrfloya-thesis-ba.pdf). Bachelor's thesis by Florian Wilkens. Compares C, Go and Rust. * [Nom, a byte oriented, streaming, zero copy, parser combinators library in Rust](http://spw15.langsec.org/papers/couprie-nom.pdf). By @@ -81,3 +80,4 @@ Language](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf). Early GPU work Munksgaard's master's thesis. Research for Servo. * [Ownership is Theft: Experiences Building an Embedded OS in Rust - Amit Levy, et. al.](http://amitlevy.com/papers/tock-plos2015.pdf) * [You can't spell trust without Rust](https://raw.githubusercontent.com/Gankro/thesis/master/thesis.pdf). Alexis Beingessner's master's thesis. +* [Rust as a Language for High Performance GC Implementation](http://users.cecs.anu.edu.au/~steveb/downloads/pdf/rust-ismm-2016.pdf) diff --git a/trpl/borrow-and-asref.md b/trpl/borrow-and-asref.md index 1cfeb26..3b1ef1a 100644 --- a/trpl/borrow-and-asref.md +++ b/trpl/borrow-and-asref.md @@ -1,14 +1,14 @@ -% Borrow and AsRef +# Borrow and AsRef The [`Borrow`][borrow] and [`AsRef`][asref] traits are very similar, but different. Here’s a quick refresher on what these two traits mean. -[borrow]: ../std/borrow/trait.Borrow.html -[asref]: ../std/convert/trait.AsRef.html +[borrow]: ../../std/borrow/trait.Borrow.html +[asref]: ../../std/convert/trait.AsRef.html # Borrow -The `Borrow` trait is used when you’re writing a datastructure, and you want to +The `Borrow` trait is used when you’re writing a data structure, and you want to use either an owned or borrowed type as synonymous for some purpose. For example, [`HashMap`][hashmap] has a [`get` method][get] which uses `Borrow`: @@ -19,8 +19,8 @@ fn get(&self, k: &Q) -> Option<&V> Q: Hash + Eq ``` -[hashmap]: ../std/collections/struct.HashMap.html -[get]: ../std/collections/struct.HashMap.html#method.get +[hashmap]: ../../std/collections/struct.HashMap.html +[get]: ../../std/collections/struct.HashMap.html#method.get This signature is pretty complicated. The `K` parameter is what we’re interested in here. It refers to a parameter of the `HashMap` itself: @@ -86,7 +86,7 @@ We can see how they’re kind of the same: they both deal with owned and borrowe versions of some type. However, they’re a bit different. Choose `Borrow` when you want to abstract over different kinds of borrowing, or -when you’re building a datastructure that treats owned and borrowed values in +when you’re building a data structure that treats owned and borrowed values in equivalent ways, such as hashing and comparison. Choose `AsRef` when you want to convert something to a reference directly, and diff --git a/trpl/casting-between-types.md b/trpl/casting-between-types.md index a101f39..26cd718 100644 --- a/trpl/casting-between-types.md +++ b/trpl/casting-between-types.md @@ -1,4 +1,4 @@ -% Casting Between Types +# Casting Between Types Rust, with its focus on safety, provides two different ways of casting different types between each other. The first, `as`, is for safe casts. @@ -16,20 +16,20 @@ function result. The most common case of coercion is removing mutability from a reference: - * `&mut T` to `&T` +* `&mut T` to `&T` An analogous conversion is to remove mutability from a -[raw pointer](raw-pointers.md): +[raw pointer](raw-pointers.html): - * `*mut T` to `*const T` +* `*mut T` to `*const T` References can also be coerced to raw pointers: - * `&T` to `*const T` +* `&T` to `*const T` - * `&mut T` to `*mut T` +* `&mut T` to `*mut T` -Custom coercions may be defined using [`Deref`](deref-coercions.md). +Custom coercions may be defined using [`Deref`](deref-coercions.html). Coercion is transitive. @@ -59,11 +59,11 @@ A cast `e as U` is valid if `e` has type `T` and `T` *coerces* to `U`. A cast `e as U` is also valid in any of the following cases: - * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast* - * `e` is a C-like enum (with no data attached to the variants), - and `U` is an integer type; *enum-cast* - * `e` has type `bool` or `char` and `U` is an integer type; *prim-int-cast* - * `e` has type `u8` and `U` is `char`; *u8-char-cast* +* `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast* +* `e` is a C-like enum (with no data attached to the variants), + and `U` is an integer type; *enum-cast* +* `e` has type `bool` or `char` and `U` is an integer type; *prim-int-cast* +* `e` has type `u8` and `U` is `char`; *u8-char-cast* For example @@ -101,12 +101,12 @@ The semantics of numeric casts are: ## Pointer casts -Perhaps surprisingly, it is safe to cast [raw pointers](raw-pointers.md) to and +Perhaps surprisingly, it is safe to cast [raw pointers](raw-pointers.html) to and from integers, and to cast between pointers to different types subject to some constraints. It is only unsafe to dereference the pointer: ```rust -let a = 300 as *const char; // a pointer to location 300 +let a = 300 as *const char; // `a` is a pointer to location 300. let b = a as u32; ``` @@ -135,14 +135,14 @@ cast four bytes into a `u32`: ```rust,ignore let a = [0u8, 0u8, 0u8, 0u8]; -let b = a as u32; // four u8s makes a u32 +let b = a as u32; // Four u8s makes a u32. ``` This errors with: ```text error: non-scalar cast: `[u8; 4]` as `u32` -let b = a as u32; // four u8s makes a u32 +let b = a as u32; // Four u8s makes a u32. ^~~~~~~~ ``` @@ -151,12 +151,9 @@ elements of the array. These kinds of casts are very dangerous, because they make assumptions about the way that multiple underlying structures are implemented. For this, we need something more dangerous. -The `transmute` function is provided by a [compiler intrinsic][intrinsics], and -what it does is very simple, but very scary. It tells Rust to treat a value of -one type as though it were another type. It does this regardless of the -typechecking system, and completely trusts you. - -[intrinsics]: intrinsics.html +The `transmute` function is very simple, but very scary. It tells Rust to treat +a value of one type as though it were another type. It does this regardless of +the typechecking system, and completely trusts you. In our previous example, we know that an array of four `u8`s represents a `u32` properly, and so we want to do the cast. Using `transmute` instead of `as`, @@ -170,7 +167,7 @@ fn main() { let a = [0u8, 1u8, 0u8, 0u8]; let b = mem::transmute::<[u8; 4], u32>(a); println!("{}", b); // 256 - // or, more concisely: + // Or, more concisely: let c: u32 = mem::transmute(a); println!("{}", c); // 256 } diff --git a/trpl/chapter_1.md b/trpl/chapter_1.md new file mode 100644 index 0000000..b743fda --- /dev/null +++ b/trpl/chapter_1.md @@ -0,0 +1 @@ +# Chapter 1 diff --git a/trpl/choosing-your-guarantees.md b/trpl/choosing-your-guarantees.md index d88f619..b1ba4df 100644 --- a/trpl/choosing-your-guarantees.md +++ b/trpl/choosing-your-guarantees.md @@ -1,4 +1,4 @@ -% Choosing your Guarantees +# Choosing your Guarantees One important feature of Rust is that it lets us control the costs and guarantees of a program. @@ -25,7 +25,7 @@ the following: ```rust let x = Box::new(1); let y = x; -// x no longer accessible here +// `x` is no longer accessible here. ``` Here, the box was _moved_ into `y`. As `x` no longer owns it, the compiler will no longer allow the @@ -38,7 +38,7 @@ This is a zero-cost abstraction for dynamic allocation. If you want to allocate heap and safely pass around a pointer to that memory, this is ideal. Note that you will only be allowed to share references to this by the regular borrowing rules, checked at compile time. -[box]: ../std/boxed/struct.Box.html +[box]: ../../std/boxed/struct.Box.html ## `&T` and `&mut T` @@ -104,7 +104,7 @@ two `usize` values) as compared to a regular `Box` (for "strong" and "weak" r or goes out of scope respectively. Note that a clone will not do a deep copy, rather it will simply increment the inner reference count and return a copy of the `Rc`. -[rc]: ../std/rc/struct.Rc.html +[rc]: ../../std/rc/struct.Rc.html # Cell types @@ -118,7 +118,8 @@ These types are _generally_ found in struct fields, but they may be found elsewh ## `Cell` -[`Cell`][cell] is a type that provides zero-cost interior mutability, but only for `Copy` types. +[`Cell`][cell] is a type that provides zero-cost interior mutability by moving data in and +out of the cell. Since the compiler knows that all the data owned by the contained value is on the stack, there's no worry of leaking any data behind references (or worse!) by simply replacing the data. @@ -160,7 +161,7 @@ This relaxes the “no aliasing with mutability” restriction in places unnecessary. However, this also relaxes the guarantees that the restriction provides; so if your invariants depend on data stored within `Cell`, you should be careful. -This is useful for mutating primitives and other `Copy` types when there is no easy way of +This is useful for mutating primitives and other types when there is no easy way of doing it in line with the static rules of `&` and `&mut`. `Cell` does not let you obtain interior references to the data, which makes it safe to freely @@ -168,16 +169,17 @@ mutate. #### Cost -There is no runtime cost to using `Cell`, however if you are using it to wrap larger (`Copy`) +There is no runtime cost to using `Cell`, however if you are using it to wrap larger structs, it might be worthwhile to instead wrap individual fields in `Cell` since each write is otherwise a full copy of the struct. ## `RefCell` -[`RefCell`][refcell] also provides interior mutability, but isn't restricted to `Copy` types. +[`RefCell`][refcell] also provides interior mutability, but doesn't move data in and out of the +cell. -Instead, it has a runtime cost. `RefCell` enforces the read-write lock pattern at runtime (it's +However, it has a runtime cost. `RefCell` enforces the read-write lock pattern at runtime (it's like a single-threaded mutex), unlike `&T`/`&mut T` which do so at compile time. This is done by the `borrow()` and `borrow_mut()` functions, which modify an internal reference count and return smart pointers which can be dereferenced immutably and mutably respectively. The refcount is restored when @@ -232,9 +234,9 @@ indicator (one word in size) along with the data. At runtime each borrow causes a modification/check of the refcount. -[cell-mod]: ../std/cell/index.html -[cell]: ../std/cell/struct.Cell.html -[refcell]: ../std/cell/struct.RefCell.html +[cell-mod]: ../../std/cell/index.html +[cell]: ../../std/cell/struct.Cell.html +[refcell]: ../../std/cell/struct.RefCell.html # Synchronous types @@ -250,7 +252,7 @@ time. There are many useful wrappers for concurrent programming in the [sync][sync] module, but only the major ones will be covered below. -[sync]: ../std/sync/index.html +[sync]: ../../std/sync/index.html ## `Arc` @@ -278,7 +280,7 @@ This has the added cost of using atomics for changing the refcount (which will h cloned or goes out of scope). When sharing data from an `Arc` in a single thread, it is preferable to share `&` pointers whenever possible. -[arc]: ../std/sync/struct.Arc.html +[arc]: ../../std/sync/struct.Arc.html ## `Mutex` and `RwLock` @@ -291,9 +293,9 @@ the inner data (mutably), and the lock will be released when the guard goes out ```rust,ignore { let guard = mutex.lock(); - // guard dereferences mutably to the inner type + // `guard` dereferences mutably to the inner type. *guard += 1; -} // lock released when destructor runs +} // Lock is released when destructor runs. ``` @@ -314,8 +316,8 @@ These use internal atomic-like types to maintain the locks, which are pretty cos all memory reads across processors till they're done). Waiting on these locks can also be slow when there's a lot of concurrent access happening. -[rwlock]: ../std/sync/struct.RwLock.html -[mutex]: ../std/sync/struct.Mutex.html +[rwlock]: ../../std/sync/struct.RwLock.html +[mutex]: ../../std/sync/struct.Mutex.html [sessions]: https://github.com/Munksgaard/rust-sessions # Composition diff --git a/trpl/closures.md b/trpl/closures.md index 1470eac..0fe08bf 100644 --- a/trpl/closures.md +++ b/trpl/closures.md @@ -1,4 +1,4 @@ -% Closures +# Closures Sometimes it is useful to wrap up a function and _free variables_ for better clarity and reuse. The free variables that can be used come from the @@ -116,7 +116,7 @@ let mut num = 5; { let plus_num = |x: i32| x + num; -} // plus_num goes out of scope, borrow of num ends +} // `plus_num` goes out of scope; borrow of `num` ends. let y = &mut num; ``` @@ -222,26 +222,11 @@ operator. From this, everything else clicks into place. In Rust, we use the trait system to overload operators. Calling functions is no different. We have three separate traits to overload with: -```rust -# #![feature(unboxed_closures)] -# mod foo { -pub trait Fn : FnMut { - extern "rust-call" fn call(&self, args: Args) -> Self::Output; -} - -pub trait FnMut : FnOnce { - extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; -} - -pub trait FnOnce { - type Output; - - extern "rust-call" fn call_once(self, args: Args) -> Self::Output; -} -# } -``` +* `Fn` +* `FnMut` +* `FnOnce` -You’ll notice a few differences between these traits, but a big one is `self`: +There are a few differences between these traits, but a big one is `self`: `Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This covers all three kinds of `self` via the usual method call syntax. But we’ve split them up into three traits, rather than having a single one. This gives us @@ -262,7 +247,7 @@ the result: ```rust fn call_with_one(some_closure: F) -> i32 - where F : Fn(i32) -> i32 { + where F: Fn(i32) -> i32 { some_closure(1) } @@ -279,21 +264,21 @@ Let’s examine the signature of `call_with_one` in more depth: ```rust fn call_with_one(some_closure: F) -> i32 -# where F : Fn(i32) -> i32 { +# where F: Fn(i32) -> i32 { # some_closure(1) } ``` -We take one parameter, and it has the type `F`. We also return a `i32`. This part +We take one parameter, and it has the type `F`. We also return an `i32`. This part isn’t interesting. The next part is: ```rust # fn call_with_one(some_closure: F) -> i32 - where F : Fn(i32) -> i32 { + where F: Fn(i32) -> i32 { # some_closure(1) } ``` Because `Fn` is a trait, we can use it as a bound for our generic type. In -this case, our closure takes a `i32` as an argument and returns an `i32`, and +this case, our closure takes an `i32` as an argument and returns an `i32`, and so the generic bound we use is `Fn(i32) -> i32`. There’s one other key point here: because we’re bounding a generic with a @@ -327,7 +312,7 @@ that takes a reference like so: fn call_with_ref(some_closure:F) -> i32 where F: Fn(&i32) -> i32 { - let mut value = 0; + let value = 0; some_closure(&value) } ``` @@ -340,14 +325,15 @@ fn call_with_ref<'a, F>(some_closure:F) -> i32 where F: Fn(&'a i32) -> i32 { ``` -However this presents a problem with in our case. When you specify the explicit -lifetime on a function it binds that lifetime to the *entire* scope of the function -instead of just the invocation scope of our closure. This means that the borrow checker -will see a mutable reference in the same lifetime as our immutable reference and fail -to compile. +However, this presents a problem in our case. When a function has an explicit +lifetime parameter, that lifetime must be at least as long as the *entire* +call to that function. The borrow checker will complain that `value` doesn't +live long enough, because it is only in scope after its declaration inside the +function body. -In order to say that we only need the lifetime to be valid for the invocation scope -of the closure we can use Higher-Ranked Trait Bounds with the `for<...>` syntax: +What we need is a closure that can borrow its argument only for its own +invocation scope, not for the outer function's scope. In order to say that, +we can use Higher-Ranked Trait Bounds with the `for<...>` syntax: ```ignore fn call_with_ref(some_closure:F) -> i32 @@ -362,7 +348,7 @@ expect. fn call_with_ref(some_closure:F) -> i32 where F: for<'a> Fn(&'a i32) -> i32 { - let mut value = 0; + let value = 0; some_closure(&value) } ``` @@ -510,12 +496,11 @@ fn factory() -> Box i32> { Box::new(|x| x + num) } -# fn main() { + let f = factory(); let answer = f(1); assert_eq!(6, answer); -# } ``` There’s just one last problem: @@ -540,12 +525,11 @@ fn factory() -> Box i32> { Box::new(move |x| x + num) } -fn main() { + let f = factory(); let answer = f(1); assert_eq!(6, answer); -} ``` By making the inner closure a `move Fn`, we create a new stack frame for our diff --git a/trpl/comments.md b/trpl/comments.md index e7eb48d..0e68ab2 100644 --- a/trpl/comments.md +++ b/trpl/comments.md @@ -1,4 +1,4 @@ -% Comments +# Comments Now that we have some functions, it’s a good idea to learn about comments. Comments are notes that you leave to other programmers to help explain things @@ -10,7 +10,7 @@ and *doc comments*. ```rust // Line comments are anything after ‘//’ and extend to the end of the line. -let x = 5; // this is also a line comment. +let x = 5; // This is also a line comment. // If you have a long explanation for something, you can put line comments next // to each other. Put a space between the // and your comment so that it’s diff --git a/trpl/concurrency.md b/trpl/concurrency.md index a783650..0fd71ee 100644 --- a/trpl/concurrency.md +++ b/trpl/concurrency.md @@ -1,10 +1,10 @@ -% Concurrency +# Concurrency Concurrency and parallelism are incredibly important topics in computer science, and are also a hot topic in industry today. Computers are gaining more and more cores, yet many programmers aren't prepared to fully utilize them. -Rust's memory safety features also apply to its concurrency story too. Even +Rust's memory safety features also apply to its concurrency story. Even concurrent Rust programs must be memory safe, having no data races. Rust's type system is up to the task, and gives you powerful ways to reason about concurrent code at compile time. @@ -26,7 +26,7 @@ to help us make sense of code that can possibly be concurrent. ### `Send` The first trait we're going to talk about is -[`Send`](../std/marker/trait.Send.html). When a type `T` implements `Send`, it +[`Send`](../../std/marker/trait.Send.html). When a type `T` implements `Send`, it indicates that something of this type is able to have ownership transferred safely between threads. @@ -36,14 +36,14 @@ down the channel and to the other thread. Therefore, we'd ensure that `Send` was implemented for that type. In the opposite way, if we were wrapping a library with [FFI][ffi] that isn't -threadsafe, we wouldn't want to implement `Send`, and so the compiler will help +thread-safe, we wouldn't want to implement `Send`, and so the compiler will help us enforce that it can't leave the current thread. [ffi]: ffi.html ### `Sync` -The second of these traits is called [`Sync`](../std/marker/trait.Sync.html). +The second of these traits is called [`Sync`](../../std/marker/trait.Sync.html). When a type `T` implements `Sync`, it indicates that something of this type has no possibility of introducing memory unsafety when used from multiple threads concurrently through shared references. This implies that @@ -213,10 +213,10 @@ fn main() { let mut data = Rc::new(vec![1, 2, 3]); for i in 0..3 { - // create a new owned reference + // Create a new owned reference: let data_ref = data.clone(); - // use it in a thread + // Use it in a thread: thread::spawn(move || { data_ref[0] += i; }); @@ -238,7 +238,7 @@ This won't work, however, and will give us the error: As the error message mentions, `Rc` cannot be sent between threads safely. This is because the internal reference count is not maintained in a thread safe -matter and can have a data race. +manner and can have a data race. To solve this, we'll use `Arc`, Rust's standard atomic reference count type. @@ -281,8 +281,8 @@ And... still gives us an error. ``` `Arc` by default has immutable contents. It allows the _sharing_ of data -between threads, but shared mutable data is unsafe and when threads are -involved can cause data races! +between threads, but shared mutable data is unsafe—and when threads are +involved—can cause data races! Usually when we wish to make something in an immutable position mutable, we use @@ -333,8 +333,8 @@ locked, it will wait until the other thread releases the lock. The lock "release" here is implicit; when the result of the lock (in this case, `data`) goes out of scope, the lock is automatically released. -Note that [`lock`](../std/sync/struct.Mutex.html#method.lock) method of -[`Mutex`](../std/sync/struct.Mutex.html) has this signature: +Note that [`lock`](../../std/sync/struct.Mutex.html#method.lock) method of +[`Mutex`](../../std/sync/struct.Mutex.html) has this signature: ```rust,ignore fn lock(&self) -> LockResult> @@ -390,8 +390,8 @@ use std::sync::mpsc; fn main() { let data = Arc::new(Mutex::new(0)); - // `tx` is the "transmitter" or "sender" - // `rx` is the "receiver" + // `tx` is the "transmitter" or "sender". + // `rx` is the "receiver". let (tx, rx) = mpsc::channel(); for _ in 0..10 { diff --git a/trpl/conditional-compilation.md b/trpl/conditional-compilation.md index 78ab3c1..0562e9f 100644 --- a/trpl/conditional-compilation.md +++ b/trpl/conditional-compilation.md @@ -1,4 +1,4 @@ -% Conditional Compilation +# Conditional Compilation Rust has a special attribute, `#[cfg]`, which allows you to compile code based on a flag passed to the compiler. It has two forms: @@ -79,8 +79,7 @@ Will be the same as `#[b]` if `a` is set by `cfg` attribute, and nothing otherwi # cfg! -The `cfg!` [syntax extension][compilerplugins] lets you use these kinds of flags -elsewhere in your code, too: +The `cfg!` macro lets you use these kinds of flags elsewhere in your code, too: ```rust if cfg!(target_os = "macos") || cfg!(target_os = "ios") { @@ -88,7 +87,5 @@ if cfg!(target_os = "macos") || cfg!(target_os = "ios") { } ``` -[compilerplugins]: compiler-plugins.html - These will be replaced by a `true` or `false` at compile-time, depending on the configuration settings. diff --git a/trpl/const-and-static.md b/trpl/const-and-static.md index 11aa25a..66a4856 100644 --- a/trpl/const-and-static.md +++ b/trpl/const-and-static.md @@ -1,4 +1,4 @@ -% `const` and `static` +# const and static Rust has a way of defining constants with the `const` keyword: @@ -32,7 +32,7 @@ static N: i32 = 5; Unlike [`let`][let] bindings, you must annotate the type of a `static`. Statics live for the entire lifetime of a program, and therefore any -reference stored in a constant has a [`'static` lifetime][lifetimes]: +reference stored in a static has a [`'static` lifetime][lifetimes]: ```rust static NAME: &'static str = "Steve"; diff --git a/trpl/crates-and-modules.md b/trpl/crates-and-modules.md index fcb7e0b..10e66d4 100644 --- a/trpl/crates-and-modules.md +++ b/trpl/crates-and-modules.md @@ -1,4 +1,4 @@ -% Crates and Modules +# Crates and Modules When a project starts getting large, it’s considered good software engineering practice to split it up into a bunch of smaller pieces, and then @@ -126,7 +126,7 @@ Instead of declaring a module like this: ```rust,ignore mod english { - // contents of our module go here + // Contents of our module go here. } ``` @@ -176,23 +176,28 @@ mod english; mod japanese; ``` -These two declarations tell Rust to look for either `src/english.rs` and -`src/japanese.rs`, or `src/english/mod.rs` and `src/japanese/mod.rs`, depending -on our preference. In this case, because our modules have sub-modules, we’ve -chosen the second. Both `src/english/mod.rs` and `src/japanese/mod.rs` look -like this: +These two declarations tell Rust to look for + +- either `src/english.rs` or `src/english/mod.rs`, and +- either `src/japanese.rs` or `src/japanese/mod.rs`, + +depending on our preference. In this case, because our modules have sub-modules, +we’ve chosen the `mod.rs` approach. Both `src/english/mod.rs` and +`src/japanese/mod.rs` look like this: ```rust,ignore mod greetings; mod farewells; ``` -Again, these declarations tell Rust to look for either -`src/english/greetings.rs`, `src/english/farewells.rs`, -`src/japanese/greetings.rs` and `src/japanese/farewells.rs` or -`src/english/greetings/mod.rs`, `src/english/farewells/mod.rs`, -`src/japanese/greetings/mod.rs` and -`src/japanese/farewells/mod.rs`. Because these sub-modules don’t have +Again, these declarations tell Rust to look for + +- `src/english/greetings.rs` or `src/english/greetings/mod.rs`, +- `src/english/farewells.rs` or `src/english/farewells/mod.rs`, +- `src/japanese/greetings.rs` or `src/japanese/greetings/mod.rs`, +- and `src/japanese/farewells.rs` or `src/japanese/farewells/mod.rs`. + +Because these sub-modules don’t have their own sub-modules, we’ve chosen to make them `src/english/greetings.rs`, `src/english/farewells.rs`, `src/japanese/greetings.rs` and `src/japanese/farewells.rs`. Whew! diff --git a/trpl/deref-coercions.md b/trpl/deref-coercions.md index beb65c4..e62c50a 100644 --- a/trpl/deref-coercions.md +++ b/trpl/deref-coercions.md @@ -1,4 +1,4 @@ -% `Deref` coercions +# `Deref` coercions The standard library provides a special trait, [`Deref`][deref]. It’s normally used to overload `*`, the dereference operator: @@ -24,7 +24,7 @@ fn main() { } ``` -[deref]: ../std/ops/trait.Deref.html +[deref]: ../../std/ops/trait.Deref.html This is useful for writing custom pointer types. However, there’s a language feature related to `Deref`: ‘deref coercions’. Here’s the rule: If you have a @@ -33,13 +33,13 @@ automatically coerce to a `&T`. Here’s an example: ```rust fn foo(s: &str) { - // borrow a string for a second + // Borrow a string for a second. } -// String implements Deref +// String implements Deref. let owned = "Hello".to_string(); -// therefore, this works: +// Therefore, this works: foo(&owned); ``` @@ -55,31 +55,31 @@ type implements `Deref`, so this works: use std::rc::Rc; fn foo(s: &str) { - // borrow a string for a second + // Borrow a string for a second. } -// String implements Deref +// String implements Deref. let owned = "Hello".to_string(); let counted = Rc::new(owned); -// therefore, this works: +// Therefore, this works: foo(&counted); ``` All we’ve done is wrap our `String` in an `Rc`. But we can now pass the `Rc` around anywhere we’d have a `String`. The signature of `foo` didn’t change, but works just as well with either type. This example has two -conversions: `Rc` to `String` and then `String` to `&str`. Rust will do +conversions: `&Rc` to `&String` and then `&String` to `&str`. Rust will do this as many times as possible until the types match. Another very common implementation provided by the standard library is: ```rust fn foo(s: &[i32]) { - // borrow a slice for a second + // Borrow a slice for a second. } -// Vec implements Deref +// Vec implements Deref. let owned = vec![1, 2, 3]; foo(&owned); diff --git a/trpl/documentation.md b/trpl/documentation.md index 6292ba9..6a2c850 100644 --- a/trpl/documentation.md +++ b/trpl/documentation.md @@ -1,4 +1,4 @@ -% Documentation +# Documentation Documentation is an important part of any software project, and it's first-class in Rust. Let's talk about the tooling Rust gives you to @@ -28,7 +28,7 @@ code. You can use documentation comments for this purpose: /// let five = Rc::new(5); /// ``` pub fn new(value: T) -> Rc { - // implementation goes here + // Implementation goes here. } ``` @@ -76,7 +76,7 @@ This [unfortunate error](https://github.com/rust-lang/rust/issues/22547) is correct; documentation comments apply to the thing after them, and there's nothing after that last comment. -[rc-new]: ../std/rc/struct.Rc.html#method.new +[rc-new]: ../../std/rc/struct.Rc.html#method.new ### Writing documentation comments @@ -170,8 +170,6 @@ more than one section: # fn foo() {} ``` -Let's discuss the details of these code blocks. - #### Code block annotations To write some Rust code in a comment, use the triple graves: @@ -183,23 +181,8 @@ To write some Rust code in a comment, use the triple graves: # fn foo() {} ``` -If you want something that's not Rust code, you can add an annotation: - -```rust -/// ```c -/// printf("Hello, world\n"); -/// ``` -# fn foo() {} -``` - -This will highlight according to whatever language you're showing off. -If you're only showing plain text, choose `text`. - -It's important to choose the correct annotation here, because `rustdoc` uses it -in an interesting way: It can be used to actually test your examples in a -library crate, so that they don't get out of date. If you have some C code but -`rustdoc` thinks it's Rust because you left off the annotation, `rustdoc` will -complain when trying to generate the documentation. +This will add code highlighting. If you are only showing plain text, put `text` +instead of `rust` after the triple graves (see below). ## Documentation as tests @@ -460,8 +443,9 @@ not actually pass as a test. ``` The `no_run` attribute will compile your code, but not run it. This is -important for examples such as "Here's how to start up a network service," -which you would want to make sure compile, but might run in an infinite loop! +important for examples such as "Here's how to retrieve a web page," +which you would want to ensure compiles, but might be run in a test +environment that has no network access. ### Documenting modules @@ -483,7 +467,7 @@ you have a module in `foo.rs`, you'll often open its code and see this: ```rust //! A module for using `foo`s. //! -//! The `foo` module contains a lot of useful functionality blah blah blah +//! The `foo` module contains a lot of useful functionality blah blah blah... ``` ### Crate documentation @@ -600,7 +584,7 @@ is documented, especially when you are working on a library. Rust allows you to to generate warnings or errors, when an item is missing documentation. To generate warnings you use `warn`: -```rust +```rust,ignore #![warn(missing_docs)] ``` @@ -630,7 +614,7 @@ struct Hidden; You can control a few aspects of the HTML that `rustdoc` generates through the `#![doc]` version of the attribute: -```rust +```rust,ignore #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://www.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/")] diff --git a/trpl/drop.md b/trpl/drop.md index 5513523..1d8c9a3 100644 --- a/trpl/drop.md +++ b/trpl/drop.md @@ -1,10 +1,10 @@ -% Drop +# Drop Now that we’ve discussed traits, let’s talk about a particular trait provided by the Rust standard library, [`Drop`][drop]. The `Drop` trait provides a way to run some code when a value goes out of scope. For example: -[drop]: ../std/ops/trait.Drop.html +[drop]: ../../std/ops/trait.Drop.html ```rust struct HasDrop; @@ -18,9 +18,9 @@ impl Drop for HasDrop { fn main() { let x = HasDrop; - // do stuff + // Do stuff. -} // x goes out of scope here +} // `x` goes out of scope here. ``` When `x` goes out of scope at the end of `main()`, the code for `Drop` will @@ -64,4 +64,4 @@ reference-counted type. When `Drop` is called, it will decrement the reference count, and if the total number of references is zero, will clean up the underlying value. -[arc]: ../std/sync/struct.Arc.html +[arc]: ../../std/sync/struct.Arc.html diff --git a/trpl/effective-rust.md b/trpl/effective-rust.md index 65873c8..ce2dfe4 100644 --- a/trpl/effective-rust.md +++ b/trpl/effective-rust.md @@ -1,4 +1,4 @@ -% Effective Rust +# Effective Rust So you’ve learned how to write some Rust code. But there’s a difference between writing *any* Rust code and writing *good* Rust code. diff --git a/trpl/enums.md b/trpl/enums.md index 5e05b4e..9cf5e6b 100644 --- a/trpl/enums.md +++ b/trpl/enums.md @@ -1,4 +1,4 @@ -% Enums +# Enums An `enum` in Rust is a type that represents data that is one of several possible variants. Each variant in the `enum` can optionally @@ -51,7 +51,7 @@ possible variants: ```rust,ignore fn process_color_change(msg: Message) { - let Message::ChangeColor(r, g, b) = msg; // compile-time error + let Message::ChangeColor(r, g, b) = msg; // This causes a compile-time error. } ``` diff --git a/trpl/error-handling.md b/trpl/error-handling.md index 6e13b46..02bd675 100644 --- a/trpl/error-handling.md +++ b/trpl/error-handling.md @@ -1,4 +1,4 @@ -% Error Handling +# Error Handling Like most programming languages, Rust encourages the programmer to handle errors in a particular way. Generally speaking, error handling is divided into @@ -59,13 +59,13 @@ handling is reducing the amount of explicit case analysis the programmer has to do while keeping code composable. Keeping code composable is important, because without that requirement, we -could [`panic`](../std/macro.panic!.html) whenever we +could [`panic`](../../std/macro.panic.html) whenever we come across something unexpected. (`panic` causes the current task to unwind, and in most cases, the entire program aborts.) Here's an example: ```rust,should_panic // Guess a number between 1 and 10. -// If it matches the number we had in mind, return true. Else, return false. +// If it matches the number we had in mind, return `true`. Else, return `false`. fn guess(n: i32) -> bool { if n < 1 || n > 10 { panic!("Invalid number: {}", n); @@ -236,7 +236,7 @@ fn extension_explicit(file_name: &str) -> Option<&str> { ``` (Pro-tip: don't use this code. Use the -[`extension`](../std/path/struct.Path.html#method.extension) +[`extension`](../../std/path/struct.Path.html#method.extension) method in the standard library instead.) The code stays simple, but the important thing to notice is that the type of @@ -350,7 +350,7 @@ fn file_path_ext_explicit(file_path: &str) -> Option<&str> { } fn file_name(file_path: &str) -> Option<&str> { - // implementation elided + // Implementation elided. unimplemented!() } ``` @@ -360,7 +360,7 @@ analysis, but its type doesn't quite fit... ```rust,ignore fn file_path_ext(file_path: &str) -> Option<&str> { - file_name(file_path).map(|x| extension(x)) //Compilation error + file_name(file_path).map(|x| extension(x)) // This causes a compilation error. } ``` @@ -530,10 +530,10 @@ above is generic over all the different number types defined in the standard library. We could (and probably should) also make our function generic, but let's favor explicitness for the moment. We only care about `i32`, so we need to [find its implementation of -`FromStr`](../std/primitive.i32.html) (do a `CTRL-F` in your browser +`FromStr`](../../std/primitive.i32.html) (do a `CTRL-F` in your browser for “FromStr”) and look at its [associated type][10] `Err`. We did this so we can find the concrete error type. In this case, it's -[`std::num::ParseIntError`](../std/num/struct.ParseIntError.html). +[`std::num::ParseIntError`](../../std/num/struct.ParseIntError.html). Finally, we can rewrite our function: ```rust @@ -577,12 +577,12 @@ fn main() { ``` The usual suspects are all there for `Result`, including -[`unwrap_or`](../std/result/enum.Result.html#method.unwrap_or) and -[`and_then`](../std/result/enum.Result.html#method.and_then). +[`unwrap_or`](../../std/result/enum.Result.html#method.unwrap_or) and +[`and_then`](../../std/result/enum.Result.html#method.and_then). Additionally, since `Result` has a second type parameter, there are combinators that affect only the error type, such as -[`map_err`](../std/result/enum.Result.html#method.map_err) (instead of -`map`) and [`or_else`](../std/result/enum.Result.html#method.or_else) +[`map_err`](../../std/result/enum.Result.html#method.map_err) (instead of +`map`) and [`or_else`](../../std/result/enum.Result.html#method.or_else) (instead of `and_then`). ### The `Result` type alias idiom @@ -611,11 +611,11 @@ Why would we do this? Well, if we have a lot of functions that could return uses `ParseIntError` so that we don't have to write it out all the time. The most prominent place this idiom is used in the standard library is -with [`io::Result`](../std/io/type.Result.html). Typically, one writes +with [`io::Result`](../../std/io/type.Result.html). Typically, one writes `io::Result`, which makes it clear that you're using the `io` module's type alias instead of the plain definition from `std::result`. (This idiom is also used for -[`fmt::Result`](../std/fmt/type.Result.html).) +[`fmt::Result`](../../std/fmt/type.Result.html).) ## A brief interlude: unwrapping isn't evil @@ -639,7 +639,7 @@ summarize some of my *opinions* on the matter. This is probably not an exhaustive list. Moreover, when using an `Option`, it is often better to use its -[`expect`](../std/option/enum.Option.html#method.expect) +[`expect`](../../std/option/enum.Option.html#method.expect) method. `expect` does exactly the same thing as `unwrap`, except it prints a message you give to `expect`. This makes the resulting panic a bit nicer to deal with, since it will show your message instead of @@ -719,7 +719,7 @@ fn main() { ``` There are a couple new things in this example. The first is the use of the -[`Option::ok_or`](../std/option/enum.Option.html#method.ok_or) +[`Option::ok_or`](../../std/option/enum.Option.html#method.ok_or) combinator. This is one way to convert an `Option` into a `Result`. The conversion requires you to specify what error to use if `Option` is `None`. Like the other combinators we've seen, its definition is very simple: @@ -734,7 +734,7 @@ fn ok_or(option: Option, err: E) -> Result { ``` The other new combinator used here is -[`Result::map_err`](../std/result/enum.Result.html#method.map_err). +[`Result::map_err`](../../std/result/enum.Result.html#method.map_err). This is like `Result::map`, except it maps a function on to the *error* portion of a `Result` value. If the `Result` is an `Ok(...)` value, then it is returned unmodified. @@ -781,7 +781,7 @@ fn main() { (N.B. The `AsRef` is used because those are the [same bounds used on -`std::fs::File::open`](../std/fs/struct.File.html#method.open). +`std::fs::File::open`](../../std/fs/struct.File.html#method.open). This makes it ergonomic to use any kind of string as a file path.) There are three different errors that can occur here: @@ -791,16 +791,16 @@ There are three different errors that can occur here: 3. A problem parsing the data as a number. The first two problems are described via the -[`std::io::Error`](../std/io/struct.Error.html) type. We know this +[`std::io::Error`](../../std/io/struct.Error.html) type. We know this because of the return types of -[`std::fs::File::open`](../std/fs/struct.File.html#method.open) and -[`std::io::Read::read_to_string`](../std/io/trait.Read.html#method.read_to_string). +[`std::fs::File::open`](../../std/fs/struct.File.html#method.open) and +[`std::io::Read::read_to_string`](../../std/io/trait.Read.html#method.read_to_string). (Note that they both use the [`Result` type alias idiom](#the-result-type-alias-idiom) described previously. If you click on the `Result` type, you'll [see the type -alias](../std/io/type.Result.html), and consequently, the underlying +alias](../../std/io/type.Result.html), and consequently, the underlying `io::Error` type.) The third problem is described by the -[`std::num::ParseIntError`](../std/num/struct.ParseIntError.html) +[`std::num::ParseIntError`](../../std/num/struct.ParseIntError.html) type. The `io::Error` type in particular is *pervasive* throughout the standard library. You will see it again and again. @@ -944,7 +944,7 @@ macro_rules! try { } ``` -(The [real definition](../std/macro.try!.html) is a bit more +(The [real definition](../../std/macro.try.html) is a bit more sophisticated. We will address that later.) Using the `try!` macro makes it very easy to simplify our last example. Since @@ -1003,7 +1003,7 @@ determine the type of error is not robust. (Admittedly, this downside is far more important inside of a library as opposed to, say, an application.) For example, the `io::Error` type embeds an -[`io::ErrorKind`](../std/io/enum.ErrorKind.html), +[`io::ErrorKind`](../../std/io/enum.ErrorKind.html), which is *structured data* that represents what went wrong during an IO operation. This is important because you might want to react differently depending on the error. (e.g., A `BrokenPipe` error might mean quitting your @@ -1076,8 +1076,8 @@ that you don't remove choices from the caller unnecessarily. # Standard library traits used for error handling The standard library defines two integral traits for error handling: -[`std::error::Error`](../std/error/trait.Error.html) and -[`std::convert::From`](../std/convert/trait.From.html). While `Error` +[`std::error::Error`](../../std/error/trait.Error.html) and +[`std::convert::From`](../../std/convert/trait.From.html). While `Error` is designed specifically for generically describing errors, the `From` trait serves a more general role for converting values between two distinct types. @@ -1085,7 +1085,7 @@ distinct types. ## The `Error` trait The `Error` trait is [defined in the standard -library](../std/error/trait.Error.html): +library](../../std/error/trait.Error.html): ```rust use std::fmt::{Debug, Display}; @@ -1113,7 +1113,7 @@ The first two are a result of `Error` requiring impls for both `Debug` and `Display`. The latter two are from the two methods defined on `Error`. The power of `Error` comes from the fact that all error types impl `Error`, which means errors can be existentially quantified as a -[trait object](../book/trait-objects.html). +[trait object](trait-objects.html). This manifests as either `Box` or `&Error`. Indeed, the `cause` method returns an `&Error`, which is itself a trait object. We'll revisit the `Error` trait's utility as a trait object later. @@ -1189,7 +1189,7 @@ different error types and satisfy the contracts defined for `description` and The `std::convert::From` trait is [defined in the standard -library](../std/convert/trait.From.html): +library](../../std/convert/trait.From.html): @@ -1204,7 +1204,7 @@ way to talk about conversion *from* a particular type `T` to some other type (in this case, “some other type” is the subject of the impl, or `Self`). The crux of `From` is the [set of implementations provided by the standard -library](../std/convert/trait.From.html). +library](../../std/convert/trait.From.html). Here are a few simple examples demonstrating how `From` works: @@ -1235,11 +1235,11 @@ use std::fs; use std::io; use std::num; -// We have to jump through some hoops to actually get error values. +// We have to jump through some hoops to actually get error values: let io_err: io::Error = io::Error::last_os_error(); let parse_err: num::ParseIntError = "not a number".parse::().unwrap_err(); -// OK, here are the conversions. +// OK, here are the conversions: let err1: Box = From::from(io_err); let err2: Box = From::from(parse_err); ``` @@ -1271,7 +1271,7 @@ macro_rules! try { ``` This is not its real definition. Its real definition is -[in the standard library](../std/macro.try!.html): +[in the standard library](../../std/macro.try.html): @@ -1340,8 +1340,8 @@ There's one little nit left: the `Box` type is *opaque*. If we return a `Box` to the caller, the caller can't (easily) inspect underlying error type. The situation is certainly better than `String` because the caller can call methods like -[`description`](../std/error/trait.Error.html#tymethod.description) -and [`cause`](../std/error/trait.Error.html#method.cause), but the +[`description`](../../std/error/trait.Error.html#tymethod.description) +and [`cause`](../../std/error/trait.Error.html#method.cause), but the limitation remains: `Box` is opaque. (N.B. This isn't entirely true because Rust does have runtime reflection, which is useful in some scenarios that are [beyond the scope of this @@ -1484,14 +1484,14 @@ And that's it! If your library needs to report custom errors, then you should probably define your own error type. It's up to you whether or not to expose its representation (like -[`ErrorKind`](../std/io/enum.ErrorKind.html)) or keep it hidden (like -[`ParseIntError`](../std/num/struct.ParseIntError.html)). Regardless +[`ErrorKind`](../../std/io/enum.ErrorKind.html)) or keep it hidden (like +[`ParseIntError`](../../std/num/struct.ParseIntError.html)). Regardless of how you do it, it's usually good practice to at least provide some information about the error beyond its `String` representation. But certainly, this will vary depending on use cases. At a minimum, you should probably implement the -[`Error`](../std/error/trait.Error.html) +[`Error`](../../std/error/trait.Error.html) trait. This will give users of your library some minimum flexibility for [composing errors](#the-real-try-macro). Implementing the `Error` trait also means that users are guaranteed the ability to obtain a string representation @@ -1507,8 +1507,8 @@ provides `From` impls for both `io::Error` and `byteorder::Error`. Finally, depending on your tastes, you may also want to define a [`Result` type alias](#the-result-type-alias-idiom), particularly if your library defines a single error type. This is used in the standard library -for [`io::Result`](../std/io/type.Result.html) -and [`fmt::Result`](../std/fmt/type.Result.html). +for [`io::Result`](../../std/io/type.Result.html) +and [`fmt::Result`](../../std/fmt/type.Result.html). # Case study: A program to read population data @@ -1609,7 +1609,7 @@ fn main() { let data_path = &matches.free[0]; let city: &str = &matches.free[1]; - // Do stuff with information + // Do stuff with information. } ``` @@ -1702,9 +1702,9 @@ fn main() { Let's outline the errors. We can start with the obvious: the three places that `unwrap` is called: -1. [`File::open`](../std/fs/struct.File.html#method.open) +1. [`File::open`](../../std/fs/struct.File.html#method.open) can return an - [`io::Error`](../std/io/struct.Error.html). + [`io::Error`](../../std/io/struct.Error.html). 2. [`csv::Reader::decode`](http://burntsushi.net/rustdoc/csv/struct.Reader.html#method.decode) decodes one record at a time, and [decoding a @@ -1747,7 +1747,7 @@ simply ignoring that row. use std::path::Path; struct Row { - // unchanged + // This struct remains unchanged. } struct PopulationCount { @@ -1769,7 +1769,7 @@ fn search>(file_path: P, city: &str) -> Vec { for row in rdr.decode::() { let row = row.unwrap(); match row.population { - None => { } // skip it + None => { } // Skip it. Some(count) => if row.city == city { found.push(PopulationCount { city: row.city, @@ -1825,7 +1825,7 @@ Let's try it: ```rust,ignore use std::error::Error; -// The rest of the code before this is unchanged +// The rest of the code before this is unchanged. fn search> (file_path: P, city: &str) @@ -1836,7 +1836,7 @@ fn search> for row in rdr.decode::() { let row = try!(row); match row.population { - None => { } // skip it + None => { } // Skip it. Some(count) => if row.city == city { found.push(PopulationCount { city: row.city, @@ -1859,7 +1859,7 @@ Instead of `x.unwrap()`, we now have `try!(x)`. Since our function returns a error occurs. At the end of `search` we also convert a plain string to an error type -by using the [corresponding `From` impls](../std/convert/trait.From.html): +by using the [corresponding `From` impls](../../std/convert/trait.From.html): ```rust,ignore // We are making use of this impl in the code above, since we call `From::from` @@ -1957,7 +1957,7 @@ that it is generic on some type parameter `R` that satisfies ```rust,ignore use std::io; -// The rest of the code before this is unchanged +// The rest of the code before this is unchanged. fn search> (file_path: &Option

, city: &str) @@ -2070,7 +2070,7 @@ fn search> for row in rdr.decode::() { let row = try!(row); match row.population { - None => { } // skip it + None => { } // Skip it. Some(count) => if row.city == city { found.push(PopulationCount { city: row.city, @@ -2162,10 +2162,10 @@ heuristics! * If you're writing short example code that would be overburdened by error handling, it's probably fine to use `unwrap` (whether that's - [`Result::unwrap`](../std/result/enum.Result.html#method.unwrap), - [`Option::unwrap`](../std/option/enum.Option.html#method.unwrap) + [`Result::unwrap`](../../std/result/enum.Result.html#method.unwrap), + [`Option::unwrap`](../../std/option/enum.Option.html#method.unwrap) or preferably - [`Option::expect`](../std/option/enum.Option.html#method.expect)). + [`Option::expect`](../../std/option/enum.Option.html#method.expect)). Consumers of your code should know to use proper error handling. (If they don't, send them here!) * If you're writing a quick 'n' dirty program, don't feel ashamed if you use @@ -2175,37 +2175,37 @@ heuristics! anyway, then use either a `String` or a `Box` for your error type. * Otherwise, in a program, define your own error types with appropriate - [`From`](../std/convert/trait.From.html) + [`From`](../../std/convert/trait.From.html) and - [`Error`](../std/error/trait.Error.html) - impls to make the [`try!`](../std/macro.try!.html) + [`Error`](../../std/error/trait.Error.html) + impls to make the [`try!`](../../std/macro.try.html) macro more ergonomic. * If you're writing a library and your code can produce errors, define your own error type and implement the - [`std::error::Error`](../std/error/trait.Error.html) + [`std::error::Error`](../../std/error/trait.Error.html) trait. Where appropriate, implement - [`From`](../std/convert/trait.From.html) to make both + [`From`](../../std/convert/trait.From.html) to make both your library code and the caller's code easier to write. (Because of Rust's coherence rules, callers will not be able to impl `From` on your error type, so your library should do it.) * Learn the combinators defined on - [`Option`](../std/option/enum.Option.html) + [`Option`](../../std/option/enum.Option.html) and - [`Result`](../std/result/enum.Result.html). + [`Result`](../../std/result/enum.Result.html). Using them exclusively can be a bit tiring at times, but I've personally found a healthy mix of `try!` and combinators to be quite appealing. `and_then`, `map` and `unwrap_or` are my favorites. -[1]: ../book/patterns.html -[2]: ../std/option/enum.Option.html#method.map -[3]: ../std/option/enum.Option.html#method.unwrap_or -[4]: ../std/option/enum.Option.html#method.unwrap_or_else -[5]: ../std/option/enum.Option.html -[6]: ../std/result/index.html -[7]: ../std/result/enum.Result.html#method.unwrap -[8]: ../std/fmt/trait.Debug.html -[9]: ../std/primitive.str.html#method.parse -[10]: ../book/associated-types.html +[1]: patterns.html +[2]: ../../std/option/enum.Option.html#method.map +[3]: ../../std/option/enum.Option.html#method.unwrap_or +[4]: ../../std/option/enum.Option.html#method.unwrap_or_else +[5]: ../../std/option/enum.Option.html +[6]: ../../std/result/index.html +[7]: ../../std/result/enum.Result.html#method.unwrap +[8]: ../../std/fmt/trait.Debug.html +[9]: ../../std/primitive.str.html#method.parse +[10]: associated-types.html [11]: https://github.com/petewarden/dstkdata [12]: http://burntsushi.net/stuff/worldcitiespop.csv.gz [13]: http://burntsushi.net/stuff/uscitiespop.csv.gz diff --git a/trpl/ffi.md b/trpl/ffi.md index ca104ff..067d061 100644 --- a/trpl/ffi.md +++ b/trpl/ffi.md @@ -1,4 +1,4 @@ -% Foreign Function Interface +# Foreign Function Interface # Introduction @@ -28,8 +28,7 @@ and add `extern crate libc;` to your crate root. The following is a minimal example of calling a foreign function which will compile if snappy is installed: -```rust,no_run -# #![feature(libc)] +```rust,ignore extern crate libc; use libc::size_t; @@ -56,14 +55,13 @@ almost any function that takes a pointer argument isn't valid for all possible inputs since the pointer could be dangling, and raw pointers fall outside of Rust's safe memory model. -When declaring the argument types to a foreign function, the Rust compiler can -not check if the declaration is correct, so specifying it correctly is part of -keeping the binding correct at runtime. +When declaring the argument types to a foreign function, the Rust compiler +cannot check if the declaration is correct, so specifying it correctly is part +of keeping the binding correct at runtime. The `extern` block can be extended to cover the entire snappy API: -```rust,no_run -# #![feature(libc)] +```rust,ignore extern crate libc; use libc::{c_int, size_t}; @@ -95,11 +93,10 @@ internal details. Wrapping the functions which expect buffers involves using the `slice::raw` module to manipulate Rust vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous block of memory. The -length is number of elements currently contained, and the capacity is the total size in elements of +length is the number of elements currently contained, and the capacity is the total size in elements of the allocated memory. The length is less than or equal to the capacity. -```rust -# #![feature(libc)] +```rust,ignore # extern crate libc; # use libc::{c_int, size_t}; # unsafe fn snappy_validate_compressed_buffer(_: *const u8, _: size_t) -> c_int { 0 } @@ -123,8 +120,7 @@ required capacity to hold the compressed output. The vector can then be passed t `snappy_compress` function as an output parameter. An output parameter is also passed to retrieve the true length after compression for setting the length. -```rust -# #![feature(libc)] +```rust,ignore # extern crate libc; # use libc::{size_t, c_int}; # unsafe fn snappy_compress(a: *const u8, b: size_t, c: *mut u8, @@ -150,8 +146,7 @@ pub fn compress(src: &[u8]) -> Vec { Decompression is similar, because snappy stores the uncompressed size as part of the compression format and `snappy_uncompressed_length` will retrieve the exact buffer size required. -```rust -# #![feature(libc)] +```rust,ignore # extern crate libc; # use libc::{size_t, c_int}; # unsafe fn snappy_uncompress(compressed: *const u8, @@ -185,8 +180,7 @@ pub fn uncompress(src: &[u8]) -> Option> { Then, we can add some tests to show how to use them. -```rust -# #![feature(libc)] +```rust,ignore # extern crate libc; # use libc::{c_int, size_t}; # unsafe fn snappy_compress(input: *const u8, @@ -246,7 +240,7 @@ Foreign libraries often hand off ownership of resources to the calling code. When this occurs, we must use Rust's destructors to provide safety and guarantee the release of these resources (especially in the case of panic). -For more about destructors, see the [Drop trait](../std/ops/trait.Drop.html). +For more about destructors, see the [Drop trait](../../std/ops/trait.Drop.html). # Callbacks from C code to Rust functions @@ -277,7 +271,7 @@ extern { fn main() { unsafe { register_callback(callback); - trigger_callback(); // Triggers the callback + trigger_callback(); // Triggers the callback. } } ``` @@ -294,7 +288,7 @@ int32_t register_callback(rust_callback callback) { } void trigger_callback() { - cb(7); // Will call callback(7) in Rust + cb(7); // Will call callback(7) in Rust. } ``` @@ -309,7 +303,7 @@ However it is often desired that the callback is targeted to a special Rust object. This could be the object that represents the wrapper for the respective C object. -This can be achieved by passing an raw pointer to the object down to the +This can be achieved by passing a raw pointer to the object down to the C library. The C library can then include the pointer to the Rust object in the notification. This will allow the callback to unsafely access the referenced Rust object. @@ -320,13 +314,13 @@ Rust code: #[repr(C)] struct RustObject { a: i32, - // other members + // Other members... } extern "C" fn callback(target: *mut RustObject, a: i32) { println!("I'm called from C with value {0}", a); unsafe { - // Update the value in RustObject with the value received from the callback + // Update the value in RustObject with the value received from the callback: (*target).a = a; } } @@ -339,7 +333,7 @@ extern { } fn main() { - // Create the object that will be referenced in the callback + // Create the object that will be referenced in the callback: let mut rust_object = Box::new(RustObject { a: 5 }); unsafe { @@ -363,7 +357,7 @@ int32_t register_callback(void* callback_target, rust_callback callback) { } void trigger_callback() { - cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust + cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust. } ``` @@ -408,7 +402,7 @@ libraries: * Static - `#[link(name = "my_build_dependency", kind = "static")]` * Frameworks - `#[link(name = "CoreFoundation", kind = "framework")]` -Note that frameworks are only available on OSX targets. +Note that frameworks are only available on macOS targets. The different `kind` values are meant to differentiate how the native library participates in linkage. From a linkage perspective, the Rust compiler creates @@ -437,7 +431,7 @@ A few examples of how this model can be used are: is included in a final target (like a binary), the native library will be linked in. -On OSX, frameworks behave with the same semantics as a dynamic library. +On macOS, frameworks behave with the same semantics as a dynamic library. # Unsafe blocks @@ -460,8 +454,7 @@ Foreign APIs often export a global variable which could do something like track global state. In order to access these variables, you declare them in `extern` blocks with the `static` keyword: -```rust,no_run -# #![feature(libc)] +```rust,ignore extern crate libc; #[link(name = "readline")] @@ -471,7 +464,7 @@ extern { fn main() { println!("You have readline version {} installed.", - rl_readline_version as i32); + unsafe { rl_readline_version as i32 }); } ``` @@ -479,8 +472,7 @@ Alternatively, you may need to alter global state provided by a foreign interface. To do this, statics can be declared with `mut` so we can mutate them. -```rust,no_run -# #![feature(libc)] +```rust,ignore extern crate libc; use std::ffi::CString; @@ -512,8 +504,7 @@ Most foreign code exposes a C ABI, and Rust uses the platform's C calling conven calling foreign functions. Some foreign functions, most notably the Windows API, use other calling conventions. Rust provides a way to tell the compiler which convention to use: -```rust -# #![feature(libc)] +```rust,ignore extern crate libc; #[cfg(all(target_os = "win32", target_arch = "x86"))] @@ -539,6 +530,7 @@ This is currently hidden behind the `abi_vectorcall` gate and is subject to chan * `system` * `C` * `win64` +* `sysv64` Most of the abis in this list are self-explanatory, but the `system` abi may seem a little odd. This constraint selects whatever the appropriate ABI is for @@ -573,6 +565,31 @@ The [`libc` crate on crates.io][libc] includes type aliases and function definitions for the C standard library in the `libc` module, and Rust links against `libc` and `libm` by default. +# Variadic functions + +In C, functions can be 'variadic', meaning they accept a variable number of arguments. This can +be achieved in Rust by specifying `...` within the argument list of a foreign function declaration: + +```no_run +extern { + fn foo(x: i32, ...); +} + +fn main() { + unsafe { + foo(10, 20, 30, 40, 50); + } +} +``` + +Normal Rust functions can *not* be variadic: + +```ignore +// This will not compile + +fn foo(x: i32, ...) { } +``` + # The "nullable pointer optimization" Certain Rust types are defined to never be `null`. This includes references (`&T`, @@ -598,14 +615,13 @@ callback, which gets called in certain situations. The callback is passed a func and an integer and it is supposed to run the function with the integer as a parameter. So we have function pointers flying across the FFI boundary in both directions. -```rust -# #![feature(libc)] +```rust,ignore extern crate libc; use libc::c_int; # #[cfg(hidden)] extern "C" { - /// Register the callback. + /// Registers the callback. fn register(cb: Option c_int>, c_int) -> c_int>); } # unsafe fn register(_: Option c_int>, @@ -661,26 +677,31 @@ attribute turns off Rust's name mangling, so that it is easier to link to. It’s important to be mindful of `panic!`s when working with FFI. A `panic!` across an FFI boundary is undefined behavior. If you’re writing code that may -panic, you should run it in another thread, so that the panic doesn’t bubble up -to C: +panic, you should run it in a closure with [`catch_unwind`]: ```rust -use std::thread; +use std::panic::catch_unwind; #[no_mangle] pub extern fn oh_no() -> i32 { - let h = thread::spawn(|| { + let result = catch_unwind(|| { panic!("Oops!"); }); - - match h.join() { - Ok(_) => 1, - Err(_) => 0, + match result { + Ok(_) => 0, + Err(_) => 1, } } -# fn main() {} + +fn main() {} ``` +Please note that [`catch_unwind`] will only catch unwinding panics, not +those who abort the process. See the documentation of [`catch_unwind`] +for more information. + +[`catch_unwind`]: ../../std/panic/fn.catch_unwind.html + # Representing opaque structs Sometimes, a C library wants to provide a pointer to something, but not let you @@ -694,8 +715,7 @@ void bar(void *arg); We can represent this in Rust with the `c_void` type: -```rust -# #![feature(libc)] +```rust,ignore extern crate libc; extern "C" { diff --git a/trpl/functions.md b/trpl/functions.md index b040684..96c8e9f 100644 --- a/trpl/functions.md +++ b/trpl/functions.md @@ -1,4 +1,4 @@ -% Functions +# Functions Every Rust program has at least one function, the `main` function: @@ -135,7 +135,7 @@ In Rust, however, using `let` to introduce a binding is _not_ an expression. The following will produce a compile-time error: ```rust,ignore -let x = (let y = 5); // expected identifier, found keyword `let` +let x = (let y = 5); // Expected identifier, found keyword `let`. ``` The compiler is telling us here that it was expecting to see the beginning of @@ -151,7 +151,7 @@ other returned value would be too surprising: ```rust let mut y = 5; -let x = (y = 6); // x has the value `()`, not `6` +let x = (y = 6); // `x` has the value `()`, not `6`. ``` The second kind of statement in Rust is the *expression statement*. Its @@ -183,7 +183,7 @@ But what about early returns? Rust does have a keyword for that, `return`: fn foo(x: i32) -> i32 { return x; - // we never run this code! + // We never run this code! x + 1 } ``` @@ -230,6 +230,19 @@ If you want more information, you can get a backtrace by setting the ```text $ RUST_BACKTRACE=1 ./diverges thread 'main' panicked at 'This function never returns!', hello.rs:2 +Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. +stack backtrace: + hello::diverges + at ./hello.rs:2 + hello::main + at ./hello.rs:6 +``` + +If you want the complete backtrace and filenames: + +```text +$ RUST_BACKTRACE=full ./diverges +thread 'main' panicked at 'This function never returns!', hello.rs:2 stack backtrace: 1: 0x7f402773a829 - sys::backtrace::write::h0942de78b6c02817K8r 2: 0x7f402773d7fc - panicking::on_panic::h3f23f9d0b5f4c91bu9w @@ -262,7 +275,7 @@ note: Run with `RUST_BACKTRACE=1` for a backtrace. `RUST_BACKTRACE` also works with Cargo’s `run` command: ```text -$ RUST_BACKTRACE=1 cargo run +$ RUST_BACKTRACE=full cargo run Running `target/debug/diverges` thread 'main' panicked at 'This function never returns!', hello.rs:2 stack backtrace: @@ -307,10 +320,10 @@ fn plus_one(i: i32) -> i32 { i + 1 } -// without type inference +// Without type inference: let f: fn(i32) -> i32 = plus_one; -// with type inference +// With type inference: let f = plus_one; ``` diff --git a/trpl/generics.md b/trpl/generics.md index 9ab6014..891380c 100644 --- a/trpl/generics.md +++ b/trpl/generics.md @@ -1,4 +1,4 @@ -% Generics +# Generics Sometimes, when writing a function or data type, we may want it to work for multiple types of arguments. In Rust, we can do this with generics. @@ -78,7 +78,7 @@ We can write functions that take generic types with a similar syntax: ```rust fn takes_anything(x: T) { - // do something with x + // Do something with `x`. } ``` @@ -140,5 +140,51 @@ container types like [`Vec`][Vec]. On the other hand, often you want to trade that flexibility for increased expressive power. Read about [trait bounds][traits] to see why and how. +## Resolving ambiguities + +Most of the time when generics are involved, the compiler can infer the +generic parameters automatically: + +```rust +// v must be a Vec but we don't know what T is yet +let mut v = Vec::new(); +// v just got a bool value, so T must be bool! +v.push(true); +// Debug-print v +println!("{:?}", v); +``` + +Sometimes though, the compiler needs a little help. For example, had we +omitted the last line, we would get a compile error: + +```rust,ignore +let v = Vec::new(); +// ^^^^^^^^ cannot infer type for `T` +// +// note: type annotations or generic parameter binding required +println!("{:?}", v); +``` + +We can solve this using either a type annotation: + +```rust +let v: Vec = Vec::new(); +println!("{:?}", v); +``` + +or by binding the generic parameter `T` via the so-called +[‘turbofish’][turbofish] `::<>` syntax: + +```rust +let v = Vec::::new(); +println!("{:?}", v); +``` + +The second approach is useful in situations where we don’t want to bind the +result to a variable. It can also be used to bind generic parameters in +functions or methods. See [Iterators § Consumers](iterators.html#consumers) +for an example. + [traits]: traits.html -[Vec]: ../std/vec/struct.Vec.html +[Vec]: ../../std/vec/struct.Vec.html +[turbofish]: ../../std/iter/trait.Iterator.html#method.collect diff --git a/trpl/getting-started.md b/trpl/getting-started.md index 700ab2b..06ea24f 100644 --- a/trpl/getting-started.md +++ b/trpl/getting-started.md @@ -1,151 +1,63 @@ -% Getting Started +# Getting Started This first chapter of the book will get us going with Rust and its tooling. First, we’ll install Rust. Then, the classic ‘Hello World’ program. Finally, we’ll talk about Cargo, Rust’s build system and package manager. +We’ll be showing off a number of commands using a terminal, and those lines all +start with `$`. You don't need to type in the `$`s, they are there to indicate +the start of each command. We’ll see many tutorials and examples around the web +that follow this convention: `$` for commands run as our regular user, and `#` +for commands we should be running as an administrator. + # Installing Rust The first step to using Rust is to install it. Generally speaking, you’ll need an Internet connection to run the commands in this section, as we’ll be downloading Rust from the Internet. -We’ll be showing off a number of commands using a terminal, and those lines all -start with `$`. You don't need to type in the `$`s, they are there to indicate -the start of each command. We’ll see many tutorials and examples around the web -that follow this convention: `$` for commands run as our regular user, and `#` -for commands we should be running as an administrator. +The Rust compiler runs on, and compiles to, a great number of platforms, but is +best supported on Linux, Mac, and Windows, on the x86 and x86-64 CPU +architecture. There are official builds of the Rust compiler and standard +library for these platforms and more. [For full details on Rust platform support +see the website][platform-support]. + +[platform-support]: https://forge.rust-lang.org/platform-support.html + +## Installing Rust -## Platform support - -The Rust compiler runs on, and compiles to, a great number of platforms, though -not all platforms are equally supported. Rust's support levels are organized -into three tiers, each with a different set of guarantees. - -Platforms are identified by their "target triple" which is the string to inform -the compiler what kind of output should be produced. The columns below indicate -whether the corresponding component works on the specified platform. - -### Tier 1 - -Tier 1 platforms can be thought of as "guaranteed to build and work". -Specifically they will each satisfy the following requirements: - -* Automated testing is set up to run tests for the platform. -* Landing changes to the `rust-lang/rust` repository's master branch is gated on - tests passing. -* Official release artifacts are provided for the platform. -* Documentation for how to use and how to build the platform is available. - -| Target | std |rustc|cargo| notes | -|-------------------------------|-----|-----|-----|----------------------------| -| `i686-apple-darwin` | ✓ | ✓ | ✓ | 32-bit OSX (10.7+, Lion+) | -| `i686-pc-windows-gnu` | ✓ | ✓ | ✓ | 32-bit MinGW (Windows 7+) | -| `i686-pc-windows-msvc` | ✓ | ✓ | ✓ | 32-bit MSVC (Windows 7+) | -| `i686-unknown-linux-gnu` | ✓ | ✓ | ✓ | 32-bit Linux (2.6.18+) | -| `x86_64-apple-darwin` | ✓ | ✓ | ✓ | 64-bit OSX (10.7+, Lion+) | -| `x86_64-pc-windows-gnu` | ✓ | ✓ | ✓ | 64-bit MinGW (Windows 7+) | -| `x86_64-pc-windows-msvc` | ✓ | ✓ | ✓ | 64-bit MSVC (Windows 7+) | -| `x86_64-unknown-linux-gnu` | ✓ | ✓ | ✓ | 64-bit Linux (2.6.18+) | - -### Tier 2 - -Tier 2 platforms can be thought of as "guaranteed to build". Automated tests -are not run so it's not guaranteed to produce a working build, but platforms -often work to quite a good degree and patches are always welcome! Specifically, -these platforms are required to have each of the following: - -* Automated building is set up, but may not be running tests. -* Landing changes to the `rust-lang/rust` repository's master branch is gated on - platforms **building**. Note that this means for some platforms only the - standard library is compiled, but for others the full bootstrap is run. -* Official release artifacts are provided for the platform. - -| Target | std |rustc|cargo| notes | -|-------------------------------|-----|-----|-----|----------------------------| -| `aarch64-apple-ios` | ✓ | | | ARM64 iOS | -| `aarch64-unknown-linux-gnu` | ✓ | ✓ | ✓ | ARM64 Linux (2.6.18+) | -| `arm-linux-androideabi` | ✓ | | | ARM Android | -| `arm-unknown-linux-gnueabi` | ✓ | ✓ | ✓ | ARM Linux (2.6.18+) | -| `arm-unknown-linux-gnueabihf` | ✓ | ✓ | ✓ | ARM Linux (2.6.18+) | -| `armv7-apple-ios` | ✓ | | | ARM iOS | -|`armv7-unknown-linux-gnueabihf`| ✓ | ✓ | ✓ | ARMv7 Linux (2.6.18+) | -| `armv7s-apple-ios` | ✓ | | | ARM iOS | -| `i386-apple-ios` | ✓ | | | 32-bit x86 iOS | -| `i586-pc-windows-msvc` | ✓ | | | 32-bit Windows w/o SSE | -| `mips-unknown-linux-gnu` | ✓ | | | MIPS Linux (2.6.18+) | -| `mips-unknown-linux-musl` | ✓ | | | MIPS Linux with MUSL | -| `mipsel-unknown-linux-gnu` | ✓ | | | MIPS (LE) Linux (2.6.18+) | -| `mipsel-unknown-linux-musl` | ✓ | | | MIPS (LE) Linux with MUSL | -| `powerpc-unknown-linux-gnu` | ✓ | | | PowerPC Linux (2.6.18+) | -| `powerpc64-unknown-linux-gnu` | ✓ | | | PPC64 Linux (2.6.18+) | -|`powerpc64le-unknown-linux-gnu`| ✓ | | | PPC64LE Linux (2.6.18+) | -| `x86_64-apple-ios` | ✓ | | | 64-bit x86 iOS | -| `x86_64-rumprun-netbsd` | ✓ | | | 64-bit NetBSD Rump Kernel | -| `x86_64-unknown-freebsd` | ✓ | ✓ | ✓ | 64-bit FreeBSD | -| `x86_64-unknown-linux-musl` | ✓ | | | 64-bit Linux with MUSL | -| `x86_64-unknown-netbsd` | ✓ | ✓ | ✓ | 64-bit NetBSD | - -### Tier 3 - -Tier 3 platforms are those which Rust has support for, but landing changes is -not gated on the platform either building or passing tests. Working builds for -these platforms may be spotty as their reliability is often defined in terms of -community contributions. Additionally, release artifacts and installers are not -provided, but there may be community infrastructure producing these in -unofficial locations. - -| Target | std |rustc|cargo| notes | -|-------------------------------|-----|-----|-----|----------------------------| -| `aarch64-linux-android` | ✓ | | | ARM64 Android | -| `armv7-linux-androideabi` | ✓ | | | ARM-v7a Android | -| `i686-linux-android` | ✓ | | | 32-bit x86 Android | -| `i686-pc-windows-msvc` (XP) | ✓ | | | Windows XP support | -| `i686-unknown-freebsd` | ✓ | ✓ | ✓ | 32-bit FreeBSD | -| `x86_64-pc-windows-msvc` (XP) | ✓ | | | Windows XP support | -| `x86_64-sun-solaris` | ✓ | ✓ | | 64-bit Solaris/SunOS | -| `x86_64-unknown-bitrig` | ✓ | ✓ | | 64-bit Bitrig | -| `x86_64-unknown-dragonfly` | ✓ | ✓ | | 64-bit DragonFlyBSD | -| `x86_64-unknown-openbsd` | ✓ | ✓ | | 64-bit OpenBSD | - -Note that this table can be expanded over time, this isn't the exhaustive set of -tier 3 platforms that will ever be! - -## Installing on Linux or Mac - -If we're on Linux or a Mac, all we need to do is open a terminal and type this: +All you need to do on Unix systems like Linux and macOS is open a +terminal and type this: ```bash -$ curl -sSf https://static.rust-lang.org/rustup.sh | sh +$ curl https://sh.rustup.rs -sSf | sh ``` -This will download a script, and start the installation. If it all goes well, -you’ll see this appear: +It will download a script, and start the installation. If everything +goes well, you’ll see this appear: ```text -Rust is ready to roll. +Rust is installed now. Great! ``` -From here, press `y` for ‘yes’, and then follow the rest of the prompts. +Installing on Windows is nearly as easy: download and run +[rustup-init.exe]. It will start the installation in a console and +present the above message on success. -## Installing on Windows +For other installation options and information, visit the [install] +page of the Rust website. -If you're on Windows, please download the appropriate [installer][install-page]. - -[install-page]: https://www.rust-lang.org/install.html +[rustup-init.exe]: https://win.rustup.rs +[install]: https://www.rust-lang.org/install.html ## Uninstalling -Uninstalling Rust is as easy as installing it. On Linux or Mac, run -the uninstall script: +Uninstalling Rust is as easy as installing it: ```bash -$ sudo /usr/local/lib/rustlib/uninstall.sh +$ rustup self uninstall ``` -If we used the Windows installer, we can re-run the `.msi` and it will give us -an uninstall option. - ## Troubleshooting If we've got Rust installed, we can open up a shell, and type this: @@ -158,20 +70,33 @@ You should see the version number, commit hash, and commit date. If you do, Rust has been installed successfully! Congrats! -If you don't and you're on Windows, check that Rust is in your %PATH% system -variable: `$ echo %PATH%`. If it isn't, run the installer again, select "Change" -on the "Change, repair, or remove installation" page and ensure "Add to PATH" is -installed on the local hard drive. If you need to configure your path manually, -you can find the Rust executables in a directory like -`"C:\Program Files\Rust stable GNU 1.x\bin"`. +If you don't, that probably means that the `PATH` environment variable +doesn't include Cargo's binary directory, `~/.cargo/bin` on Unix, or +`%USERPROFILE%\.cargo\bin` on Windows. This is the directory where +Rust development tools live, and most Rust developers keep it in their +`PATH` environment variable, which makes it possible to run `rustc` on +the command line. Due to differences in operating systems, command +shells, and bugs in installation, you may need to restart your shell, +log out of the system, or configure `PATH` manually as appropriate for +your operating environment. Rust does not do its own linking, and so you’ll need to have a linker -installed. Doing so will depend on your specific system, consult its -documentation for more details. - -If not, there are a number of places where we can get help. The easiest is -[the #rust-beginners IRC channel on irc.mozilla.org][irc-beginners] and for -general discussion [the #rust IRC channel on irc.mozilla.org][irc], which we +installed. Doing so will depend on your specific system. For +Linux-based systems, Rust will attempt to call `cc` for linking. On +`windows-msvc` (Rust built on Windows with Microsoft Visual Studio), +this depends on having [Microsoft Visual C++ Build Tools][msvbt] +installed. These do not need to be in `%PATH%` as `rustc` will find +them automatically. In general, if you have your linker in a +non-traditional location you can call `rustc +linker=/path/to/cc`, where `/path/to/cc` should point to your linker path. + +[msvbt]: http://landinghub.visualstudio.com/visual-cpp-build-tools + +If you are still stuck, there are a number of places where we can get +help. The easiest is +[the #rust-beginners IRC channel on irc.mozilla.org][irc-beginners] +and for general discussion +[the #rust IRC channel on irc.mozilla.org][irc], which we can access through [Mibbit][mibbit]. Then we'll be chatting with other Rustaceans (a silly nickname we call ourselves) who can help us out. Other great resources include [the user’s forum][users] and [Stack Overflow][stackoverflow]. @@ -183,9 +108,7 @@ resources include [the user’s forum][users] and [Stack Overflow][stackoverflow [stackoverflow]: http://stackoverflow.com/questions/tagged/rust This installer also installs a copy of the documentation locally, so we can -read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location. -On Windows, it's in a `share/doc` directory, inside the directory to which Rust -was installed. +read it offline. It's only a `rustup doc` away! # Hello, world! @@ -230,12 +153,13 @@ $ cd hello_world ## Writing and Running a Rust Program -Next, make a new source file and call it *main.rs*. Rust files always end -in a *.rs* extension. If you’re using more than one word in your filename, use -an underscore to separate them; for example, you'd use *hello_world.rs* rather -than *helloworld.rs*. +We need to create a source file for our Rust program. Rust files always end +in a *.rs* extension. If you are using more than one word in your filename, +use an underscore to separate them; for example, you would use +*my_program.rs* rather than *myprogram.rs*. -Now open the *main.rs* file you just created, and type the following code: +Now, make a new file and call it *main.rs*. Open the file and type +the following code: ```rust fn main() { @@ -243,7 +167,7 @@ fn main() { } ``` -Save the file, and go back to your terminal window. On Linux or OSX, enter the +Save the file, and go back to your terminal window. On Linux or macOS, enter the following commands: ```bash @@ -329,7 +253,7 @@ $ rustc main.rs If you come from a C or C++ background, you'll notice that this is similar to `gcc` or `clang`. After compiling successfully, Rust should output a binary -executable, which you can see on Linux or OSX by entering the `ls` command in +executable, which you can see on Linux or macOS by entering the `ls` command in your shell as follows: ```bash @@ -494,6 +418,9 @@ $ cargo run Hello, world! ``` +The `run` command comes in handy when you need to rapidly iterate on a +project. + Notice that this example didn’t re-build the project. Cargo figured out that the file hasn’t changed, and so it just ran the binary. If you'd modified your source code, Cargo would have rebuilt the project before running it, and you diff --git a/trpl/glossary.md b/trpl/glossary.md index 8aa7fdf..3895303 100644 --- a/trpl/glossary.md +++ b/trpl/glossary.md @@ -1,4 +1,4 @@ -% Glossary +# Glossary Not every Rustacean has a background in systems programming, nor in computer science, so we've added explanations of terms that might be unfamiliar. @@ -56,7 +56,7 @@ They can be used to manage control flow in a modular fashion. A type without a statically known size or alignment. ([more info][link]) -[link]: ../nomicon/exotic-sizes.html#dynamically-sized-types-dsts +[link]: ../../nomicon/exotic-sizes.html#dynamically-sized-types-dsts ### Expression diff --git a/trpl/guessing-game.md b/trpl/guessing-game.md index 22cf606..d59b392 100644 --- a/trpl/guessing-game.md +++ b/trpl/guessing-game.md @@ -1,4 +1,4 @@ -% Guessing Game +# Guessing Game Let’s learn some Rust! For our first project, we’ll implement a classic beginner programming problem: the guessing game. Here’s how it works: Our @@ -19,6 +19,7 @@ has a command that does that for us. Let’s give it a shot: ```bash $ cd ~/projects $ cargo new guessing_game --bin + Created binary (application) `guessing_game` project $ cd guessing_game ``` @@ -51,25 +52,24 @@ Let’s try compiling what Cargo gave us: ```{bash} $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 0.53 secs ``` Excellent! Open up your `src/main.rs` again. We’ll be writing all of our code in this file. -Before we move on, let me show you one more Cargo command: `run`. `cargo run` -is kind of like `cargo build`, but it also then runs the produced executable. -Try it out: +Remember the `run` command from last chapter? Try it out again here: ```bash $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/guessing_game` Hello, world! ``` -Great! The `run` command comes in handy when you need to rapidly iterate on a -project. Our game is such a project, we need to quickly test each -iteration before moving on to the next one. +Great! Our game is just the kind of project `run` is good for: we need +to quickly test each iteration before moving on to the next one. # Processing a Guess @@ -106,8 +106,8 @@ prelude, you’ll have to `use` it directly. There is also a second ‘prelude [`io` prelude][ioprelude], which serves a similar function: you import it, and it imports a number of useful, `io`-related things. -[prelude]: ../std/prelude/index.html -[ioprelude]: ../std/io/prelude/index.html +[prelude]: ../../std/prelude/index.html +[ioprelude]: ../../std/io/prelude/index.html ```rust,ignore fn main() { @@ -158,8 +158,8 @@ take a name on the left hand side of the assignment, it actually accepts a to use for now: ```rust -let foo = 5; // immutable. -let mut bar = 5; // mutable +let foo = 5; // `foo` is immutable. +let mut bar = 5; // `bar` is mutable. ``` [immutable]: mutability.html @@ -177,7 +177,7 @@ bound to: `String::new()`. `String` is a string type, provided by the standard library. A [`String`][string] is a growable, UTF-8 encoded bit of text. -[string]: ../std/string/struct.String.html +[string]: ../../std/string/struct.String.html The `::new()` syntax uses `::` because this is an ‘associated function’ of a particular type. That is to say, it’s associated with `String` itself, @@ -209,7 +209,7 @@ have written this line as `std::io::stdin()`. This particular function returns a handle to the standard input for your terminal. More specifically, a [std::io::Stdin][iostdin]. -[iostdin]: ../std/io/struct.Stdin.html +[iostdin]: ../../std/io/struct.Stdin.html The next part will use this handle to get input from the user: @@ -217,12 +217,12 @@ The next part will use this handle to get input from the user: .read_line(&mut guess) ``` -Here, we call the [`read_line()`][read_line] method on our handle. +Here, we call the [`read_line`] method on our handle. [Methods][method] are like associated functions, but are only available on a particular instance of a type, rather than the type itself. We’re also passing one argument to `read_line()`: `&mut guess`. -[read_line]: ../std/io/struct.Stdin.html#method.read_line +[`read_line`]: ../../std/io/struct.Stdin.html#method.read_line [method]: method-syntax.html Remember how we bound `guess` above? We said it was mutable. However, @@ -255,7 +255,7 @@ and other whitespace. This helps you split up long lines. We _could_ have done: ```rust,ignore - io::stdin().read_line(&mut guess).expect("failed to read line"); + io::stdin().read_line(&mut guess).expect("Failed to read line"); ``` But that gets hard to read. So we’ve split it up, two lines for two method @@ -266,8 +266,8 @@ String` we pass it. But it also returns a value: in this case, an standard library: a generic [`Result`][result], and then specific versions for sub-libraries, like `io::Result`. -[ioresult]: ../std/io/type.Result.html -[result]: ../std/result/enum.Result.html +[ioresult]: ../../std/io/type.Result.html +[result]: ../../std/result/enum.Result.html The purpose of these `Result` types is to encode error handling information. Values of the `Result` type, like any type, have methods defined on them. In @@ -276,19 +276,22 @@ it’s called on, and if it isn’t a successful one, [`panic!`][panic]s with a message you passed it. A `panic!` like this will cause our program to crash, displaying the message. -[expect]: ../std/result/enum.Result.html#method.expect +[expect]: ../../std/result/enum.Result.html#method.expect [panic]: error-handling.html -If we leave off calling this method, our program will compile, but +If we do not call `expect()`, our program will compile, but we’ll get a warning: ```bash $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) -src/main.rs:10:5: 10:39 warning: unused result which must be used, -#[warn(unused_must_use)] on by default -src/main.rs:10 io::stdin().read_line(&mut guess); - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +warning: unused result which must be used, #[warn(unused_must_use)] on by default + --> src/main.rs:10:5 + | +10 | io::stdin().read_line(&mut guess); + | ^ + + Finished debug [unoptimized + debuginfo] target(s) in 0.42 secs ``` Rust warns us that we haven’t used the `Result` value. This warning comes from @@ -324,6 +327,7 @@ Anyway, that’s the tour. We can run what we have with `cargo run`: ```bash $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 0.44 secs Running `target/debug/guessing_game` Guess the number! Please input your guess. @@ -352,7 +356,7 @@ add these few lines at the bottom: ```toml [dependencies] -rand="0.3.0" +rand = "0.3.0" ``` The `[dependencies]` section of `Cargo.toml` is like the `[package]` section: @@ -363,9 +367,8 @@ which Cargo understands to be any release that’s compatible with this specific Cargo understands [Semantic Versioning][semver], which is a standard for writing version numbers. A bare number like above is actually shorthand for `^0.3.0`, meaning "anything compatible with 0.3.0". -If we wanted to use only `0.3.0` exactly, we could say `rand="=0.3.0"` +If we wanted to use only `0.3.0` exactly, we could say `rand = "=0.3.0"` (note the two equal signs). -And if we wanted to use the latest version we could use `rand="*"`. We could also use a range of versions. [Cargo’s documentation][cargodoc] contains more details. @@ -377,11 +380,12 @@ Now, without changing any of our code, let’s build our project: ```bash $ cargo build Updating registry `https://github.com/rust-lang/crates.io-index` - Downloading rand v0.3.8 - Downloading libc v0.1.6 - Compiling libc v0.1.6 - Compiling rand v0.3.8 + Downloading rand v0.3.14 + Downloading libc v0.2.17 + Compiling libc v0.2.17 + Compiling rand v0.3.14 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 5.88 secs ``` (You may see different versions, of course.) @@ -403,22 +407,24 @@ If we run `cargo build` again, we’ll get different output: ```bash $ cargo build + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs ``` -That’s right, no output! Cargo knows that our project has been built, and that +That’s right, nothing was done! Cargo knows that our project has been built, and that all of its dependencies are built, and so there’s no reason to do all that stuff. With nothing to do, it simply exits. If we open up `src/main.rs` again, -make a trivial change, and then save it again, we’ll only see one line: +make a trivial change, and then save it again, we’ll only see two lines: ```bash $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 0.45 secs ``` So, we told Cargo we wanted any `0.3.x` version of `rand`, and so it fetched the latest -version at the time this was written, `v0.3.8`. But what happens when next -week, version `v0.3.9` comes out, with an important bugfix? While getting -bugfixes is important, what if `0.3.9` contains a regression that breaks our +version at the time this was written, `v0.3.14`. But what happens when next +week, version `v0.3.15` comes out, with an important bugfix? While getting +bugfixes is important, what if `0.3.15` contains a regression that breaks our code? The answer to this problem is the `Cargo.lock` file you’ll now find in your @@ -427,11 +433,11 @@ figures out all of the versions that fit your criteria, and then writes them to the `Cargo.lock` file. When you build your project in the future, Cargo will see that the `Cargo.lock` file exists, and then use that specific version rather than do all the work of figuring out versions again. This lets you -have a repeatable build automatically. In other words, we’ll stay at `0.3.8` +have a repeatable build automatically. In other words, we’ll stay at `0.3.14` until we explicitly upgrade, and so will anyone who we share our code with, thanks to the lock file. -What about when we _do_ want to use `v0.3.9`? Cargo has another command, +What about when we _do_ want to use `v0.3.15`? Cargo has another command, `update`, which says ‘ignore the lock, figure out all the latest versions that fit what we’ve specified. If that works, write those versions out to the lock file’. But, by default, Cargo will only look for versions larger than `0.3.0` @@ -467,7 +473,7 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .expect("failed to read line"); + .expect("Failed to read line"); println!("You guessed: {}", guess); } @@ -514,6 +520,7 @@ Try running our new program a few times: ```bash $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 0.55 secs Running `target/debug/guessing_game` Guess the number! The secret number is: 7 @@ -521,6 +528,7 @@ Please input your guess. 4 You guessed: 4 $ cargo run + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/guessing_game` Guess the number! The secret number is: 83 @@ -555,7 +563,7 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .expect("failed to read line"); + .expect("Failed to read line"); println!("You guessed: {}", guess); @@ -612,7 +620,7 @@ match guess.cmp(&secret_number) { } ``` -[ordering]: ../std/cmp/enum.Ordering.html +[ordering]: ../../std/cmp/enum.Ordering.html If it’s `Less`, we print `Too small!`, if it’s `Greater`, `Too big!`, and if `Equal`, `You win!`. `match` is really useful, and is used often in Rust. @@ -622,15 +630,20 @@ I did mention that this won’t quite compile yet, though. Let’s try it: ```bash $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) -src/main.rs:28:21: 28:35 error: mismatched types: - expected `&collections::string::String`, - found `&_` -(expected struct `collections::string::String`, - found integral variable) [E0308] -src/main.rs:28 match guess.cmp(&secret_number) { - ^~~~~~~~~~~~~~ +error[E0308]: mismatched types + --> src/main.rs:23:21 + | +23 | match guess.cmp(&secret_number) { + | ^^^^^^^^^^^^^^ expected struct `std::string::String`, found integral variable + | + = note: expected type `&std::string::String` + = note: found type `&{integer}` + error: aborting due to previous error -Could not compile `guessing_game`. + +error: Could not compile `guessing_game`. + +To learn more, run the command again with --verbose. ``` Whew! This is a big error. The core of it is that we have ‘mismatched types’. @@ -665,7 +678,7 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .expect("failed to read line"); + .expect("Failed to read line"); let guess: u32 = guess.trim().parse() .expect("Please type a number!"); @@ -713,7 +726,7 @@ exact type of number we want. Hence, `let guess: u32`. The colon (`:`) after thirty-two bit integer. Rust has [a number of built-in number types][number], but we’ve chosen `u32`. It’s a good default choice for a small positive number. -[parse]: ../std/primitive.str.html#method.parse +[parse]: ../../std/primitive.str.html#method.parse [number]: primitive-types.html#numeric-types Just like `read_line()`, our call to `parse()` could cause an error. What if @@ -726,6 +739,7 @@ Let’s try our program out! ```bash $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 0.57 secs Running `target/guessing_game` Guess the number! The secret number is: 58 @@ -766,7 +780,7 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .expect("failed to read line"); + .expect("Failed to read line"); let guess: u32 = guess.trim().parse() .expect("Please type a number!"); @@ -789,6 +803,7 @@ and quit. Observe: ```bash $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 0.58 secs Running `target/guessing_game` Guess the number! The secret number is: 59 @@ -832,7 +847,7 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .expect("failed to read line"); + .expect("Failed to read line"); let guess: u32 = guess.trim().parse() .expect("Please type a number!"); @@ -877,7 +892,7 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .expect("failed to read line"); + .expect("Failed to read line"); let guess: u32 = match guess.trim().parse() { Ok(num) => num, @@ -923,6 +938,7 @@ Now we should be good! Let’s try: ```bash $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 0.57 secs Running `target/guessing_game` Guess the number! The secret number is: 61 @@ -965,7 +981,7 @@ fn main() { let mut guess = String::new(); io::stdin().read_line(&mut guess) - .expect("failed to read line"); + .expect("Failed to read line"); let guess: u32 = match guess.trim().parse() { Ok(num) => num, diff --git a/trpl/if-let.md b/trpl/if-let.md index 9afe5fa..9eeac3d 100644 --- a/trpl/if-let.md +++ b/trpl/if-let.md @@ -1,7 +1,8 @@ -% if let +# if let -`if let` allows you to combine `if` and `let` together to reduce the overhead -of certain kinds of pattern matches. +`if let` permits [patterns][patterns] matching within the condition of an [if][if] statement. +This allows us to reduce the overhead of certain kinds of [pattern][patterns] matches +and express them in a more convenient way. For example, let’s say we have some sort of `Option`. We want to call a function on it if it’s `Some`, but do nothing if it’s `None`. That looks like this: @@ -80,3 +81,4 @@ while let Some(x) = v.pop() { ``` [patterns]: patterns.html +[if]: if.html diff --git a/trpl/if.md b/trpl/if.md index 52d0dd8..d745037 100644 --- a/trpl/if.md +++ b/trpl/if.md @@ -1,4 +1,4 @@ -% if +# if Rust’s take on `if` is not particularly complex, but it’s much more like the `if` you’ll find in a dynamically typed language than in a more traditional diff --git a/trpl/iterators.md b/trpl/iterators.md index c174d2d..548816a 100644 --- a/trpl/iterators.md +++ b/trpl/iterators.md @@ -1,4 +1,4 @@ -% Iterators +# Iterators Let's talk about loops. @@ -14,10 +14,9 @@ Now that you know more Rust, we can talk in detail about how this works. Ranges (the `0..10`) are 'iterators'. An iterator is something that we can call the `.next()` method on repeatedly, and it gives us a sequence of things. -(By the way, a range with two dots like `0..10` is inclusive on the left (so it +A range with two dots like `0..10` is inclusive on the left (so it starts at 0) and exclusive on the right (so it ends at 9). A mathematician -would write "[0, 10)". To get a range that goes all the way up to 10 you can -write `0...10`.) +would write "[0, 10)". Like this: @@ -135,10 +134,10 @@ Here's the version that does compile: let one_to_one_hundred = (1..101).collect::>(); ``` -If you remember, the `::<>` syntax allows us to give a type hint, -and so we tell it that we want a vector of integers. You don't always -need to use the whole type, though. Using a `_` will let you provide -a partial hint: +If you remember, the [`::<>` syntax](generics.html#resolving-ambiguities) +allows us to give a type hint that tells the compiler we want a vector of +integers. You don't always need to use the whole type, though. Using a `_` +will let you provide a partial hint: ```rust let one_to_one_hundred = (1..101).collect::>(); @@ -341,4 +340,4 @@ can help you with. There are a number of really useful iterators, and you can write your own as well. Iterators provide a safe, efficient way to manipulate all kinds of lists. They're a little unusual at first, but if you play with them, you'll get hooked. For a full list of the different iterators and -consumers, check out the [iterator module documentation](../std/iter/index.html). +consumers, check out the [iterator module documentation](../../std/iter/index.html). diff --git a/trpl/lifetimes.md b/trpl/lifetimes.md index f7d9c94..042d9af 100644 --- a/trpl/lifetimes.md +++ b/trpl/lifetimes.md @@ -1,4 +1,4 @@ -% Lifetimes +# Lifetimes This is the last of three sections presenting Rust’s ownership system. This is one of Rust’s most distinct and compelling features, with which Rust developers should @@ -50,29 +50,94 @@ complicated. For example, imagine this set of operations: 4. You decide to use the resource. Uh oh! Your reference is pointing to an invalid resource. This is called a -dangling pointer or ‘use after free’, when the resource is memory. +dangling pointer or ‘use after free’, when the resource is memory. A small +example of such a situation would be: + +```rust,compile_fail +let r; // Introduce reference: `r`. +{ + let i = 1; // Introduce scoped value: `i`. + r = &i; // Store reference of `i` in `r`. +} // `i` goes out of scope and is dropped. + +println!("{}", r); // `r` still refers to `i`. +``` To fix this, we have to make sure that step four never happens after step -three. The ownership system in Rust does this through a concept called -lifetimes, which describe the scope that a reference is valid for. +three. In the small example above the Rust compiler is able to report the issue +as it can see the lifetimes of the various values in the function. -When we have a function that takes an argument by reference, we can be -implicit or explicit about the lifetime of the reference: +When we have a function that takes arguments by reference the situation becomes +more complex. Consider the following example: -```rust -// implicit -fn foo(x: &i32) { +```rust,compile_fail,E0106 +fn skip_prefix(line: &str, prefix: &str) -> &str { + // ... +# line } -// explicit -fn bar<'a>(x: &'a i32) { +let line = "lang:en=Hello World!"; +let lang = "en"; + +let v; +{ + let p = format!("lang:{}=", lang); // -+ `p` comes into scope. + v = skip_prefix(line, p.as_str()); // | +} // -+ `p` goes out of scope. +println!("{}", v); +``` + +Here we have a function `skip_prefix` which takes two `&str` references +as parameters and returns a single `&str` reference. We call it +by passing in references to `line` and `p`: Two variables with different +lifetimes. Now the safety of the `println!`-line depends on whether the +reference returned by `skip_prefix` function references the still living +`line` or the already dropped `p` string. + +Because of the above ambiguity, Rust will refuse to compile the example +code. To get it to compile we need to tell the compiler more about the +lifetimes of the references. This can be done by making the lifetimes +explicit in the function declaration: + +```rust +fn skip_prefix<'a, 'b>(line: &'a str, prefix: &'b str) -> &'a str { + // ... +# line } ``` +Let's examine the changes without going too deep into the syntax for now - +we'll get to that later. The first change was adding the `<'a, 'b>` after the +method name. This introduces two lifetime parameters: `'a` and `'b`. Next, each +reference in the function signature was associated with one of the lifetime +parameters by adding the lifetime name after the `&`. This tells the compiler +how the lifetimes between different references are related. + +As a result the compiler is now able to deduce that the return value of +`skip_prefix` has the same lifetime as the `line` parameter, which makes the `v` +reference safe to use even after the `p` goes out of scope in the original +example. + +In addition to the compiler being able to validate the usage of `skip_prefix` +return value, it can also ensure that the implementation follows the contract +established by the function declaration. This is useful especially when you are +implementing traits that are introduced [later in the book][traits]. + +**Note** It's important to understand that lifetime annotations are +_descriptive_, not _prescriptive_. This means that how long a reference is valid +is determined by the code, not by the annotations. The annotations, however, +give information about lifetimes to the compiler that uses them to check the +validity of references. The compiler can do so without annotations in simple +cases, but needs the programmer's support in complex scenarios. + +[traits]: traits.html + +# Syntax + The `'a` reads ‘the lifetime a’. Technically, every reference has some lifetime associated with it, but the compiler lets you elide (i.e. omit, see -["Lifetime Elision"][lifetime-elision] below) them in common cases. -Before we get to that, though, let’s break the explicit example down: +["Lifetime Elision"][lifetime-elision] below) them in common cases. Before we +get to that, though, let’s look at a short example with explicit lifetimes: [lifetime-elision]: #lifetime-elision @@ -90,7 +155,8 @@ focus on the lifetimes aspect. [generics]: generics.html We use `<>` to declare our lifetimes. This says that `bar` has one lifetime, -`'a`. If we had two reference parameters, it would look like this: +`'a`. If we had two reference parameters with different lifetimes, it would +look like this: ```rust,ignore @@ -125,7 +191,7 @@ struct Foo<'a> { } fn main() { - let y = &5; // this is the same as `let _y = 5; let y = &_y;` + let y = &5; // This is the same as `let _y = 5; let y = &_y;`. let f = Foo { x: y }; println!("{}", f.x); @@ -167,7 +233,7 @@ impl<'a> Foo<'a> { } fn main() { - let y = &5; // this is the same as `let _y = 5; let y = &_y;` + let y = &5; // This is the same as `let _y = 5; let y = &_y;`. let f = Foo { x: y }; println!("x is: {}", f.x()); @@ -208,11 +274,11 @@ valid for. For example: ```rust fn main() { - let y = &5; // -+ y goes into scope + let y = &5; // -+ `y` comes into scope. // | - // stuff // | + // Stuff... // | // | -} // -+ y goes out of scope +} // -+ `y` goes out of scope. ``` Adding in our `Foo`: @@ -223,11 +289,12 @@ struct Foo<'a> { } fn main() { - let y = &5; // -+ y goes into scope - let f = Foo { x: y }; // -+ f goes into scope - // stuff // | + let y = &5; // -+ `y` comes into scope. + let f = Foo { x: y }; // -+ `f` comes into scope. + // | + // Stuff... // | // | -} // -+ f and y go out of scope +} // -+ `f` and `y` go out of scope. ``` Our `f` lives within the scope of `y`, so everything works. What if it didn’t? @@ -239,16 +306,16 @@ struct Foo<'a> { } fn main() { - let x; // -+ x goes into scope + let x; // -+ `x` comes into scope. // | { // | - let y = &5; // ---+ y goes into scope - let f = Foo { x: y }; // ---+ f goes into scope - x = &f.x; // | | error here - } // ---+ f and y go out of scope + let y = &5; // ---+ `y` comes into scope. + let f = Foo { x: y }; // ---+ `f` comes into scope. + x = &f.x; // | | This causes an error. + } // ---+ `f` and y go out of scope. // | println!("{}", x); // | -} // -+ x goes out of scope +} // -+ `x` goes out of scope. ``` Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope @@ -282,10 +349,10 @@ to it. ## Lifetime Elision -Rust supports powerful local type inference in the bodies of functions but not in their item signatures. -It's forbidden to allow reasoning about types based on the item signature alone. +Rust supports powerful local type inference in the bodies of functions, but it +deliberately does not perform any reasoning about types for item signatures. However, for ergonomic reasons, a very restricted secondary inference algorithm called -“lifetime elision” does apply when judging lifetimes. Lifetime elision is concerned solely to infer +“lifetime elision” does apply when judging lifetimes. Lifetime elision is concerned solely with inferring lifetime parameters using three easily memorizable and unambiguous rules. This means lifetime elision acts as a shorthand for writing an item signature, while not hiding away the actual types involved as full local inference would if applied to it. diff --git a/trpl/loops.md b/trpl/loops.md index e4cb861..20e6eee 100644 --- a/trpl/loops.md +++ b/trpl/loops.md @@ -1,4 +1,4 @@ -% Loops +# Loops Rust currently provides three approaches to performing some kind of iterative activity. They are: `loop`, `while` and `for`. Each approach has its own set of uses. @@ -81,14 +81,14 @@ for var in expression { ``` The expression is an item that can be converted into an [iterator] using -[`IntoIterator`]. The iterator gives back a series of elements. Each element is -one iteration of the loop. That value is then bound to the name `var`, which is +[`IntoIterator`]. The iterator gives back a series of elements, one element per +iteration of the loop. That value is then bound to the name `var`, which is valid for the loop body. Once the body is over, the next value is fetched from the iterator, and we loop another time. When there are no more values, the `for` loop is over. [iterator]: iterators.html -[`IntoIterator`]: ../std/iter/trait.IntoIterator.html +[`IntoIterator`]: ../../std/iter/trait.IntoIterator.html In our example, `0..10` is an expression that takes a start and an end position, and gives an iterator over those values. The upper bound is exclusive, though, @@ -100,7 +100,8 @@ developers. ### Enumerate -When you need to keep track of how many times you already looped, you can use the `.enumerate()` function. +When you need to keep track of how many times you have already looped, you can +use the `.enumerate()` function. #### On ranges: @@ -193,17 +194,21 @@ for x in 0..10 { You may also encounter situations where you have nested loops and need to specify which one your `break` or `continue` statement is for. Like most -other languages, by default a `break` or `continue` will apply to innermost -loop. In a situation where you would like to `break` or `continue` for one +other languages, Rust's `break` or `continue` apply to the innermost loop. +In a situation where you would like to `break` or `continue` for one of the outer loops, you can use labels to specify which loop the `break` or - `continue` statement applies to. This will only print when both `x` and `y` are - odd: +`continue` statement applies to. + +In the example below, we `continue` to the next iteration of `outer` loop +when `x` is even, while we `continue` to the next iteration of `inner` +loop when y is even. So it will execute the `println!` when both `x` and +`y` are odd. ```rust 'outer: for x in 0..10 { 'inner: for y in 0..10 { - if x % 2 == 0 { continue 'outer; } // continues the loop over x - if y % 2 == 0 { continue 'inner; } // continues the loop over y + if x % 2 == 0 { continue 'outer; } // Continues the loop over `x`. + if y % 2 == 0 { continue 'inner; } // Continues the loop over `y`. println!("x: {}, y: {}", x, y); } } diff --git a/trpl/macros.md b/trpl/macros.md index 9f40829..c2b9960 100644 --- a/trpl/macros.md +++ b/trpl/macros.md @@ -1,4 +1,4 @@ -% Macros +# Macros By now you’ve learned about many of the tools Rust provides for abstracting and reusing code. These units of code reuse have a rich semantic structure. For @@ -58,6 +58,7 @@ We can implement this shorthand, using a macro: [^actual] [^actual]: The actual definition of `vec!` in libcollections differs from the one presented here, for reasons of efficiency and reusability. + ```rust macro_rules! vec { @@ -101,7 +102,7 @@ trees, at compile time. The semicolon is optional on the last (here, only) case. The "pattern" on the left-hand side of `=>` is known as a ‘matcher’. These have [their own little grammar] within the language. -[their own little grammar]: ../reference.html#macros +[their own little grammar]: ../../reference/macros.html The matcher `$x:expr` will match any Rust expression, binding that syntax tree to the ‘metavariable’ `$x`. The identifier `expr` is a ‘fragment specifier’; @@ -261,36 +262,34 @@ The metavariable `$x` is parsed as a single expression node, and keeps its place in the syntax tree even after substitution. Another common problem in macro systems is ‘variable capture’. Here’s a C -macro, using [a GNU C extension] to emulate Rust’s expression blocks. - -[a GNU C extension]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html +macro using a block with multiple statements. ```text -#define LOG(msg) ({ \ +#define LOG(msg) do { \ int state = get_log_state(); \ if (state > 0) { \ printf("log(%d): %s\n", state, msg); \ } \ -}) +} while (0) ``` Here’s a simple use case that goes terribly wrong: ```text const char *state = "reticulating splines"; -LOG(state) +LOG(state); ``` This expands to ```text const char *state = "reticulating splines"; -{ +do { int state = get_log_state(); if (state > 0) { printf("log(%d): %s\n", state, state); } -} +} while (0); ``` The second variable named `state` shadows the first one. This is a problem @@ -365,7 +364,7 @@ fn main() { } ``` -[items]: ../reference.html#items +[items]: ../../reference/items.html # Recursive macros @@ -492,7 +491,7 @@ be forced to choose between parsing `$i` and parsing `$e`. Changing the invocation syntax to put a distinctive token in front can solve the problem. In this case, you can write `$(I $i:ident)* E $e:expr`. -[item]: ../reference.html#items +[item]: ../../reference/items.html # Scoping and macro import/export @@ -533,33 +532,33 @@ An example: ```rust macro_rules! m1 { () => (()) } -// visible here: m1 +// Visible here: `m1`. mod foo { - // visible here: m1 + // Visible here: `m1`. #[macro_export] macro_rules! m2 { () => (()) } - // visible here: m1, m2 + // Visible here: `m1`, `m2`. } -// visible here: m1 +// Visible here: `m1`. macro_rules! m3 { () => (()) } -// visible here: m1, m3 +// Visible here: `m1`, `m3`. #[macro_use] mod bar { - // visible here: m1, m3 + // Visible here: `m1`, `m3`. macro_rules! m4 { () => (()) } - // visible here: m1, m3, m4 + // Visible here: `m1`, `m3`, `m4`. } -// visible here: m1, m3, m4 +// Visible here: `m1`, `m3`, `m4`. # fn main() { } ``` @@ -567,7 +566,7 @@ When this library is loaded with `#[macro_use] extern crate`, only `m2` will be imported. The Rust Reference has a [listing of macro-related -attributes](../reference.html#macro-related-attributes). +attributes](../../reference/attributes.html#macro-related-attributes). # The variable `$crate` @@ -644,7 +643,7 @@ macro_rules! bct { (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) => (bct!($($ps),*, 1, $p ; $($ds),*)); - // halt on empty data string + // Halt on empty data string: ( $($ps:tt),* ; ) => (()); } @@ -662,7 +661,7 @@ Here are some common macros you’ll see in Rust code. This macro causes the current thread to panic. You can give it a message to panic with: -```rust,no_run +```rust,should_panic panic!("oh no!"); ``` @@ -688,13 +687,13 @@ These two macros are used in tests. `assert!` takes a boolean. `assert_eq!` takes two values and checks them for equality. `true` passes, `false` `panic!`s. Like this: -```rust,no_run +```rust,should_panic // A-ok! assert!(true); assert_eq!(5, 3 + 2); -// nope :( +// Nope :( assert!(5 < 3); assert_eq!(5, 3); @@ -763,12 +762,3 @@ to typecheck, and don’t want to worry about writing out the body of the function. One example of this situation is implementing a trait with multiple required methods, where you want to tackle one at a time. Define the others as `unimplemented!` until you’re ready to write them. - -# Procedural macros - -If Rust’s macro system can’t do what you need, you may want to write a -[compiler plugin](compiler-plugins.html) instead. Compared to `macro_rules!` -macros, this is significantly more work, the interfaces are much less stable, -and bugs can be much harder to track down. In exchange you get the -flexibility of running arbitrary Rust code within the compiler. Syntax -extension plugins are sometimes called ‘procedural macros’ for this reason. diff --git a/trpl/match.md b/trpl/match.md index d01a200..b1e26a9 100644 --- a/trpl/match.md +++ b/trpl/match.md @@ -1,4 +1,4 @@ -% Match +# Match Often, a simple [`if`][if]/`else` isn’t enough, because you have more than two possible options. Also, conditions can get quite complex. Rust @@ -82,7 +82,7 @@ fn process_message(msg: Message) { match msg { Message::Quit => quit(), Message::ChangeColor(r, g, b) => change_color(r, g, b), - Message::Move { x: x, y: y } => move_cursor(x, y), + Message::Move { x, y: new_name_for_y } => move_cursor(x, new_name_for_y), Message::Write(s) => println!("{}", s), }; } diff --git a/trpl/method-syntax.md b/trpl/method-syntax.md index b253266..0404a5c 100644 --- a/trpl/method-syntax.md +++ b/trpl/method-syntax.md @@ -1,4 +1,4 @@ -% Method Syntax +# Method Syntax Functions are great, but if you want to call a bunch of them on some data, it can be awkward. Consider this code: diff --git a/trpl/mutability.md b/trpl/mutability.md index a0a49d5..7625e06 100644 --- a/trpl/mutability.md +++ b/trpl/mutability.md @@ -1,4 +1,4 @@ -% Mutability +# Mutability Mutability, the ability to change something, works a bit differently in Rust than in other languages. The first aspect of mutability is its non-default @@ -6,7 +6,7 @@ status: ```rust,ignore let x = 5; -x = 6; // error! +x = 6; // Error! ``` We can introduce mutability with the `mut` keyword: @@ -14,7 +14,7 @@ We can introduce mutability with the `mut` keyword: ```rust let mut x = 5; -x = 6; // no problem! +x = 6; // No problem! ``` This is a mutable [variable binding][vb]. When a binding is mutable, it means @@ -72,7 +72,7 @@ let x = Arc::new(5); let y = x.clone(); ``` -[arc]: ../std/sync/struct.Arc.html +[arc]: ../../std/sync/struct.Arc.html When we call `clone()`, the `Arc` needs to update the reference count. Yet we’ve not used any `mut`s here, `x` is an immutable binding, and we didn’t take @@ -107,7 +107,7 @@ let x = RefCell::new(42); let y = x.borrow_mut(); ``` -[stdcell]: ../std/cell/index.html +[stdcell]: ../../std/cell/index.html RefCell hands out `&mut` references to what’s inside of it with the `borrow_mut()` method. Isn’t that dangerous? What if we do: @@ -136,7 +136,7 @@ some fields mutable and some immutable: ```rust,ignore struct Point { x: i32, - mut y: i32, // nope + mut y: i32, // Nope. } ``` @@ -152,9 +152,9 @@ let mut a = Point { x: 5, y: 6 }; a.x = 10; -let b = Point { x: 5, y: 6}; +let b = Point { x: 5, y: 6 }; -b.x = 10; // error: cannot assign to immutable field `b.x` +b.x = 10; // Error: cannot assign to immutable field `b.x`. ``` [struct]: structs.html @@ -176,6 +176,6 @@ point.y.set(7); println!("y: {:?}", point.y); ``` -[cell]: ../std/cell/struct.Cell.html +[cell]: ../../std/cell/struct.Cell.html This will print `y: Cell { value: 7 }`. We’ve successfully updated `y`. diff --git a/trpl/operators-and-overloading.md b/trpl/operators-and-overloading.md index 424e2cd..ed202f3 100644 --- a/trpl/operators-and-overloading.md +++ b/trpl/operators-and-overloading.md @@ -1,4 +1,4 @@ -% Operators and Overloading +# Operators and Overloading Rust allows for a limited form of operator overloading. There are certain operators that are able to be overloaded. To support a particular operator @@ -41,7 +41,7 @@ There are a number of operators that can be overloaded this way, and all of their associated traits live in the [`std::ops`][stdops] module. Check out its documentation for the full list. -[stdops]: ../std/ops/index.html +[stdops]: ../../std/ops/index.html Implementing these traits follows a pattern. Let’s look at [`Add`][add] in more detail: @@ -56,7 +56,7 @@ pub trait Add { # } ``` -[add]: ../std/ops/trait.Add.html +[add]: ../../std/ops/trait.Add.html There’s three types in total involved here: the type you `impl Add` for, `RHS`, which defaults to `Self`, and `Output`. For an expression `let z = x + y`, `x` @@ -69,7 +69,7 @@ impl Add for Point { type Output = f64; fn add(self, rhs: i32) -> f64 { - // add an i32 to a Point and get an f64 + // Add an i32 to a Point and get an f64. # 1.0 } } diff --git a/trpl/ownership.md b/trpl/ownership.md index 23ca21b..21ebd63 100644 --- a/trpl/ownership.md +++ b/trpl/ownership.md @@ -1,4 +1,4 @@ -% Ownership +# Ownership This is the first of three sections presenting Rust’s ownership system. This is one of Rust’s most distinct and compelling features, with which Rust developers should @@ -57,13 +57,13 @@ of scope at the end of `foo()`, Rust will clean up everything related to the vector, even the heap-allocated memory. This happens deterministically, at the end of the scope. -We'll cover [vectors] in detail later in this chapter; we only use them +We covered [vectors] in the previous chapter; we use them here as an example of a type that allocates space on the heap at runtime. They behave like [arrays], except their size may change by `push()`ing more elements onto them. Vectors have a [generic type][generics] `Vec`, so in this example `v` will have type -`Vec`. We'll cover generics in detail later in this chapter. +`Vec`. We'll cover [generics] in detail in a later chapter. [arrays]: primitive-types.html#arrays [vectors]: vectors.html @@ -107,7 +107,7 @@ try to use something after we’ve passed it as an argument: ```rust,ignore fn take(v: Vec) { - // what happens here isn’t important. + // What happens here isn’t important. } let v = vec![1, 2, 3]; @@ -264,9 +264,9 @@ Of course, if we had to hand ownership back with every function we wrote: ```rust fn foo(v: Vec) -> Vec { - // do stuff with v + // Do stuff with `v`. - // hand back ownership + // Hand back ownership. v } ``` @@ -275,9 +275,9 @@ This would get very tedious. It gets worse the more things we want to take owner ```rust fn foo(v1: Vec, v2: Vec) -> (Vec, Vec, i32) { - // do stuff with v1 and v2 + // Do stuff with `v1` and `v2`. - // hand back ownership, and the result of our function + // Hand back ownership, and the result of our function. (v1, v2, 42) } diff --git a/trpl/patterns.md b/trpl/patterns.md index 910b137..1983927 100644 --- a/trpl/patterns.md +++ b/trpl/patterns.md @@ -1,4 +1,4 @@ -% Patterns +# Patterns Patterns are quite common in Rust. We use them in [variable bindings][bindings], [match expressions][match], and other places, too. Let’s go @@ -23,6 +23,33 @@ match x { This prints `one`. +It's possible to create a binding for the value in the any case: + +```rust +let x = 1; + +match x { + y => println!("x: {} y: {}", x, y), +} +``` + +This prints: + +```text +x: 1 y: 1 +``` + +Note it is an error to have both a catch-all `_` and a catch-all binding in the same match block: + +```rust +let x = 1; + +match x { + y => println!("x: {} y: {}", x, y), + _ => println!("anything"), // this causes an error as it is unreachable +} +``` + There’s one pitfall with patterns: like anything that introduces a new binding, they introduce shadowing. For example: @@ -163,7 +190,7 @@ ignore parts of a larger structure: ```rust fn coordinate() -> (i32, i32, i32) { - // generate and return some sort of triple tuple + // Generate and return some sort of triple tuple. # (1, 2, 3) } @@ -182,7 +209,7 @@ let tuple: (u32, String) = (5, String::from("five")); // Here, tuple is moved, because the String moved: let (x, _s) = tuple; -// The next line would give "error: use of partially moved value: `tuple`" +// The next line would give "error: use of partially moved value: `tuple`". // println!("Tuple is: {:?}", tuple); // However, diff --git a/trpl/primitive-types.md b/trpl/primitive-types.md index ea0bdf2..93220a2 100644 --- a/trpl/primitive-types.md +++ b/trpl/primitive-types.md @@ -1,4 +1,4 @@ -% Primitive Types +# Primitive Types The Rust language has a number of types that are considered ‘primitive’. This means that they’re built-in to the language. Rust is structured in such a way @@ -22,7 +22,7 @@ A common use of booleans is in [`if` conditionals][if]. You can find more documentation for `bool`s [in the standard library documentation][bool]. -[bool]: ../std/primitive.bool.html +[bool]: ../../std/primitive.bool.html # `char` @@ -40,7 +40,7 @@ but four. You can find more documentation for `char`s [in the standard library documentation][char]. -[char]: ../std/primitive.char.html +[char]: ../../std/primitive.char.html # Numeric types @@ -54,26 +54,26 @@ bigger numbers. If a number literal has nothing to cause its type to be inferred, it defaults: ```rust -let x = 42; // x has type i32 +let x = 42; // `x` has type `i32`. -let y = 1.0; // y has type f64 +let y = 1.0; // `y` has type `f64`. ``` Here’s a list of the different numeric types, with links to their documentation in the standard library: -* [i8](../std/primitive.i8.html) -* [i16](../std/primitive.i16.html) -* [i32](../std/primitive.i32.html) -* [i64](../std/primitive.i64.html) -* [u8](../std/primitive.u8.html) -* [u16](../std/primitive.u16.html) -* [u32](../std/primitive.u32.html) -* [u64](../std/primitive.u64.html) -* [isize](../std/primitive.isize.html) -* [usize](../std/primitive.usize.html) -* [f32](../std/primitive.f32.html) -* [f64](../std/primitive.f64.html) +* [i8](../../std/primitive.i8.html) +* [i16](../../std/primitive.i16.html) +* [i32](../../std/primitive.i32.html) +* [i64](../../std/primitive.i64.html) +* [u8](../../std/primitive.u8.html) +* [u16](../../std/primitive.u16.html) +* [u32](../../std/primitive.u32.html) +* [u64](../../std/primitive.u64.html) +* [isize](../../std/primitive.isize.html) +* [usize](../../std/primitive.usize.html) +* [f32](../../std/primitive.f32.html) +* [f64](../../std/primitive.f64.html) Let’s go over them by category: @@ -155,7 +155,7 @@ languages. You can find more documentation for `array`s [in the standard library documentation][array]. -[array]: ../std/primitive.array.html +[array]: ../../std/primitive.array.html # Slices @@ -177,8 +177,8 @@ length of the slice: ```rust let a = [0, 1, 2, 3, 4]; -let complete = &a[..]; // A slice containing all of the elements in a -let middle = &a[1..4]; // A slice of a: only the elements 1, 2, and 3 +let complete = &a[..]; // A slice containing all of the elements in `a`. +let middle = &a[1..4]; // A slice of `a`: only the elements `1`, `2`, and `3`. ``` Slices have type `&[T]`. We’ll talk about that `T` when we cover @@ -189,7 +189,7 @@ Slices have type `&[T]`. We’ll talk about that `T` when we cover You can find more documentation for slices [in the standard library documentation][slice]. -[slice]: ../std/primitive.slice.html +[slice]: ../../std/primitive.slice.html # `str` @@ -205,7 +205,7 @@ reference, like `&str`. We'll elaborate further when we cover You can find more documentation for `str` [in the standard library documentation][str]. -[str]: ../std/primitive.str.html +[str]: ../../std/primitive.str.html # Tuples @@ -264,8 +264,8 @@ You can disambiguate a single-element tuple from a value in parentheses with a comma: ```rust -(0,); // single-element tuple -(0); // zero in parentheses +(0,); // A single-element tuple. +(0); // A zero in parentheses. ``` ## Tuple Indexing @@ -289,7 +289,7 @@ Like array indexing, it starts at zero, but unlike array indexing, it uses a You can find more documentation for tuples [in the standard library documentation][tuple]. -[tuple]: ../std/primitive.tuple.html +[tuple]: ../../std/primitive.tuple.html # Functions diff --git a/trpl/procedural-macros.md b/trpl/procedural-macros.md new file mode 100644 index 0000000..c290279 --- /dev/null +++ b/trpl/procedural-macros.md @@ -0,0 +1,286 @@ +# Procedural Macros (and custom Derive) + +As you've seen throughout the rest of the book, Rust provides a mechanism +called "derive" that lets you implement traits easily. For example, + +```rust +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} +``` + +is a lot simpler than + +```rust +struct Point { + x: i32, + y: i32, +} + +use std::fmt; + +impl fmt::Debug for Point { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Point {{ x: {}, y: {} }}", self.x, self.y) + } +} +``` + +Rust includes several traits that you can derive, but it also lets you define +your own. We can accomplish this task through a feature of Rust called +"procedural macros." Eventually, procedural macros will allow for all sorts of +advanced metaprogramming in Rust, but today, they're only for custom derive. + +Let's build a very simple trait, and derive it with custom derive. + +## Hello World + +So the first thing we need to do is start a new crate for our project. + +```bash +$ cargo new --bin hello-world +``` + +All we want is to be able to call `hello_world()` on a derived type. Something +like this: + +```rust,ignore +#[derive(HelloWorld)] +struct Pancakes; + +fn main() { + Pancakes::hello_world(); +} +``` + +With some kind of nice output, like `Hello, World! My name is Pancakes.`. + +Let's go ahead and write up what we think our macro will look like from a user +perspective. In `src/main.rs` we write: + +```rust,ignore +#[macro_use] +extern crate hello_world_derive; + +trait HelloWorld { + fn hello_world(); +} + +#[derive(HelloWorld)] +struct FrenchToast; + +#[derive(HelloWorld)] +struct Waffles; + +fn main() { + FrenchToast::hello_world(); + Waffles::hello_world(); +} +``` + +Great. So now we just need to actually write the procedural macro. At the +moment, procedural macros need to be in their own crate. Eventually, this +restriction may be lifted, but for now, it's required. As such, there's a +convention; for a crate named `foo`, a custom derive procedural macro is called +`foo-derive`. Let's start a new crate called `hello-world-derive` inside our +`hello-world` project. + +```bash +$ cargo new hello-world-derive +``` + +To make sure that our `hello-world` crate is able to find this new crate we've +created, we'll add it to our toml: + +```toml +[dependencies] +hello-world-derive = { path = "hello-world-derive" } +``` + +As for the source of our `hello-world-derive` crate, here's an example: + +```rust,ignore +extern crate proc_macro; +extern crate syn; +#[macro_use] +extern crate quote; + +use proc_macro::TokenStream; + +#[proc_macro_derive(HelloWorld)] +pub fn hello_world(input: TokenStream) -> TokenStream { + // Construct a string representation of the type definition + let s = input.to_string(); + + // Parse the string representation + let ast = syn::parse_derive_input(&s).unwrap(); + + // Build the impl + let gen = impl_hello_world(&ast); + + // Return the generated impl + gen.parse().unwrap() +} +``` + +So there is a lot going on here. We have introduced two new crates: [`syn`] and +[`quote`]. As you may have noticed, `input: TokenSteam` is immediately converted +to a `String`. This `String` is a string representation of the Rust code for which +we are deriving `HelloWorld`. At the moment, the only thing you can do with a +`TokenStream` is convert it to a string. A richer API will exist in the future. + +So what we really need is to be able to _parse_ Rust code into something +usable. This is where `syn` comes to play. `syn` is a crate for parsing Rust +code. The other crate we've introduced is `quote`. It's essentially the dual of +`syn` as it will make generating Rust code really easy. We could write this +stuff on our own, but it's much simpler to use these libraries. Writing a full +parser for Rust code is no simple task. + +[`syn`]: https://crates.io/crates/syn +[`quote`]: https://crates.io/crates/quote + +The comments seem to give us a pretty good idea of our overall strategy. We +are going to take a `String` of the Rust code for the type we are deriving, parse +it using `syn`, construct the implementation of `hello_world` (using `quote`), +then pass it back to Rust compiler. + +One last note: you'll see some `unwrap()`s there. If you want to provide an +error for a procedural macro, then you should `panic!` with the error message. +In this case, we're keeping it as simple as possible. + +Great, so let's write `impl_hello_world(&ast)`. + +```rust,ignore +fn impl_hello_world(ast: &syn::MacroInput) -> quote::Tokens { + let name = &ast.ident; + quote! { + impl HelloWorld for #name { + fn hello_world() { + println!("Hello, World! My name is {}", stringify!(#name)); + } + } + } +} +``` + +So this is where quotes comes in. The `ast` argument is a struct that gives us +a representation of our type (which can be either a `struct` or an `enum`). +Check out the [docs](https://docs.rs/syn/0.10.5/syn/struct.MacroInput.html), +there is some useful information there. We are able to get the name of the +type using `ast.ident`. The `quote!` macro lets us write up the Rust code +that we wish to return and convert it into `Tokens`. `quote!` lets us use some +really cool templating mechanics; we simply write `#name` and `quote!` will +replace it with the variable named `name`. You can even do some repetition +similar to regular macros work. You should check out the +[docs](https://docs.rs/quote) for a good introduction. + +So I think that's it. Oh, well, we do need to add dependencies for `syn` and +`quote` in the `cargo.toml` for `hello-world-derive`. + +```toml +[dependencies] +syn = "0.10.5" +quote = "0.3.10" +``` + +That should be it. Let's try to compile `hello-world`. + +```bash +error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type + --> hello-world-derive/src/lib.rs:8:3 + | +8 | #[proc_macro_derive(HelloWorld)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``` + +Oh, so it appears that we need to declare that our `hello-world-derive` crate is +a `proc-macro` crate type. How do we do this? Like this: + +```toml +[lib] +proc-macro = true +``` + +Ok so now, let's compile `hello-world`. Executing `cargo run` now yields: + +```bash +Hello, World! My name is FrenchToast +Hello, World! My name is Waffles +``` + +We've done it! + +## Custom Attributes + +In some cases it might make sense to allow users some kind of configuration. +For example, the user might want to overwrite the name that is printed in the `hello_world()` method. + +This can be achieved with custom attributes: + +```rust,ignore +#[derive(HelloWorld)] +#[HelloWorldName = "the best Pancakes"] +struct Pancakes; + +fn main() { + Pancakes::hello_world(); +} +``` + +If we try to compile this though, the compiler will respond with an error: + +```bash +error: The attribute `HelloWorldName` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +``` + +The compiler needs to know that we're handling this attribute and to not respond with an error. +This is done in the `hello-world-derive` crate by adding `attributes` to the `proc_macro_derive` attribute: + +```rust,ignore +#[proc_macro_derive(HelloWorld, attributes(HelloWorldName))] +pub fn hello_world(input: TokenStream) -> TokenStream +``` + +Multiple attributes can be specified that way. + +## Raising Errors + +Let's assume that we do not want to accept enums as input to our custom derive method. + +This condition can be easily checked with the help of `syn`. +But how do we tell the user, that we do not accept enums? +The idiomatic way to report errors in procedural macros is to panic: + +```rust,ignore +fn impl_hello_world(ast: &syn::MacroInput) -> quote::Tokens { + let name = &ast.ident; + // Check if derive(HelloWorld) was specified for a struct + if let syn::Body::Struct(_) = ast.body { + // Yes, this is a struct + quote! { + impl HelloWorld for #name { + fn hello_world() { + println!("Hello, World! My name is {}", stringify!(#name)); + } + } + } + } else { + //Nope. This is an Enum. We cannot handle these! + panic!("#[derive(HelloWorld)] is only defined for structs, not for enums!"); + } +} +``` + +If a user now tries to derive `HelloWorld` from an enum they will be greeted with following, hopefully helpful, error: + +```bash +error: custom derive attribute panicked + --> src/main.rs + | + | #[derive(HelloWorld)] + | ^^^^^^^^^^ + | + = help: message: #[derive(HelloWorld)] is only defined for structs, not for enums! +``` diff --git a/trpl/raw-pointers.md b/trpl/raw-pointers.md index ae100ae..7702427 100644 --- a/trpl/raw-pointers.md +++ b/trpl/raw-pointers.md @@ -1,4 +1,4 @@ -% Raw Pointers +# Raw Pointers Rust has a number of different smart pointer types in its standard library, but there are two types that are extra-special. Much of Rust’s safety comes from @@ -72,7 +72,7 @@ println!("raw points at {}", points_at); For more operations on raw pointers, see [their API documentation][rawapi]. [unsafe]: unsafe.html -[rawapi]: ../std/primitive.pointer.html +[rawapi]: ../../std/primitive.pointer.html # FFI @@ -101,11 +101,11 @@ programmer *must* guarantee this. The recommended method for the conversion is: ```rust -// explicit cast +// Explicit cast: let i: u32 = 1; let p_imm: *const u32 = &i as *const u32; -// implicit coercion +// Implicit coercion: let mut m: u32 = 2; let p_mut: *mut u32 = &mut m; diff --git a/trpl/references-and-borrowing.md b/trpl/references-and-borrowing.md index 57bfbce..1daaaef 100644 --- a/trpl/references-and-borrowing.md +++ b/trpl/references-and-borrowing.md @@ -1,4 +1,4 @@ -% References and Borrowing +# References and Borrowing This is the second of three sections presenting Rust’s ownership system. This is one of Rust’s most distinct and compelling features, with which Rust developers should @@ -46,9 +46,9 @@ like this: ```rust fn foo(v1: Vec, v2: Vec) -> (Vec, Vec, i32) { - // do stuff with v1 and v2 + // Do stuff with `v1` and `v2`. - // hand back ownership, and the result of our function + // Hand back ownership, and the result of our function. (v1, v2, 42) } @@ -63,9 +63,9 @@ the first step: ```rust fn foo(v1: &Vec, v2: &Vec) -> i32 { - // do stuff with v1 and v2 + // Do stuff with `v1` and `v2`. - // return the answer + // Return the answer. 42 } @@ -74,7 +74,7 @@ let v2 = vec![1, 2, 3]; let answer = foo(&v1, &v2); -// we can use v1 and v2 here! +// We can use `v1` and `v2` here! ``` A more concrete example: @@ -83,15 +83,15 @@ A more concrete example: fn main() { // Don't worry if you don't understand how `fold` works, the point here is that an immutable reference is borrowed. fn sum_vec(v: &Vec) -> i32 { - return v.iter().fold(0, |a, &b| a + b); + v.iter().fold(0, |a, &b| a + b) } // Borrow two vectors and sum them. - // This kind of borrowing does not allow mutation to the borrowed. + // This kind of borrowing does not allow mutation through the borrowed reference. fn foo(v1: &Vec, v2: &Vec) -> i32 { - // do stuff with v1 and v2 + // Do stuff with `v1` and `v2`. let s1 = sum_vec(v1); let s2 = sum_vec(v2); - // return the answer + // Return the answer. s1 + s2 } @@ -152,7 +152,7 @@ the thing `y` points at. You’ll notice that `x` had to be marked `mut` as well If it wasn’t, we couldn’t take a mutable borrow to an immutable value. You'll also notice we added an asterisk (`*`) in front of `y`, making it `*y`, -this is because `y` is a `&mut` reference. You'll need to use astrisks to +this is because `y` is a `&mut` reference. You'll need to use asterisks to access the contents of a reference as well. Otherwise, `&mut` references are like references. There _is_ a large @@ -240,7 +240,7 @@ fn main() { In other words, the mutable borrow is held through the rest of our example. What we want is for the mutable borrow by `y` to end so that the resource can be -returned to the owner, `x`. `x` can then provide a immutable borrow to `println!`. +returned to the owner, `x`. `x` can then provide an immutable borrow to `println!`. In Rust, borrowing is tied to the scope that the borrow is valid for. And our scopes look like this: @@ -248,12 +248,12 @@ scopes look like this: fn main() { let mut x = 5; - let y = &mut x; // -+ &mut borrow of x starts here + let y = &mut x; // -+ &mut borrow of `x` starts here. // | *y += 1; // | // | - println!("{}", x); // -+ - try to borrow x here -} // -+ &mut borrow of x ends here + println!("{}", x); // -+ - Try to borrow `x` here. +} // -+ &mut borrow of `x` ends here. ``` @@ -265,11 +265,11 @@ So when we add the curly braces: let mut x = 5; { - let y = &mut x; // -+ &mut borrow starts here + let y = &mut x; // -+ &mut borrow starts here. *y += 1; // | -} // -+ ... and ends here +} // -+ ... and ends here. -println!("{}", x); // <- try to borrow x here +println!("{}", x); // <- Try to borrow `x` here. ``` There’s no problem. Our mutable borrow goes out of scope before we create an diff --git a/trpl/release-channels.md b/trpl/release-channels.md index 1e203c6..af89ca8 100644 --- a/trpl/release-channels.md +++ b/trpl/release-channels.md @@ -1,4 +1,4 @@ -% Release Channels +# Release Channels The Rust project uses a concept called ‘release channels’ to manage releases. It’s important to understand this process to choose which version of Rust diff --git a/trpl/strings.md b/trpl/strings.md index 135778c..537e5f9 100644 --- a/trpl/strings.md +++ b/trpl/strings.md @@ -1,4 +1,4 @@ -% Strings +# Strings Strings are an important concept for any programmer to master. Rust’s string handling system is a bit different from other languages, due to its systems @@ -83,10 +83,10 @@ converted using `&*`. ```rust,no_run use std::net::TcpStream; -TcpStream::connect("192.168.0.1:3000"); // &str parameter +TcpStream::connect("192.168.0.1:3000"); // Parameter is of type &str. let addr_string = "192.168.0.1:3000".to_string(); -TcpStream::connect(&*addr_string); // convert addr_string to &str +TcpStream::connect(&*addr_string); // Convert `addr_string` to &str. ``` Viewing a `String` as a `&str` is cheap, but converting the `&str` to a @@ -138,14 +138,14 @@ You can get something similar to an index like this: ```rust # let hachiko = "忠犬ハチ公"; -let dog = hachiko.chars().nth(1); // kinda like hachiko[1] +let dog = hachiko.chars().nth(1); // Kinda like `hachiko[1]`. ``` This emphasizes that we have to walk from the beginning of the list of `chars`. ## Slicing -You can get a slice of a string with slicing syntax: +You can get a slice of a string with the slicing syntax: ```rust let dog = "hachiko"; @@ -163,8 +163,8 @@ let hachi = &dog[0..2]; with this error: ```text -thread 'main' panicked at 'index 0 and/or 2 in `忠犬ハチ公` do not lie on -character boundary' +thread 'main' panicked at 'byte index 2 is not a char boundary; it is inside '忠' +(bytes 0..3) of `忠犬ハチ公`' ``` ## Concatenation @@ -192,4 +192,4 @@ feature called ‘[`Deref` coercions][dc]’. [ut]: unsized-types.html [dc]: deref-coercions.html -[connect]: ../std/net/struct.TcpStream.html#method.connect +[connect]: ../../std/net/struct.TcpStream.html#method.connect diff --git a/trpl/structs.md b/trpl/structs.md index 328db25..27c653a 100644 --- a/trpl/structs.md +++ b/trpl/structs.md @@ -1,4 +1,4 @@ -% Structs +# Structs `struct`s are a way of creating more complex data types. For example, if we were doing calculations involving coordinates in 2D space, we would need both an `x` @@ -61,7 +61,7 @@ write something like this: ```rust,ignore struct Point { - mut x: i32, + mut x: i32, // This causes an error. y: i32, } ``` @@ -82,13 +82,13 @@ fn main() { point.x = 5; - let point = point; // now immutable + let point = point; // `point` is now immutable. - point.y = 6; // this causes an error + point.y = 6; // This causes an error. } ``` -Your structure can still contain `&mut` pointers, which will let +Your structure can still contain `&mut` references, which will let you do some kinds of mutation: ```rust @@ -117,6 +117,28 @@ fn main() { } ``` +Initialization of a data structure (struct, enum, union) can be simplified when +fields of the data structure are initialized with variables of the same +names as the fields. + +```rust +#[derive(Debug)] +struct Person<'a> { + name: &'a str, + age: u8 +} + +fn main() { + // Create struct with field init shorthand + let name = "Peter"; + let age = 27; + let peter = Person { name, age }; + + // Debug-print struct + println!("{:?}", peter); +} +``` + # Update syntax A `struct` can include `..` to indicate that you want to use a copy of some @@ -233,13 +255,14 @@ rather than positions. You can define a `struct` with no members at all: -```rust -struct Electron {} // use empty braces... -struct Proton; // ...or just a semicolon +```rust,compile_fail,E0423 +struct Electron {} // Use empty braces... +struct Proton; // ...or just a semicolon. -// whether you declared the struct with braces or not, do the same when creating one +// Use the same notation when creating an instance. let x = Electron {}; let y = Proton; +let z = Electron; // Error ``` Such a `struct` is called ‘unit-like’ because it resembles the empty diff --git a/trpl/syntax-and-semantics.md b/trpl/syntax-and-semantics.md index e9ec26d..aa4c125 100644 --- a/trpl/syntax-and-semantics.md +++ b/trpl/syntax-and-semantics.md @@ -1,4 +1,4 @@ -% Syntax and Semantics +# Syntax and Semantics This chapter breaks Rust down into small chunks, one for each concept. diff --git a/trpl/syntax-index.md b/trpl/syntax-index.md index 0259db2..b9a1868 100644 --- a/trpl/syntax-index.md +++ b/trpl/syntax-index.md @@ -1,4 +1,4 @@ -% Syntax Index +# Syntax Index ## Keywords @@ -45,7 +45,7 @@ * `%` (`expr % expr`): arithmetic remainder. Overloadable (`Rem`). * `%=` (`var %= expr`): arithmetic remainder & assignment. Overloadable (`RemAssign`). * `&` (`expr & expr`): bitwise and. Overloadable (`BitAnd`). -* `&` (`&expr`): borrow. See [References and Borrowing]. +* `&` (`&expr`, `&mut expr`): borrow. See [References and Borrowing]. * `&` (`&type`, `&mut type`, `&'a type`, `&'a mut type`): borrowed pointer type. See [References and Borrowing]. * `&=` (`var &= expr`): bitwise and & assignment. Overloadable (`BitAndAssign`). * `&&` (`expr && expr`): logical and. @@ -61,7 +61,6 @@ * `-` (`- expr`): arithmetic negation. Overloadable (`Neg`). * `-=` (`var -= expr`): arithmetic subtraction & assignment. Overloadable (`SubAssign`). * `->` (`fn(…) -> type`, `|…| -> type`): function and closure return type. See [Functions], [Closures]. -* `-> !` (`fn(…) -> !`, `|…| -> !`): diverging function or closure. See [Diverging Functions]. * `.` (`expr.ident`): member access. See [Structs], [Method Syntax]. * `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal. * `..` (`..expr`): struct literal update syntax. See [Structs (Update syntax)]. @@ -95,6 +94,7 @@ * `|=` (`var |= expr`): bitwise or & assignment. Overloadable (`BitOrAssign`). * `||` (`expr || expr`): logical or. * `_`: "ignored" pattern binding (see [Patterns (Ignoring bindings)]). Also used to make integer-literals readable (see [Reference (Integer literals)]). +* `?` (`expr?`): Error propagation. Returns early when `Err(_)` is encountered, unwraps otherwise. Similar to the [`try!` macro]. ## Other Syntax @@ -125,7 +125,7 @@ * `path<…>` (*e.g.* `Vec`): specifies parameters to generic type *in a type*. See [Generics]. -* `path::<…>`, `method::<…>` (*e.g.* `"42".parse::()`): specifies parameters to generic type, function, or method *in an expression*. +* `path::<…>`, `method::<…>` (*e.g.* `"42".parse::()`): specifies parameters to generic type, function, or method *in an expression*. See [Generics § Resolving ambiguities](generics.html#resolving-ambiguities). * `fn ident<…> …`: define generic function. See [Generics]. * `struct ident<…> …`: define generic structure. See [Generics]. * `enum ident<…> …`: define generic enumeration. See [Generics]. @@ -159,6 +159,10 @@ * `/*!…*/`: inner block doc comment. See [Comments]. * `/**…*/`: outer block doc comment. See [Comments]. + + +* `!`: always empty Never type. See [Diverging Functions]. + * `()`: empty tuple (*a.k.a.* unit), both literal and type. @@ -207,6 +211,7 @@ [Functions]: functions.html [Generics]: generics.html [Iterators]: iterators.html +[`try!` macro]: error-handling.html#the-try-macro [Lifetimes]: lifetimes.html [Loops (`for`)]: loops.html#for [Loops (`loop`)]: loops.html#loop @@ -230,10 +235,10 @@ [Primitive Types (Tuple Indexing)]: primitive-types.html#tuple-indexing [Primitive Types (Tuples)]: primitive-types.html#tuples [Raw Pointers]: raw-pointers.html -[Reference (Byte String Literals)]: ../reference.html#byte-string-literals -[Reference (Integer literals)]: ../reference.html#integer-literals -[Reference (Raw Byte String Literals)]: ../reference.html#raw-byte-string-literals -[Reference (Raw String Literals)]: ../reference.html#raw-string-literals +[Reference (Byte String Literals)]: ../../reference/tokens.html#byte-and-byte-string-literals +[Reference (Integer literals)]: ../../reference/tokens.html#integer-literals +[Reference (Raw Byte String Literals)]: ../../reference/tokens.html#raw-byte-string-literals +[Reference (Raw String Literals)]: ../../reference/tokens.html#raw-string-literals [References and Borrowing]: references-and-borrowing.html [Strings]: strings.html [Structs (Update syntax)]: structs.html#update-syntax diff --git a/trpl/testing.md b/trpl/testing.md index 8672914..b4f580f 100644 --- a/trpl/testing.md +++ b/trpl/testing.md @@ -1,4 +1,4 @@ -% Testing +# Testing > Program testing can be a very effective way to show the presence of bugs, but > it is hopelessly inadequate for showing their absence. @@ -23,8 +23,26 @@ $ cd adder Cargo will automatically generate a simple test when you make a new project. Here's the contents of `src/lib.rs`: -```rust -# fn main() {} +```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + } +} +``` + +For now, let's remove the `mod` bit, and focus on just the function: + +```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[test] fn it_works() { } @@ -36,8 +54,9 @@ currently has no body. That's good enough to pass! We can run the tests with ```bash $ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///home/you/projects/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.15 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test test it_works ... ok @@ -62,7 +81,9 @@ test it_works ... ok Note the `it_works`. This comes from the name of our function: ```rust +# fn main() { fn it_works() { +} # } ``` @@ -75,8 +96,11 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured So why does our do-nothing test pass? Any test which doesn't `panic!` passes, and any test that does `panic!` fails. Let's make our test fail: -```rust -# fn main() {} +```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[test] fn it_works() { assert!(false); @@ -89,8 +113,9 @@ run our tests again: ```bash $ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///home/you/projects/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.17 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test test it_works ... FAILED @@ -98,8 +123,8 @@ test it_works ... FAILED failures: ---- it_works stdout ---- - thread 'it_works' panicked at 'assertion failed: false', /home/steve/tmp/adder/src/lib.rs:3 - + thread 'it_works' panicked at 'assertion failed: false', src/lib.rs:5 +note: Run with `RUST_BACKTRACE=1` for a backtrace. failures: @@ -107,7 +132,7 @@ failures: test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured -thread 'main' panicked at 'Some tests failed', /home/steve/src/rust/src/libtest/lib.rs:247 +error: test failed ``` Rust indicates that our test failed: @@ -122,7 +147,7 @@ And that's reflected in the summary line: test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured ``` -We also get a non-zero status code. We can use `$?` on OS X and Linux: +We also get a non-zero status code. We can use `$?` on macOS and Linux: ```bash $ echo $? @@ -146,8 +171,11 @@ This is useful if you want to integrate `cargo test` into other tooling. We can invert our test's failure with another attribute: `should_panic`: -```rust -# fn main() {} +```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[test] #[should_panic] fn it_works() { @@ -159,8 +187,9 @@ This test will now succeed if we `panic!` and fail if we complete. Let's try it: ```bash $ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///home/you/projects/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.17 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test test it_works ... ok @@ -177,8 +206,11 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured Rust provides another macro, `assert_eq!`, that compares two arguments for equality: -```rust -# fn main() {} +```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[test] #[should_panic] fn it_works() { @@ -191,8 +223,9 @@ passes: ```bash $ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///home/you/projects/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.21 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test test it_works ... ok @@ -212,8 +245,11 @@ parameter can be added to the `should_panic` attribute. The test harness will make sure that the failure message contains the provided text. A safer version of the example above would be: -```rust -# fn main() {} +```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[test] #[should_panic(expected = "assertion failed")] fn it_works() { @@ -224,7 +260,10 @@ fn it_works() { That's all there is to the basics! Let's write one 'real' test: ```rust,ignore -# fn main() {} +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# pub fn add_two(a: i32) -> i32 { a + 2 } @@ -243,8 +282,15 @@ some known arguments and compare it to the expected output. Sometimes a few specific tests can be very time-consuming to execute. These can be disabled by default by using the `ignore` attribute: -```rust -# fn main() {} +```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# +pub fn add_two(a: i32) -> i32 { + a + 2 +} + #[test] fn it_works() { assert_eq!(4, add_two(2)); @@ -253,7 +299,7 @@ fn it_works() { #[test] #[ignore] fn expensive_test() { - // code that takes an hour to run + // Code that takes an hour to run... } ``` @@ -262,8 +308,9 @@ not: ```bash $ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///home/you/projects/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.20 secs + Running target/debug/deps/adder-941f01916ca4a642 running 2 tests test expensive_test ... ignored @@ -282,7 +329,8 @@ The expensive tests can be run explicitly using `cargo test -- --ignored`: ```bash $ cargo test -- --ignored - Running target/adder-91b3e234d4ed382a + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test test expensive_test ... ok @@ -302,11 +350,17 @@ which is why the command is `cargo test -- --ignored`. # The `tests` module There is one way in which our existing example is not idiomatic: it's -missing the `tests` module. The idiomatic way of writing our example -looks like this: +missing the `tests` module. You might have noticed this test module was +present in the code that was initially generated with `cargo new` but +was missing from our last example. Let's explain what this does. + +The idiomatic way of writing our example looks like this: ```rust,ignore -# fn main() {} +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# pub fn add_two(a: i32) -> i32 { a + 2 } @@ -330,12 +384,15 @@ currently trying to run the tests. This can save compile time, and also ensures that our tests are entirely left out of a normal build. The second change is the `use` declaration. Because we're in an inner module, -we need to bring our test function into scope. This can be annoying if you have +we need to bring the tested function into scope. This can be annoying if you have a large module, and so this is a common use of globs. Let's change our `src/lib.rs` to make use of it: ```rust,ignore -# fn main() {} +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# pub fn add_two(a: i32) -> i32 { a + 2 } @@ -356,8 +413,8 @@ Note the different `use` line. Now we run our tests: ```bash $ cargo test Updating registry `https://github.com/rust-lang/crates.io-index` - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///home/you/projects/adder) + Running target/debug/deps/adder-91b3e234d4ed382a running 1 test test tests::it_works ... ok @@ -380,14 +437,19 @@ the `tests` directory. # The `tests` directory -Each file in `tests/*.rs` directory is treated as individual crate. -So, to write an integration test, let's make a `tests` directory, and -put a `tests/integration_test.rs` file inside, with this as its contents: +Each file in `tests/*.rs` directory is treated as an individual crate. +To write an integration test, let's make a `tests` directory and +put a `tests/integration_test.rs` file inside with this as its contents: ```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# +# // Sadly, this code will not work in play.rust-lang.org, because we have no +# // crate adder to import. You'll need to try this part on your own machine. extern crate adder; -# fn main() {} #[test] fn it_works() { assert_eq!(4, adder::add_two(2)); @@ -404,15 +466,15 @@ Let's run them: ```bash $ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///home/you/projects/adder) + Running target/debug/deps/adder-91b3e234d4ed382a running 1 test test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured - Running target/lib-c18e7d3494509e74 + Running target/debug/integration_test-68064b69521c828a running 1 test test it_works ... ok @@ -437,6 +499,10 @@ be imported in every test with `mod common;` That's all there is to the `tests` directory. The `tests` module isn't needed here, since the whole thing is focused on tests. +Note, when building integration tests, cargo will not pass the `test` attribute +to the compiler. It means that all parts in `cfg(test)` won't be included in +the build used in your integration tests. + Let's finally check out that third section: documentation tests. # Documentation tests @@ -448,7 +514,10 @@ running examples in your documentation (**note:** this only works in library crates, not binary crates). Here's a fleshed-out `src/lib.rs` with examples: ```rust,ignore -# fn main() {} +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# //! The `adder` crate provides functions that add numbers to other numbers. //! //! # Examples @@ -490,15 +559,15 @@ Let's run the tests again: ```bash $ cargo test - Compiling adder v0.0.1 (file:///home/steve/tmp/adder) - Running target/adder-91b3e234d4ed382a + Compiling adder v0.1.0. (file:///home/you/projects/adder) + Running target/debug/deps/adder-91b3e234d4ed382a running 1 test test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured - Running target/lib-c18e7d3494509e74 + Running target/debug/integration_test-68064b69521c828a running 1 test test it_works ... ok @@ -521,3 +590,44 @@ you add more examples. We haven’t covered all of the details with writing documentation tests. For more, please see the [Documentation chapter](documentation.html). + +# Testing and concurrency + +It is important to note that tests are run concurrently using threads. For this +reason, care should be taken to ensure your tests do not depend on each-other, +or on any shared state. "Shared state" can also include the environment, such +as the current working directory, or environment variables. + +If this is an issue it is possible to control this concurrency, either by +setting the environment variable `RUST_TEST_THREADS`, or by passing the argument +`--test-threads` to the tests: + +```bash +$ RUST_TEST_THREADS=1 cargo test # Run tests with no concurrency +... +$ cargo test -- --test-threads=1 # Same as above +... +``` + +# Test output + +By default Rust's test library captures and discards output to standard +out/error, e.g. output from `println!()`. This too can be controlled using the +environment or a switch: + + +```bash +$ RUST_TEST_NOCAPTURE=1 cargo test # Preserve stdout/stderr +... +$ cargo test -- --nocapture # Same as above +... +``` + +However a better method avoiding capture is to use logging rather than raw +output. Rust has a [standard logging API][log], which provides a frontend to +multiple logging implementations. This can be used in conjunction with the +default [env_logger] to output any debugging information in a manner that can be +controlled at runtime. + +[log]: https://crates.io/crates/log +[env_logger]: https://crates.io/crates/env_logger diff --git a/trpl/the-stack-and-the-heap.md b/trpl/the-stack-and-the-heap.md index aee4529..6f8011f 100644 --- a/trpl/the-stack-and-the-heap.md +++ b/trpl/the-stack-and-the-heap.md @@ -1,4 +1,4 @@ -% The Stack and the Heap +# The Stack and the Heap As a systems language, Rust operates at a low level. If you’re coming from a high-level language, there are some aspects of systems programming that you may @@ -86,7 +86,7 @@ to a large number, representing how much RAM your computer has. For example, if you have a gigabyte of RAM, your addresses go from `0` to `1,073,741,823`. That number comes from 230, the number of bytes in a gigabyte. [^gigabyte] -[^gigabyte]: ‘Gigabyte’ can mean two things: 10^9, or 2^30. The SI standard resolved this by stating that ‘gigabyte’ is 10^9, and ‘gibibyte’ is 2^30. However, very few people use this terminology, and rely on context to differentiate. We follow in that tradition here. +[^gigabyte]: ‘Gigabyte’ can mean two things: 109, or 230. The IEC standard resolved this by stating that ‘gigabyte’ is 109, and ‘gibibyte’ is 230. However, very few people use this terminology, and rely on context to differentiate. We follow in that tradition here. This memory is kind of like a giant array: addresses start at zero and go up to the final number. So here’s a diagram of our first stack frame: @@ -215,7 +215,7 @@ fn main() { } ``` -[box]: ../std/boxed/index.html +[box]: ../../std/boxed/index.html Here’s what happens in memory when `main()` is called: @@ -238,7 +238,7 @@ like this: | 1 | y | 42 | | 0 | x | → (230) - 1 | -We have (230) - 1 addresses in our hypothetical computer with 1GB of RAM. And since +We have (230) addresses in our hypothetical computer with 1GB of RAM. And since our stack grows from zero, the easiest place to allocate memory is from the other end. So our first value is at the highest place in memory. And the value of the struct at `x` has a [raw pointer][rawpointer] to the place we’ve diff --git a/trpl/trait-objects.md b/trpl/trait-objects.md index b1aee57..4a4b2cb 100644 --- a/trpl/trait-objects.md +++ b/trpl/trait-objects.md @@ -1,4 +1,4 @@ -% Trait Objects +# Trait Objects When code involves polymorphism, there needs to be a mechanism to determine which specific version is actually run. This is called ‘dispatch’. There are @@ -195,7 +195,7 @@ pub struct TraitObject { # } ``` -[stdraw]: ../std/raw/struct.TraitObject.html +[stdraw]: ../../std/raw/struct.TraitObject.html That is, a trait object like `&Foo` consists of a ‘data’ pointer and a ‘vtable’ pointer. @@ -221,8 +221,8 @@ struct FooVtable { // u8: fn call_method_on_u8(x: *const ()) -> String { - // the compiler guarantees that this function is only called - // with `x` pointing to a u8 + // The compiler guarantees that this function is only called + // with `x` pointing to a u8. let byte: &u8 = unsafe { &*(x as *const u8) }; byte.method() @@ -233,7 +233,7 @@ static Foo_for_u8_vtable: FooVtable = FooVtable { size: 1, align: 1, - // cast to a function pointer + // Cast to a function pointer: method: call_method_on_u8 as fn(*const ()) -> String, }; @@ -241,8 +241,8 @@ static Foo_for_u8_vtable: FooVtable = FooVtable { // String: fn call_method_on_String(x: *const ()) -> String { - // the compiler guarantees that this function is only called - // with `x` pointing to a String + // The compiler guarantees that this function is only called + // with `x` pointing to a String. let string: &String = unsafe { &*(x as *const String) }; string.method() @@ -250,7 +250,7 @@ fn call_method_on_String(x: *const ()) -> String { static Foo_for_String_vtable: FooVtable = FooVtable { destructor: /* compiler magic */, - // values for a 64-bit computer, halve them for 32-bit ones + // Values for a 64-bit computer, halve them for 32-bit ones. size: 24, align: 8, @@ -263,10 +263,7 @@ any resources of the vtable’s type: for `u8` it is trivial, but for `String` i will free the memory. This is necessary for owning trait objects like `Box`, which need to clean-up both the `Box` allocation as well as the internal type when they go out of scope. The `size` and `align` fields store -the size of the erased type, and its alignment requirements; these are -essentially unused at the moment since the information is embedded in the -destructor, but will be used in the future, as trait objects are progressively -made more flexible. +the size of the erased type, and its alignment requirements. Suppose we’ve got some values that implement `Foo`. The explicit form of construction and use of `Foo` trait objects might look a bit like (ignoring the @@ -278,17 +275,17 @@ let x: u8 = 1; // let b: &Foo = &a; let b = TraitObject { - // store the data + // Store the data: data: &a, - // store the methods + // Store the methods: vtable: &Foo_for_String_vtable }; // let y: &Foo = x; let y = TraitObject { - // store the data + // Store the data: data: &x, - // store the methods + // Store the methods: vtable: &Foo_for_u8_vtable }; diff --git a/trpl/traits.md b/trpl/traits.md index e685cb1..91a4bbb 100644 --- a/trpl/traits.md +++ b/trpl/traits.md @@ -1,4 +1,4 @@ -% Traits +# Traits A trait is a language feature that tells the Rust compiler about functionality a type must provide. @@ -47,6 +47,34 @@ As you can see, the `trait` block looks very similar to the `impl` block, but we don’t define a body, only a type signature. When we `impl` a trait, we use `impl Trait for Item`, rather than only `impl Item`. +`Self` may be used in a type annotation to refer to an instance of the type +implementing this trait passed as a parameter. `Self`, `&Self` or `&mut Self` +may be used depending on the level of ownership required. + +```rust +struct Circle { + x: f64, + y: f64, + radius: f64, +} + +trait HasArea { + fn area(&self) -> f64; + + fn is_larger(&self, &Self) -> bool; +} + +impl HasArea for Circle { + fn area(&self) -> f64 { + std::f64::consts::PI * (self.radius * self.radius) + } + + fn is_larger(&self, other: &Self) -> bool { + self.area() > other.area() + } +} +``` + ## Trait bounds on generic functions Traits are useful because they allow a type to make certain promises about its @@ -202,7 +230,7 @@ impl Rectangle { ... } Now, a rectangle can be defined in terms of any type that can be compared for equality. -[PartialEq]: ../core/cmp/trait.PartialEq.html +[PartialEq]: ../../core/cmp/trait.PartialEq.html Here we defined a new struct `Rectangle` that accepts numbers of any precision—really, objects of pretty much any type—as long as they can be @@ -215,28 +243,22 @@ to know more about [operator traits][operators-and-overloading]. # Rules for implementing traits So far, we’ve only added trait implementations to structs, but you can -implement a trait for any type. So technically, we _could_ implement `HasArea` -for `i32`: +implement a trait for any type such as `f32`: ```rust -trait HasArea { - fn area(&self) -> f64; +trait ApproxEqual { + fn approx_equal(&self, other: &Self) -> bool; } - -impl HasArea for i32 { - fn area(&self) -> f64 { - println!("this is silly"); - - *self as f64 +impl ApproxEqual for f32 { + fn approx_equal(&self, other: &Self) -> bool { + // Appropriate for `self` and `other` being close to 1.0. + (self - other).abs() <= ::std::f32::EPSILON } } -5.area(); +println!("{}", 1.0.approx_equal(&1.00000001)); ``` -It is considered poor style to implement methods on such primitive types, even -though it is possible. - This may seem like the Wild West, but there are two restrictions around implementing traits that prevent this from getting out of hand. The first is that if the trait isn’t defined in your scope, it doesn’t apply. Here’s an @@ -244,13 +266,13 @@ example: the standard library provides a [`Write`][write] trait which adds extra functionality to `File`s, for doing file I/O. By default, a `File` won’t have its methods: -[write]: ../std/io/trait.Write.html +[write]: ../../std/io/trait.Write.html ```rust,ignore -let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt"); -let buf = b"whatever"; // byte string literal. buf: &[u8; 8] +let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt"); +let buf = b"whatever"; // buf: &[u8; 8], a byte string literal. let result = f.write(buf); -# result.unwrap(); // ignore the error +# result.unwrap(); // Ignore the error. ``` Here’s the error: @@ -263,13 +285,13 @@ let result = f.write(buf); We need to `use` the `Write` trait first: -```rust,ignore +```rust,no_run use std::io::Write; -let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt"); +let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt"); let buf = b"whatever"; let result = f.write(buf); -# result.unwrap(); // ignore the error +# result.unwrap(); // Ignore the error. ``` This will compile without error. @@ -391,14 +413,14 @@ impl ConvertTo for i32 { fn convert(&self) -> i64 { *self as i64 } } -// can be called with T == i32 -fn normal>(x: &T) -> i64 { +// Can be called with T == i32. +fn convert_t_to_i64>(x: T) -> i64 { x.convert() } -// can be called with T == i64 -fn inverse(x: i32) -> T - // this is using ConvertTo as if it were "ConvertTo" +// Can be called with T == i64. +fn convert_i32_to_t(x: i32) -> T + // This is using ConvertTo as if it were "ConvertTo". where i32: ConvertTo { x.convert() } @@ -448,15 +470,15 @@ impl Foo for OverrideDefault { fn is_invalid(&self) -> bool { println!("Called OverrideDefault.is_invalid!"); - true // overrides the expected value of is_invalid() + true // Overrides the expected value of `is_invalid()`. } } let default = UseDefault; -assert!(!default.is_invalid()); // prints "Called UseDefault.is_valid." +assert!(!default.is_invalid()); // Prints "Called UseDefault.is_valid." let over = OverrideDefault; -assert!(over.is_invalid()); // prints "Called OverrideDefault.is_invalid!" +assert!(over.is_invalid()); // Prints "Called OverrideDefault.is_invalid!" ``` # Inheritance @@ -518,12 +540,12 @@ fn main() { However, deriving is limited to a certain set of traits: -- [`Clone`](../core/clone/trait.Clone.html) -- [`Copy`](../core/marker/trait.Copy.html) -- [`Debug`](../core/fmt/trait.Debug.html) -- [`Default`](../core/default/trait.Default.html) -- [`Eq`](../core/cmp/trait.Eq.html) -- [`Hash`](../core/hash/trait.Hash.html) -- [`Ord`](../core/cmp/trait.Ord.html) -- [`PartialEq`](../core/cmp/trait.PartialEq.html) -- [`PartialOrd`](../core/cmp/trait.PartialOrd.html) +- [`Clone`](../../core/clone/trait.Clone.html) +- [`Copy`](../../core/marker/trait.Copy.html) +- [`Debug`](../../core/fmt/trait.Debug.html) +- [`Default`](../../core/default/trait.Default.html) +- [`Eq`](../../core/cmp/trait.Eq.html) +- [`Hash`](../../core/hash/trait.Hash.html) +- [`Ord`](../../core/cmp/trait.Ord.html) +- [`PartialEq`](../../core/cmp/trait.PartialEq.html) +- [`PartialOrd`](../../core/cmp/trait.PartialOrd.html) diff --git a/trpl/type-aliases.md b/trpl/type-aliases.md index def2e31..f70e7a3 100644 --- a/trpl/type-aliases.md +++ b/trpl/type-aliases.md @@ -1,4 +1,4 @@ -% `type` Aliases +# Type Aliases The `type` keyword lets you declare an alias of another type: @@ -75,4 +75,4 @@ This creates a specialized version of the `Result` type, which always has a in the standard library to create custom errors for each subsection. For example, [io::Result][ioresult]. -[ioresult]: ../std/io/type.Result.html +[ioresult]: ../../std/io/type.Result.html diff --git a/trpl/ufcs.md b/trpl/ufcs.md index 7725970..016ecc7 100644 --- a/trpl/ufcs.md +++ b/trpl/ufcs.md @@ -1,4 +1,4 @@ -% Universal Function Call Syntax +# Universal Function Call Syntax Sometimes, functions can have the same names. Consider this code: diff --git a/trpl/unsafe.md b/trpl/unsafe.md index 9cab586..0331c95 100644 --- a/trpl/unsafe.md +++ b/trpl/unsafe.md @@ -1,4 +1,4 @@ -% Unsafe +# Unsafe Rust’s main draw is its powerful static guarantees about behavior. But safety checks are conservative by nature: there are some programs that are actually @@ -12,7 +12,7 @@ four contexts. The first one is to mark a function as unsafe: ```rust unsafe fn danger_will_robinson() { - // scary stuff + // Scary stuff... } ``` @@ -23,7 +23,7 @@ The second use of `unsafe` is an unsafe block: ```rust unsafe { - // scary stuff + // Scary stuff... } ``` @@ -139,4 +139,4 @@ I’ll repeat again: even though you _can_ do arbitrary things in unsafe blocks and functions doesn’t mean you should. The compiler will act as though you’re upholding its invariants, so be careful! -[intrinsics]: intrinsics.html +[intrinsics]: ../../unstable-book/language-features/intrinsics.html diff --git a/trpl/unsized-types.md b/trpl/unsized-types.md index a23470d..2d09092 100644 --- a/trpl/unsized-types.md +++ b/trpl/unsized-types.md @@ -1,4 +1,4 @@ -% Unsized Types +# Unsized Types Most types have a particular size, in bytes, that is knowable at compile time. For example, an `i32` is thirty-two bits big, or four bytes. However, there are diff --git a/trpl/using-rust-without-the-standard-library.md b/trpl/using-rust-without-the-standard-library.md index 69958dd..c1dcfea 100644 --- a/trpl/using-rust-without-the-standard-library.md +++ b/trpl/using-rust-without-the-standard-library.md @@ -1,4 +1,4 @@ -% Using Rust Without the Standard Library +# Using Rust Without the Standard Library Rust’s standard library provides a lot of useful functionality, but assumes support for various features of its host system: threads, networking, heap @@ -9,11 +9,11 @@ don’t want to use the standard library via an attribute: `#![no_std]`. > Note: This feature is technically stable, but there are some caveats. For > one, you can build a `#![no_std]` _library_ on stable, but not a _binary_. > For details on binaries without the standard library, see [the nightly -> chapter on `#![no_std]`](no-stdlib.html) +> chapter on 'lang items'][unstable book lang items] To use `#![no_std]`, add it to your crate root: -```rust +```rust,ignore #![no_std] fn plus_one(x: i32) -> i32 { @@ -22,14 +22,14 @@ fn plus_one(x: i32) -> i32 { ``` Much of the functionality that’s exposed in the standard library is also -available via the [`core` crate](../core/index.html). When we’re using the +available via the [`core` crate](../../core/index.html). When we’re using the standard library, Rust automatically brings `std` into scope, allowing you to use its features without an explicit import. By the same token, when using `#![no_std]`, Rust will bring `core` into scope for you, as well as [its -prelude](../core/prelude/v1/index.html). This means that a lot of code will Just +prelude](../../core/prelude/v1/index.html). This means that a lot of code will Just Work: -```rust +```rust,ignore #![no_std] fn may_fail(failure: bool) -> Result<(), &'static str> { @@ -40,3 +40,5 @@ fn may_fail(failure: bool) -> Result<(), &'static str> { } } ``` + +[unstable book lang items]: ../../unstable-book/language-features/lang-items.html#using-libc diff --git a/trpl/variable-bindings.md b/trpl/variable-bindings.md index 30e922d..65e172e 100644 --- a/trpl/variable-bindings.md +++ b/trpl/variable-bindings.md @@ -1,4 +1,4 @@ -% Variable Bindings +# Variable Bindings Virtually every non-'Hello World’ Rust program uses *variable bindings*. They bind some value to a name, so it can be used later. `let` is @@ -47,7 +47,7 @@ let x: i32 = 5; ``` If I asked you to read this out loud to the rest of the class, you’d say “`x` -is a binding with the type `i32` and the value `five`.” +is a binding with the type `i32` and the value `5`.” In this case we chose to represent `x` as a 32-bit signed integer. Rust has many different primitive integer types. They begin with `i` for signed integers @@ -102,7 +102,7 @@ mutation, then the solution is quite easy: add `mut`. There are other good reasons to avoid mutable state when possible, but they’re out of the scope of this guide. In general, you can often avoid explicit mutation, and so it is preferable in Rust. That said, sometimes, mutation is -what you need, so it’s not verboten. +what you need, so it’s not forbidden. # Initializing bindings @@ -161,7 +161,7 @@ Could not compile `hello_world`. Rust will not let us use a value that has not been initialized. -Let take a minute to talk about this stuff we've added to `println!`. +Let us take a minute to talk about this stuff we've added to `println!`. If you include two curly braces (`{}`, some call them moustaches...) in your string to print, Rust will interpret this as a request to interpolate some sort @@ -176,12 +176,12 @@ more detailed manner, there are a [wide number of options available][format]. For now, we'll stick to the default: integers aren't very complicated to print. -[format]: ../std/fmt/index.html +[format]: ../../std/fmt/index.html # Scope and shadowing Let’s get back to bindings. Variable bindings have a scope - they are -constrained to live in a block they were defined in. A block is a collection +constrained to live in the block they were defined in. A block is a collection of statements enclosed by `{` and `}`. Function definitions are also blocks! In the following example we define two variable bindings, `x` and `y`, which live in different blocks. `x` can be accessed from inside the `fn main() {}` @@ -194,7 +194,7 @@ fn main() { let y: i32 = 3; println!("The value of x is {} and value of y is {}", x, y); } - println!("The value of x is {} and value of y is {}", x, y); // This won't work + println!("The value of x is {} and value of y is {}", x, y); // This won't work. } ``` @@ -207,7 +207,7 @@ Instead we get this error: $ cargo build Compiling hello v0.1.0 (file:///home/you/projects/hello_world) main.rs:7:62: 7:63 error: unresolved name `y`. Did you mean `x`? [E0425] -main.rs:7 println!("The value of x is {} and value of y is {}", x, y); // This won't work +main.rs:7 println!("The value of x is {} and value of y is {}", x, y); // This won't work. ^ note: in expansion of format_args! :2:25: 2:56 note: expansion site @@ -229,13 +229,13 @@ scope will override the previous binding. ```rust let x: i32 = 8; { - println!("{}", x); // Prints "8" + println!("{}", x); // Prints "8". let x = 12; - println!("{}", x); // Prints "12" + println!("{}", x); // Prints "12". } -println!("{}", x); // Prints "8" +println!("{}", x); // Prints "8". let x = 42; -println!("{}", x); // Prints "42" +println!("{}", x); // Prints "42". ``` Shadowing and mutable bindings may appear as two sides of the same coin, but @@ -249,8 +249,8 @@ by any means. ```rust let mut x: i32 = 1; x = 7; -let x = x; // x is now immutable and is bound to 7 +let x = x; // `x` is now immutable and is bound to `7`. let y = 4; -let y = "I can also be bound to text!"; // y is now of a different type +let y = "I can also be bound to text!"; // `y` is now of a different type. ``` diff --git a/trpl/vectors.md b/trpl/vectors.md index cb6781c..138a152 100644 --- a/trpl/vectors.md +++ b/trpl/vectors.md @@ -1,4 +1,4 @@ -% Vectors +# Vectors A ‘vector’ is a dynamic or ‘growable’ array, implemented as the standard library type [`Vec`][vec]. The `T` means that we can have vectors @@ -17,7 +17,7 @@ situation, this is just convention.) There’s an alternate form of `vec!` for repeating an initial value: ```rust -let v = vec![0; 10]; // ten zeroes +let v = vec![0; 10]; // A vector of ten zeroes. ``` Vectors store their contents as contiguous arrays of `T` on the heap. This means @@ -46,10 +46,10 @@ let v = vec![1, 2, 3, 4, 5]; let i: usize = 0; let j: i32 = 0; -// works +// Works: v[i]; -// doesn’t +// Doesn’t: v[j]; ``` @@ -148,9 +148,9 @@ for i in &v { Vectors have many more useful methods, which you can read about in [their API documentation][vec]. -[vec]: ../std/vec/index.html -[box]: ../std/boxed/index.html +[vec]: ../../std/vec/index.html +[box]: ../../std/boxed/index.html [generic]: generics.html [panic]: concurrency.html#panics -[get]: ../std/vec/struct.Vec.html#method.get -[get_mut]: ../std/vec/struct.Vec.html#method.get_mut +[get]: ../../std/vec/struct.Vec.html#method.get +[get_mut]: ../../std/vec/struct.Vec.html#method.get_mut From 59180f89cbe4a0c4c9dfe6a3717d6372f34576fa Mon Sep 17 00:00:00 2001 From: Nick Hahn Date: Tue, 23 May 2017 19:37:33 +0200 Subject: [PATCH 2/3] Update nomicon sources --- nomicon/README.md | 6 +- nomicon/SUMMARY.md | 3 + nomicon/arc-and-mutex.md | 2 +- nomicon/atomics.md | 12 +- nomicon/borrow-splitting.md | 2 +- nomicon/casts.md | 2 +- nomicon/chapter_1.md | 1 + nomicon/checked-uninit.md | 2 +- nomicon/coercions.md | 6 +- nomicon/concurrency.md | 2 +- nomicon/constructors.md | 2 +- nomicon/conversions.md | 2 +- nomicon/data.md | 2 +- nomicon/destructors.md | 24 +- nomicon/dot-operator.md | 2 +- nomicon/drop-flags.md | 18 +- nomicon/dropck.md | 34 +- nomicon/exception-safety.md | 6 +- nomicon/exotic-sizes.md | 2 +- nomicon/ffi.md | 756 ++++++++++++++++++++++++++++++++ nomicon/hrtb.md | 2 +- nomicon/img/safeandunsafe.svg | 66 +++ nomicon/leaking.md | 2 +- nomicon/lifetime-elision.md | 10 +- nomicon/lifetime-mismatch.md | 2 +- nomicon/lifetimes.md | 2 +- nomicon/meet-safe-and-unsafe.md | 6 +- nomicon/obrm.md | 2 +- nomicon/other-reprs.md | 2 +- nomicon/ownership.md | 4 +- nomicon/phantom-data.md | 33 +- nomicon/poisoning.md | 2 +- nomicon/races.md | 12 +- nomicon/references.md | 2 +- nomicon/repr-rust.md | 2 +- nomicon/safe-unsafe-meaning.md | 251 +++++------ nomicon/send-and-sync.md | 4 +- nomicon/subtyping.md | 2 +- nomicon/transmutes.md | 2 +- nomicon/unbounded-lifetimes.md | 4 +- nomicon/unchecked-uninit.md | 2 +- nomicon/uninitialized.md | 2 +- nomicon/unwinding.md | 2 +- nomicon/vec-alloc.md | 24 +- nomicon/vec-dealloc.md | 4 +- nomicon/vec-deref.md | 6 +- nomicon/vec-drain.md | 2 +- nomicon/vec-final.md | 18 +- nomicon/vec-insert-remove.md | 2 +- nomicon/vec-into-iter.md | 4 +- nomicon/vec-layout.md | 16 +- nomicon/vec-push-pop.md | 2 +- nomicon/vec-raw.md | 13 +- nomicon/vec-zsts.md | 18 +- nomicon/vec.md | 2 +- nomicon/working-with-unsafe.md | 2 +- 56 files changed, 1111 insertions(+), 306 deletions(-) create mode 100644 nomicon/chapter_1.md create mode 100644 nomicon/ffi.md create mode 100644 nomicon/img/safeandunsafe.svg diff --git a/nomicon/README.md b/nomicon/README.md index 0654313..d577d7b 100644 --- a/nomicon/README.md +++ b/nomicon/README.md @@ -1,8 +1,8 @@ -% The Rustonomicon +# The Rustonomicon #### The Dark Arts of Advanced and Unsafe Rust Programming -**NOTE: This is a draft document, and may contain serious errors** +# NOTE: This is a draft document, and may contain serious errors > Instead of the programs I had hoped for, there came only a shuddering blackness and ineffable loneliness; and I saw at last a fearful truth which no one had @@ -35,4 +35,4 @@ exception-safety, pointer aliasing, memory models, and even some type-theory. We will also be spending a lot of time talking about the different kinds of safety and guarantees. -[trpl]: ../book/ +[trpl]: ../book/index.html diff --git a/nomicon/SUMMARY.md b/nomicon/SUMMARY.md index 7d4ef9c..0b34952 100644 --- a/nomicon/SUMMARY.md +++ b/nomicon/SUMMARY.md @@ -1,5 +1,7 @@ # Summary +[Introduction](README.md) + * [Meet Safe and Unsafe](meet-safe-and-unsafe.md) * [How Safe and Unsafe Interact](safe-unsafe-meaning.md) * [Working with Unsafe](working-with-unsafe.md) @@ -51,3 +53,4 @@ * [Handling Zero-Sized Types](vec-zsts.md) * [Final Code](vec-final.md) * [Implementing Arc and Mutex](arc-and-mutex.md) +* [FFI](ffi.md) diff --git a/nomicon/arc-and-mutex.md b/nomicon/arc-and-mutex.md index fcafe55..fedc7b8 100644 --- a/nomicon/arc-and-mutex.md +++ b/nomicon/arc-and-mutex.md @@ -1,4 +1,4 @@ -% Implementing Arc and Mutex +# Implementing Arc and Mutex Knowing the theory is all fine and good, but the *best* way to understand something is to use it. To better understand atomics and interior mutability, diff --git a/nomicon/atomics.md b/nomicon/atomics.md index 1efca08..4cd209a 100644 --- a/nomicon/atomics.md +++ b/nomicon/atomics.md @@ -1,4 +1,4 @@ -% Atomics +# Atomics Rust pretty blatantly just inherits C11's memory model for atomics. This is not due to this model being particularly excellent or easy to understand. Indeed, @@ -24,10 +24,10 @@ exactly what we said but, you know, fast. Wouldn't that be great? # Compiler Reordering -Compilers fundamentally want to be able to do all sorts of crazy transformations -to reduce data dependencies and eliminate dead code. In particular, they may -radically change the actual order of events, or make events never occur! If we -write something like +Compilers fundamentally want to be able to do all sorts of complicated +transformations to reduce data dependencies and eliminate dead code. In +particular, they may radically change the actual order of events, or make events +never occur! If we write something like ```rust,ignore x = 1; @@ -196,7 +196,7 @@ reordered to occur before it. When thread A releases a location in memory and then thread B subsequently acquires *the same* location in memory, causality is established. Every write -that happened before A's release will be observed by B after its release. +that happened before A's release will be observed by B after its acquisition. However no causality is established with any other threads. Similarly, no causality is established if A and B access *different* locations in memory. diff --git a/nomicon/borrow-splitting.md b/nomicon/borrow-splitting.md index cc5bc8a..28ddb50 100644 --- a/nomicon/borrow-splitting.md +++ b/nomicon/borrow-splitting.md @@ -1,4 +1,4 @@ -% Splitting Borrows +# Splitting Borrows The mutual exclusion property of mutable references can be very limiting when working with a composite structure. The borrow checker understands some basic diff --git a/nomicon/casts.md b/nomicon/casts.md index 6cc41bd..31b7858 100644 --- a/nomicon/casts.md +++ b/nomicon/casts.md @@ -1,4 +1,4 @@ -% Casts +# Casts Casts are a superset of coercions: every coercion can be explicitly invoked via a cast. However some conversions require a cast. diff --git a/nomicon/chapter_1.md b/nomicon/chapter_1.md new file mode 100644 index 0000000..b743fda --- /dev/null +++ b/nomicon/chapter_1.md @@ -0,0 +1 @@ +# Chapter 1 diff --git a/nomicon/checked-uninit.md b/nomicon/checked-uninit.md index f7c4482..4423404 100644 --- a/nomicon/checked-uninit.md +++ b/nomicon/checked-uninit.md @@ -1,4 +1,4 @@ -% Checked Uninitialized Memory +# Checked Uninitialized Memory Like C, all stack variables in Rust are uninitialized until a value is explicitly assigned to them. Unlike C, Rust statically prevents you from ever diff --git a/nomicon/coercions.md b/nomicon/coercions.md index 6a9ebd6..1a51bb5 100644 --- a/nomicon/coercions.md +++ b/nomicon/coercions.md @@ -1,4 +1,4 @@ -% Coercions +# Coercions Types can implicitly be coerced to change in certain contexts. These changes are generally just *weakening* of types, largely focused around pointers and @@ -17,6 +17,7 @@ Coercion is allowed between the following types: * `&T` to `*const T` * `&mut T` to `*mut T` * Unsizing: `T` to `U` if `T` implements `CoerceUnsized` +* Deref coercion: Expression `&x` of type `&T` to `&*x` of type `&U` if `T` derefs to `U` (i.e. `T: Deref`) `CoerceUnsized> for Pointer where T: Unsize` is implemented for all pointer types (including smart pointers like Box and Rc). Unsize is @@ -27,8 +28,9 @@ only implemented automatically, and enables the following transformations: * `Foo<..., T, ...>` => `Foo<..., U, ...>` where: * `T: Unsize` * `Foo` is a struct - * Only the last field of `Foo` has type `T` + * Only the last field of `Foo` has type involving `T` * `T` is not part of the type of any other fields + * `Bar: Unsize>`, if the last field of `Foo` has type `Bar` Coercions occur at a *coercion site*. Any location that is explicitly typed will cause a coercion to its type. If inference is necessary, the coercion will diff --git a/nomicon/concurrency.md b/nomicon/concurrency.md index b93b303..6205199 100644 --- a/nomicon/concurrency.md +++ b/nomicon/concurrency.md @@ -1,4 +1,4 @@ -% Concurrency and Parallelism +# Concurrency and Parallelism Rust as a language doesn't *really* have an opinion on how to do concurrency or parallelism. The standard library exposes OS threads and blocking sys-calls diff --git a/nomicon/constructors.md b/nomicon/constructors.md index 97817cd..b79e72d 100644 --- a/nomicon/constructors.md +++ b/nomicon/constructors.md @@ -1,4 +1,4 @@ -% Constructors +# Constructors There is exactly one way to create an instance of a user-defined type: name it, and initialize all its fields at once: diff --git a/nomicon/conversions.md b/nomicon/conversions.md index b099a78..388d003 100644 --- a/nomicon/conversions.md +++ b/nomicon/conversions.md @@ -1,4 +1,4 @@ -% Type Conversions +# Type Conversions At the end of the day, everything is just a pile of bits somewhere, and type systems are just there to help us use those bits right. There are two common diff --git a/nomicon/data.md b/nomicon/data.md index d0a796b..bf202ad 100644 --- a/nomicon/data.md +++ b/nomicon/data.md @@ -1,4 +1,4 @@ -% Data Representation in Rust +# Data Representation in Rust Low-level programming cares a lot about data layout. It's a big deal. It also pervasively influences the rest of the language, so we're going to start by diff --git a/nomicon/destructors.md b/nomicon/destructors.md index c6fa5b0..6c7b2c9 100644 --- a/nomicon/destructors.md +++ b/nomicon/destructors.md @@ -1,4 +1,4 @@ -% Destructors +# Destructors What the language *does* provide is full-blown automatic destructors through the `Drop` trait, which provides the following method: @@ -26,7 +26,7 @@ this is totally fine. For instance, a custom implementation of `Box` might write `Drop` like this: ```rust -#![feature(alloc, heap_api, drop_in_place, unique)] +#![feature(alloc, heap_api, unique)] extern crate alloc; @@ -40,8 +40,8 @@ struct Box{ ptr: Unique } impl Drop for Box { fn drop(&mut self) { unsafe { - drop_in_place(*self.ptr); - heap::deallocate((*self.ptr) as *mut u8, + drop_in_place(self.ptr.as_ptr()); + heap::deallocate(self.ptr.as_ptr() as *mut u8, mem::size_of::(), mem::align_of::()); } @@ -57,7 +57,7 @@ use-after-free the `ptr` because when drop exits, it becomes inaccessible. However this wouldn't work: ```rust -#![feature(alloc, heap_api, drop_in_place, unique)] +#![feature(alloc, heap_api, unique)] extern crate alloc; @@ -71,8 +71,8 @@ struct Box{ ptr: Unique } impl Drop for Box { fn drop(&mut self) { unsafe { - drop_in_place(*self.ptr); - heap::deallocate((*self.ptr) as *mut u8, + drop_in_place(self.ptr.as_ptr()); + heap::deallocate(self.ptr.as_ptr() as *mut u8, mem::size_of::(), mem::align_of::()); } @@ -86,7 +86,7 @@ impl Drop for SuperBox { unsafe { // Hyper-optimized: deallocate the box's contents for it // without `drop`ing the contents - heap::deallocate((*self.my_box.ptr) as *mut u8, + heap::deallocate(self.my_box.ptr.as_ptr() as *mut u8, mem::size_of::(), mem::align_of::()); } @@ -135,7 +135,7 @@ The classic safe solution to overriding recursive drop and allowing moving out of Self during `drop` is to use an Option: ```rust -#![feature(alloc, heap_api, drop_in_place, unique)] +#![feature(alloc, heap_api, unique)] extern crate alloc; @@ -149,8 +149,8 @@ struct Box{ ptr: Unique } impl Drop for Box { fn drop(&mut self) { unsafe { - drop_in_place(*self.ptr); - heap::deallocate((*self.ptr) as *mut u8, + drop_in_place(self.ptr.as_ptr()); + heap::deallocate(self.ptr.as_ptr() as *mut u8, mem::size_of::(), mem::align_of::()); } @@ -166,7 +166,7 @@ impl Drop for SuperBox { // without `drop`ing the contents. Need to set the `box` // field as `None` to prevent Rust from trying to Drop it. let my_box = self.my_box.take().unwrap(); - heap::deallocate((*my_box.ptr) as *mut u8, + heap::deallocate(my_box.ptr.as_ptr() as *mut u8, mem::size_of::(), mem::align_of::()); mem::forget(my_box); diff --git a/nomicon/dot-operator.md b/nomicon/dot-operator.md index 5d2010d..a1fc33b 100644 --- a/nomicon/dot-operator.md +++ b/nomicon/dot-operator.md @@ -1,4 +1,4 @@ -% The Dot Operator +# The Dot Operator The dot operator will perform a lot of magic to convert types. It will perform auto-referencing, auto-dereferencing, and coercion until types match. diff --git a/nomicon/drop-flags.md b/nomicon/drop-flags.md index cfceafe..e69264f 100644 --- a/nomicon/drop-flags.md +++ b/nomicon/drop-flags.md @@ -1,4 +1,4 @@ -% Drop Flags +# Drop Flags The examples in the previous section introduce an interesting problem for Rust. We have seen that it's possible to conditionally initialize, deinitialize, and @@ -79,17 +79,5 @@ if condition { } ``` -As of Rust 1.0, the drop flags are actually not-so-secretly stashed in a hidden -field of any type that implements Drop. Rust sets the drop flag by overwriting -the entire value with a particular bit pattern. This is pretty obviously Not -The Fastest and causes a bunch of trouble with optimizing code. It's legacy from -a time when you could do much more complex conditional initialization. - -As such work is currently under way to move the flags out onto the stack frame -where they more reasonably belong. Unfortunately, this work will take some time -as it requires fairly substantial changes to the compiler. - -Regardless, Rust programs don't need to worry about uninitialized values on -the stack for correctness. Although they might care for performance. Thankfully, -Rust makes it easy to take control here! Uninitialized values are there, and -you can work with them in Safe Rust, but you're never in danger. +The drop flags are tracked on the stack and no longer stashed in types that +implement drop. diff --git a/nomicon/dropck.md b/nomicon/dropck.md index ad7c650..3903969 100644 --- a/nomicon/dropck.md +++ b/nomicon/dropck.md @@ -1,4 +1,4 @@ -% Drop Check +# Drop Check We have seen how lifetimes provide us some fairly simple rules for ensuring that we never read dangling references. However up to this point we have only ever @@ -125,7 +125,7 @@ is that some Drop implementations will not access borrowed data even though their type gives them the capability for such access. For example, this variant of the above `Inspector` example will never -accessed borrowed data: +access borrowed data: ```rust,ignore struct Inspector<'a>(&'a u8, &'static str); @@ -199,24 +199,42 @@ assert (unsafely) that a generic type's destructor is *guaranteed* to not access any expired data, even if its type gives it the capability to do so. -That attribute is called `unsafe_destructor_blind_to_params`. +That attribute is called `may_dangle` and was introduced in [RFC 1327] +(https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md). To deploy it on the Inspector example from above, we would write: ```rust,ignore struct Inspector<'a>(&'a u8, &'static str); -impl<'a> Drop for Inspector<'a> { - #[unsafe_destructor_blind_to_params] +unsafe impl<#[may_dangle] 'a> Drop for Inspector<'a> { fn drop(&mut self) { println!("Inspector(_, {}) knows when *not* to inspect.", self.1); } } ``` -This attribute has the word `unsafe` in it because the compiler is not -checking the implicit assertion that no potentially expired data +Use of this attribute requires the `Drop` impl to be marked `unsafe` because the +compiler is not checking the implicit assertion that no potentially expired data (e.g. `self.0` above) is accessed. +The attribute can be applied to any number of lifetime and type parameters. In +the following example, we assert that we access no data behind a reference of +lifetime `'b` and that the only uses of `T` will be moves or drops, but omit +the attribute from `'a` and `U`, because we do access data with that lifetime +and that type: + +```rust,ignore +use std::fmt::Display; + +struct Inspector<'a, 'b, T, U: Display>(&'a u8, &'b u8, T, U); + +unsafe impl<'a, #[may_dangle] 'b, #[may_dangle] T, U: Display> Drop for Inspector<'a, 'b, T, U> { + fn drop(&mut self) { + println!("Inspector({}, _, _, {})", self.0, self.3); + } +} +``` + It is sometimes obvious that no such access can occur, like the case above. However, when dealing with a generic type parameter, such access can occur indirectly. Examples of such indirect access are: @@ -263,7 +281,7 @@ some other method invoked by the destructor, rather than being written directly within it. In all of the above cases where the `&'a u8` is accessed in the -destructor, adding the `#[unsafe_destructor_blind_to_params]` +destructor, adding the `#[may_dangle]` attribute makes the type vulnerable to misuse that the borrower checker will not catch, inviting havoc. It is better to avoid adding the attribute. diff --git a/nomicon/exception-safety.md b/nomicon/exception-safety.md index 74f7831..a3cbc6a 100644 --- a/nomicon/exception-safety.md +++ b/nomicon/exception-safety.md @@ -1,4 +1,4 @@ -% Exception Safety +# Exception Safety Although programs should use unwinding sparingly, there's a lot of code that *can* panic. If you unwrap a None, index out of bounds, or divide by 0, your @@ -93,7 +93,7 @@ uselessly. We would rather have the following: ```text bubble_up(heap, index): let elem = heap[index] - while index != 0 && element < heap[parent(index)]: + while index != 0 && elem < heap[parent(index)]: heap[index] = heap[parent(index)] index = parent(index) heap[index] = elem @@ -137,7 +137,7 @@ If Rust had `try` and `finally` like in Java, we could do the following: bubble_up(heap, index): let elem = heap[index] try: - while index != 0 && element < heap[parent(index)]: +        while index != 0 && elem < heap[parent(index)]: heap[index] = heap[parent(index)] index = parent(index) finally: diff --git a/nomicon/exotic-sizes.md b/nomicon/exotic-sizes.md index 052e3c5..9f858d1 100644 --- a/nomicon/exotic-sizes.md +++ b/nomicon/exotic-sizes.md @@ -1,4 +1,4 @@ -% Exotically Sized Types +# Exotically Sized Types Most of the time, we think in terms of types with a fixed, positive size. This is not always the case, however. diff --git a/nomicon/ffi.md b/nomicon/ffi.md new file mode 100644 index 0000000..03693bb --- /dev/null +++ b/nomicon/ffi.md @@ -0,0 +1,756 @@ +# Foreign Function Interface + +# Introduction + +This guide will use the [snappy](https://github.com/google/snappy) +compression/decompression library as an introduction to writing bindings for +foreign code. Rust is currently unable to call directly into a C++ library, but +snappy includes a C interface (documented in +[`snappy-c.h`](https://github.com/google/snappy/blob/master/snappy-c.h)). + +## A note about libc + +Many of these examples use [the `libc` crate][libc], which provides various +type definitions for C types, among other things. If you’re trying these +examples yourself, you’ll need to add `libc` to your `Cargo.toml`: + +```toml +[dependencies] +libc = "0.2.0" +``` + +[libc]: https://crates.io/crates/libc + +and add `extern crate libc;` to your crate root. + +## Calling foreign functions + +The following is a minimal example of calling a foreign function which will +compile if snappy is installed: + +```rust,ignore +extern crate libc; +use libc::size_t; + +#[link(name = "snappy")] +extern { + fn snappy_max_compressed_length(source_length: size_t) -> size_t; +} + +fn main() { + let x = unsafe { snappy_max_compressed_length(100) }; + println!("max compressed length of a 100 byte buffer: {}", x); +} +``` + +The `extern` block is a list of function signatures in a foreign library, in +this case with the platform's C ABI. The `#[link(...)]` attribute is used to +instruct the linker to link against the snappy library so the symbols are +resolved. + +Foreign functions are assumed to be unsafe so calls to them need to be wrapped +with `unsafe {}` as a promise to the compiler that everything contained within +truly is safe. C libraries often expose interfaces that aren't thread-safe, and +almost any function that takes a pointer argument isn't valid for all possible +inputs since the pointer could be dangling, and raw pointers fall outside of +Rust's safe memory model. + +When declaring the argument types to a foreign function, the Rust compiler +cannot check if the declaration is correct, so specifying it correctly is part +of keeping the binding correct at runtime. + +The `extern` block can be extended to cover the entire snappy API: + +```rust,ignore +extern crate libc; +use libc::{c_int, size_t}; + +#[link(name = "snappy")] +extern { + fn snappy_compress(input: *const u8, + input_length: size_t, + compressed: *mut u8, + compressed_length: *mut size_t) -> c_int; + fn snappy_uncompress(compressed: *const u8, + compressed_length: size_t, + uncompressed: *mut u8, + uncompressed_length: *mut size_t) -> c_int; + fn snappy_max_compressed_length(source_length: size_t) -> size_t; + fn snappy_uncompressed_length(compressed: *const u8, + compressed_length: size_t, + result: *mut size_t) -> c_int; + fn snappy_validate_compressed_buffer(compressed: *const u8, + compressed_length: size_t) -> c_int; +} +# fn main() {} +``` + +# Creating a safe interface + +The raw C API needs to be wrapped to provide memory safety and make use of higher-level concepts +like vectors. A library can choose to expose only the safe, high-level interface and hide the unsafe +internal details. + +Wrapping the functions which expect buffers involves using the `slice::raw` module to manipulate Rust +vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous block of memory. The +length is the number of elements currently contained, and the capacity is the total size in elements of +the allocated memory. The length is less than or equal to the capacity. + +```rust,ignore +# extern crate libc; +# use libc::{c_int, size_t}; +# unsafe fn snappy_validate_compressed_buffer(_: *const u8, _: size_t) -> c_int { 0 } +# fn main() {} +pub fn validate_compressed_buffer(src: &[u8]) -> bool { + unsafe { + snappy_validate_compressed_buffer(src.as_ptr(), src.len() as size_t) == 0 + } +} +``` + +The `validate_compressed_buffer` wrapper above makes use of an `unsafe` block, but it makes the +guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function +signature. + +The `snappy_compress` and `snappy_uncompress` functions are more complex, since a buffer has to be +allocated to hold the output too. + +The `snappy_max_compressed_length` function can be used to allocate a vector with the maximum +required capacity to hold the compressed output. The vector can then be passed to the +`snappy_compress` function as an output parameter. An output parameter is also passed to retrieve +the true length after compression for setting the length. + +```rust,ignore +# extern crate libc; +# use libc::{size_t, c_int}; +# unsafe fn snappy_compress(a: *const u8, b: size_t, c: *mut u8, +# d: *mut size_t) -> c_int { 0 } +# unsafe fn snappy_max_compressed_length(a: size_t) -> size_t { a } +# fn main() {} +pub fn compress(src: &[u8]) -> Vec { + unsafe { + let srclen = src.len() as size_t; + let psrc = src.as_ptr(); + + let mut dstlen = snappy_max_compressed_length(srclen); + let mut dst = Vec::with_capacity(dstlen as usize); + let pdst = dst.as_mut_ptr(); + + snappy_compress(psrc, srclen, pdst, &mut dstlen); + dst.set_len(dstlen as usize); + dst + } +} +``` + +Decompression is similar, because snappy stores the uncompressed size as part of the compression +format and `snappy_uncompressed_length` will retrieve the exact buffer size required. + +```rust,ignore +# extern crate libc; +# use libc::{size_t, c_int}; +# unsafe fn snappy_uncompress(compressed: *const u8, +# compressed_length: size_t, +# uncompressed: *mut u8, +# uncompressed_length: *mut size_t) -> c_int { 0 } +# unsafe fn snappy_uncompressed_length(compressed: *const u8, +# compressed_length: size_t, +# result: *mut size_t) -> c_int { 0 } +# fn main() {} +pub fn uncompress(src: &[u8]) -> Option> { + unsafe { + let srclen = src.len() as size_t; + let psrc = src.as_ptr(); + + let mut dstlen: size_t = 0; + snappy_uncompressed_length(psrc, srclen, &mut dstlen); + + let mut dst = Vec::with_capacity(dstlen as usize); + let pdst = dst.as_mut_ptr(); + + if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 { + dst.set_len(dstlen as usize); + Some(dst) + } else { + None // SNAPPY_INVALID_INPUT + } + } +} +``` + +Then, we can add some tests to show how to use them. + +```rust,ignore +# extern crate libc; +# use libc::{c_int, size_t}; +# unsafe fn snappy_compress(input: *const u8, +# input_length: size_t, +# compressed: *mut u8, +# compressed_length: *mut size_t) +# -> c_int { 0 } +# unsafe fn snappy_uncompress(compressed: *const u8, +# compressed_length: size_t, +# uncompressed: *mut u8, +# uncompressed_length: *mut size_t) +# -> c_int { 0 } +# unsafe fn snappy_max_compressed_length(source_length: size_t) -> size_t { 0 } +# unsafe fn snappy_uncompressed_length(compressed: *const u8, +# compressed_length: size_t, +# result: *mut size_t) +# -> c_int { 0 } +# unsafe fn snappy_validate_compressed_buffer(compressed: *const u8, +# compressed_length: size_t) +# -> c_int { 0 } +# fn main() { } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn valid() { + let d = vec![0xde, 0xad, 0xd0, 0x0d]; + let c: &[u8] = &compress(&d); + assert!(validate_compressed_buffer(c)); + assert!(uncompress(c) == Some(d)); + } + + #[test] + fn invalid() { + let d = vec![0, 0, 0, 0]; + assert!(!validate_compressed_buffer(&d)); + assert!(uncompress(&d).is_none()); + } + + #[test] + fn empty() { + let d = vec![]; + assert!(!validate_compressed_buffer(&d)); + assert!(uncompress(&d).is_none()); + let c = compress(&d); + assert!(validate_compressed_buffer(&c)); + assert!(uncompress(&c) == Some(d)); + } +} +``` + +# Destructors + +Foreign libraries often hand off ownership of resources to the calling code. +When this occurs, we must use Rust's destructors to provide safety and guarantee +the release of these resources (especially in the case of panic). + +For more about destructors, see the [Drop trait](../std/ops/trait.Drop.html). + +# Callbacks from C code to Rust functions + +Some external libraries require the usage of callbacks to report back their +current state or intermediate data to the caller. +It is possible to pass functions defined in Rust to an external library. +The requirement for this is that the callback function is marked as `extern` +with the correct calling convention to make it callable from C code. + +The callback function can then be sent through a registration call +to the C library and afterwards be invoked from there. + +A basic example is: + +Rust code: + +```rust,no_run +extern fn callback(a: i32) { + println!("I'm called from C with value {0}", a); +} + +#[link(name = "extlib")] +extern { + fn register_callback(cb: extern fn(i32)) -> i32; + fn trigger_callback(); +} + +fn main() { + unsafe { + register_callback(callback); + trigger_callback(); // Triggers the callback. + } +} +``` + +C code: + +```c +typedef void (*rust_callback)(int32_t); +rust_callback cb; + +int32_t register_callback(rust_callback callback) { + cb = callback; + return 1; +} + +void trigger_callback() { + cb(7); // Will call callback(7) in Rust. +} +``` + +In this example Rust's `main()` will call `trigger_callback()` in C, +which would, in turn, call back to `callback()` in Rust. + + +## Targeting callbacks to Rust objects + +The former example showed how a global function can be called from C code. +However it is often desired that the callback is targeted to a special +Rust object. This could be the object that represents the wrapper for the +respective C object. + +This can be achieved by passing a raw pointer to the object down to the +C library. The C library can then include the pointer to the Rust object in +the notification. This will allow the callback to unsafely access the +referenced Rust object. + +Rust code: + +```rust,no_run +#[repr(C)] +struct RustObject { + a: i32, + // Other members... +} + +extern "C" fn callback(target: *mut RustObject, a: i32) { + println!("I'm called from C with value {0}", a); + unsafe { + // Update the value in RustObject with the value received from the callback: + (*target).a = a; + } +} + +#[link(name = "extlib")] +extern { + fn register_callback(target: *mut RustObject, + cb: extern fn(*mut RustObject, i32)) -> i32; + fn trigger_callback(); +} + +fn main() { + // Create the object that will be referenced in the callback: + let mut rust_object = Box::new(RustObject { a: 5 }); + + unsafe { + register_callback(&mut *rust_object, callback); + trigger_callback(); + } +} +``` + +C code: + +```c +typedef void (*rust_callback)(void*, int32_t); +void* cb_target; +rust_callback cb; + +int32_t register_callback(void* callback_target, rust_callback callback) { + cb_target = callback_target; + cb = callback; + return 1; +} + +void trigger_callback() { + cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust. +} +``` + +## Asynchronous callbacks + +In the previously given examples the callbacks are invoked as a direct reaction +to a function call to the external C library. +The control over the current thread is switched from Rust to C to Rust for the +execution of the callback, but in the end the callback is executed on the +same thread that called the function which triggered the callback. + +Things get more complicated when the external library spawns its own threads +and invokes callbacks from there. +In these cases access to Rust data structures inside the callbacks is +especially unsafe and proper synchronization mechanisms must be used. +Besides classical synchronization mechanisms like mutexes, one possibility in +Rust is to use channels (in `std::sync::mpsc`) to forward data from the C +thread that invoked the callback into a Rust thread. + +If an asynchronous callback targets a special object in the Rust address space +it is also absolutely necessary that no more callbacks are performed by the +C library after the respective Rust object gets destroyed. +This can be achieved by unregistering the callback in the object's +destructor and designing the library in a way that guarantees that no +callback will be performed after deregistration. + +# Linking + +The `link` attribute on `extern` blocks provides the basic building block for +instructing rustc how it will link to native libraries. There are two accepted +forms of the link attribute today: + +* `#[link(name = "foo")]` +* `#[link(name = "foo", kind = "bar")]` + +In both of these cases, `foo` is the name of the native library that we're +linking to, and in the second case `bar` is the type of native library that the +compiler is linking to. There are currently three known types of native +libraries: + +* Dynamic - `#[link(name = "readline")]` +* Static - `#[link(name = "my_build_dependency", kind = "static")]` +* Frameworks - `#[link(name = "CoreFoundation", kind = "framework")]` + +Note that frameworks are only available on macOS targets. + +The different `kind` values are meant to differentiate how the native library +participates in linkage. From a linkage perspective, the Rust compiler creates +two flavors of artifacts: partial (rlib/staticlib) and final (dylib/binary). +Native dynamic library and framework dependencies are propagated to the final +artifact boundary, while static library dependencies are not propagated at +all, because the static libraries are integrated directly into the subsequent +artifact. + +A few examples of how this model can be used are: + +* A native build dependency. Sometimes some C/C++ glue is needed when writing + some Rust code, but distribution of the C/C++ code in a library format is + a burden. In this case, the code will be archived into `libfoo.a` and then the + Rust crate would declare a dependency via `#[link(name = "foo", kind = + "static")]`. + + Regardless of the flavor of output for the crate, the native static library + will be included in the output, meaning that distribution of the native static + library is not necessary. + +* A normal dynamic dependency. Common system libraries (like `readline`) are + available on a large number of systems, and often a static copy of these + libraries cannot be found. When this dependency is included in a Rust crate, + partial targets (like rlibs) will not link to the library, but when the rlib + is included in a final target (like a binary), the native library will be + linked in. + +On macOS, frameworks behave with the same semantics as a dynamic library. + +# Unsafe blocks + +Some operations, like dereferencing raw pointers or calling functions that have been marked +unsafe are only allowed inside unsafe blocks. Unsafe blocks isolate unsafety and are a promise to +the compiler that the unsafety does not leak out of the block. + +Unsafe functions, on the other hand, advertise it to the world. An unsafe function is written like +this: + +```rust +unsafe fn kaboom(ptr: *const i32) -> i32 { *ptr } +``` + +This function can only be called from an `unsafe` block or another `unsafe` function. + +# Accessing foreign globals + +Foreign APIs often export a global variable which could do something like track +global state. In order to access these variables, you declare them in `extern` +blocks with the `static` keyword: + +```rust,ignore +extern crate libc; + +#[link(name = "readline")] +extern { + static rl_readline_version: libc::c_int; +} + +fn main() { + println!("You have readline version {} installed.", + unsafe { rl_readline_version as i32 }); +} +``` + +Alternatively, you may need to alter global state provided by a foreign +interface. To do this, statics can be declared with `mut` so we can mutate +them. + +```rust,ignore +extern crate libc; + +use std::ffi::CString; +use std::ptr; + +#[link(name = "readline")] +extern { + static mut rl_prompt: *const libc::c_char; +} + +fn main() { + let prompt = CString::new("[my-awesome-shell] $").unwrap(); + unsafe { + rl_prompt = prompt.as_ptr(); + + println!("{:?}", rl_prompt); + + rl_prompt = ptr::null(); + } +} +``` + +Note that all interaction with a `static mut` is unsafe, both reading and +writing. Dealing with global mutable state requires a great deal of care. + +# Foreign calling conventions + +Most foreign code exposes a C ABI, and Rust uses the platform's C calling convention by default when +calling foreign functions. Some foreign functions, most notably the Windows API, use other calling +conventions. Rust provides a way to tell the compiler which convention to use: + +```rust,ignore +extern crate libc; + +#[cfg(all(target_os = "win32", target_arch = "x86"))] +#[link(name = "kernel32")] +#[allow(non_snake_case)] +extern "stdcall" { + fn SetEnvironmentVariableA(n: *const u8, v: *const u8) -> libc::c_int; +} +# fn main() { } +``` + +This applies to the entire `extern` block. The list of supported ABI constraints +are: + +* `stdcall` +* `aapcs` +* `cdecl` +* `fastcall` +* `vectorcall` +This is currently hidden behind the `abi_vectorcall` gate and is subject to change. +* `Rust` +* `rust-intrinsic` +* `system` +* `C` +* `win64` +* `sysv64` + +Most of the abis in this list are self-explanatory, but the `system` abi may +seem a little odd. This constraint selects whatever the appropriate ABI is for +interoperating with the target's libraries. For example, on win32 with a x86 +architecture, this means that the abi used would be `stdcall`. On x86_64, +however, windows uses the `C` calling convention, so `C` would be used. This +means that in our previous example, we could have used `extern "system" { ... }` +to define a block for all windows systems, not only x86 ones. + +# Interoperability with foreign code + +Rust guarantees that the layout of a `struct` is compatible with the platform's +representation in C only if the `#[repr(C)]` attribute is applied to it. +`#[repr(C, packed)]` can be used to lay out struct members without padding. +`#[repr(C)]` can also be applied to an enum. + +Rust's owned boxes (`Box`) use non-nullable pointers as handles which point +to the contained object. However, they should not be manually created because +they are managed by internal allocators. References can safely be assumed to be +non-nullable pointers directly to the type. However, breaking the borrow +checking or mutability rules is not guaranteed to be safe, so prefer using raw +pointers (`*`) if that's needed because the compiler can't make as many +assumptions about them. + +Vectors and strings share the same basic memory layout, and utilities are +available in the `vec` and `str` modules for working with C APIs. However, +strings are not terminated with `\0`. If you need a NUL-terminated string for +interoperability with C, you should use the `CString` type in the `std::ffi` +module. + +The [`libc` crate on crates.io][libc] includes type aliases and function +definitions for the C standard library in the `libc` module, and Rust links +against `libc` and `libm` by default. + +# Variadic functions + +In C, functions can be 'variadic', meaning they accept a variable number of arguments. This can +be achieved in Rust by specifying `...` within the argument list of a foreign function declaration: + +```no_run +extern { + fn foo(x: i32, ...); +} + +fn main() { + unsafe { + foo(10, 20, 30, 40, 50); + } +} +``` + +Normal Rust functions can *not* be variadic: + +```ignore +// This will not compile + +fn foo(x: i32, ...) { } +``` + +# The "nullable pointer optimization" + +Certain Rust types are defined to never be `null`. This includes references (`&T`, +`&mut T`), boxes (`Box`), and function pointers (`extern "abi" fn()`). When +interfacing with C, pointers that might be `null` are often used, which would seem to +require some messy `transmute`s and/or unsafe code to handle conversions to/from Rust types. +However, the language provides a workaround. + +As a special case, an `enum` is eligible for the "nullable pointer optimization" if it contains +exactly two variants, one of which contains no data and the other contains a field of one of the +non-nullable types listed above. This means no extra space is required for a discriminant; rather, +the empty variant is represented by putting a `null` value into the non-nullable field. This is +called an "optimization", but unlike other optimizations it is guaranteed to apply to eligible +types. + +The most common type that takes advantage of the nullable pointer optimization is `Option`, +where `None` corresponds to `null`. So `Option c_int>` is a correct way +to represent a nullable function pointer using the C ABI (corresponding to the C type +`int (*)(int)`). + +Here is a contrived example. Let's say some C library has a facility for registering a +callback, which gets called in certain situations. The callback is passed a function pointer +and an integer and it is supposed to run the function with the integer as a parameter. So +we have function pointers flying across the FFI boundary in both directions. + +```rust,ignore +extern crate libc; +use libc::c_int; + +# #[cfg(hidden)] +extern "C" { + /// Registers the callback. + fn register(cb: Option c_int>, c_int) -> c_int>); +} +# unsafe fn register(_: Option c_int>, +# c_int) -> c_int>) +# {} + +/// This fairly useless function receives a function pointer and an integer +/// from C, and returns the result of calling the function with the integer. +/// In case no function is provided, it squares the integer by default. +extern "C" fn apply(process: Option c_int>, int: c_int) -> c_int { + match process { + Some(f) => f(int), + None => int * int + } +} + +fn main() { + unsafe { + register(Some(apply)); + } +} +``` + +And the code on the C side looks like this: + +```c +void register(void (*f)(void (*)(int), int)) { + ... +} +``` + +No `transmute` required! + +# Calling Rust code from C + +You may wish to compile Rust code in a way so that it can be called from C. This is +fairly easy, but requires a few things: + +```rust +#[no_mangle] +pub extern fn hello_rust() -> *const u8 { + "Hello, world!\0".as_ptr() +} +# fn main() {} +``` + +The `extern` makes this function adhere to the C calling convention, as +discussed above in "[Foreign Calling +Conventions](ffi.html#foreign-calling-conventions)". The `no_mangle` +attribute turns off Rust's name mangling, so that it is easier to link to. + +# FFI and panics + +It’s important to be mindful of `panic!`s when working with FFI. A `panic!` +across an FFI boundary is undefined behavior. If you’re writing code that may +panic, you should run it in a closure with [`catch_unwind`]: + +```rust +use std::panic::catch_unwind; + +#[no_mangle] +pub extern fn oh_no() -> i32 { + let result = catch_unwind(|| { + panic!("Oops!"); + }); + match result { + Ok(_) => 0, + Err(_) => 1, + } +} + +fn main() {} +``` + +Please note that [`catch_unwind`] will only catch unwinding panics, not +those who abort the process. See the documentation of [`catch_unwind`] +for more information. + +[`catch_unwind`]: ../std/panic/fn.catch_unwind.html + +# Representing opaque structs + +Sometimes, a C library wants to provide a pointer to something, but not let you +know the internal details of the thing it wants. The simplest way is to use a +`void *` argument: + +```c +void foo(void *arg); +void bar(void *arg); +``` + +We can represent this in Rust with the `c_void` type: + +```rust,ignore +extern crate libc; + +extern "C" { + pub fn foo(arg: *mut libc::c_void); + pub fn bar(arg: *mut libc::c_void); +} +# fn main() {} +``` + +This is a perfectly valid way of handling the situation. However, we can do a bit +better. To solve this, some C libraries will instead create a `struct`, where +the details and memory layout of the struct are private. This gives some amount +of type safety. These structures are called ‘opaque’. Here’s an example, in C: + +```c +struct Foo; /* Foo is a structure, but its contents are not part of the public interface */ +struct Bar; +void foo(struct Foo *arg); +void bar(struct Bar *arg); +``` + +To do this in Rust, let’s create our own opaque types with `enum`: + +```rust +pub enum Foo {} +pub enum Bar {} + +extern "C" { + pub fn foo(arg: *mut Foo); + pub fn bar(arg: *mut Bar); +} +# fn main() {} +``` + +By using an `enum` with no variants, we create an opaque type that we can’t +instantiate, as it has no variants. But because our `Foo` and `Bar` types are +different, we’ll get type safety between the two of them, so we cannot +accidentally pass a pointer to `Foo` to `bar()`. diff --git a/nomicon/hrtb.md b/nomicon/hrtb.md index 8692832..645986a 100644 --- a/nomicon/hrtb.md +++ b/nomicon/hrtb.md @@ -1,4 +1,4 @@ -% Higher-Rank Trait Bounds (HRTBs) +# Higher-Rank Trait Bounds (HRTBs) Rust's `Fn` traits are a little bit magic. For instance, we can write the following code: diff --git a/nomicon/img/safeandunsafe.svg b/nomicon/img/safeandunsafe.svg new file mode 100644 index 0000000..72022b3 --- /dev/null +++ b/nomicon/img/safeandunsafe.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nomicon/leaking.md b/nomicon/leaking.md index a5d5742..38b70b8 100644 --- a/nomicon/leaking.md +++ b/nomicon/leaking.md @@ -1,4 +1,4 @@ -% Leaking +# Leaking Ownership-based resource management is intended to simplify composition. You acquire resources when you create the object, and you release the resources when diff --git a/nomicon/lifetime-elision.md b/nomicon/lifetime-elision.md index bcd93a5..7628351 100644 --- a/nomicon/lifetime-elision.md +++ b/nomicon/lifetime-elision.md @@ -1,4 +1,4 @@ -% Lifetime Elision +# Lifetime Elision In order to make common patterns more ergonomic, Rust allows lifetimes to be *elided* in function signatures. @@ -42,11 +42,11 @@ Examples: fn print(s: &str); // elided fn print<'a>(s: &'a str); // expanded -fn debug(lvl: uint, s: &str); // elided -fn debug<'a>(lvl: uint, s: &'a str); // expanded +fn debug(lvl: usize, s: &str); // elided +fn debug<'a>(lvl: usize, s: &'a str); // expanded -fn substr(s: &str, until: uint) -> &str; // elided -fn substr<'a>(s: &'a str, until: uint) -> &'a str; // expanded +fn substr(s: &str, until: usize) -> &str; // elided +fn substr<'a>(s: &'a str, until: usize) -> &'a str; // expanded fn get_str() -> &str; // ILLEGAL diff --git a/nomicon/lifetime-mismatch.md b/nomicon/lifetime-mismatch.md index 0ad8a78..30b4f09 100644 --- a/nomicon/lifetime-mismatch.md +++ b/nomicon/lifetime-mismatch.md @@ -1,4 +1,4 @@ -% Limits of Lifetimes +# Limits of Lifetimes Given the following code: diff --git a/nomicon/lifetimes.md b/nomicon/lifetimes.md index 45eb68b..e2f0cc8 100644 --- a/nomicon/lifetimes.md +++ b/nomicon/lifetimes.md @@ -1,4 +1,4 @@ -% Lifetimes +# Lifetimes Rust enforces these rules through *lifetimes*. Lifetimes are effectively just names for scopes somewhere in the program. Each reference, diff --git a/nomicon/meet-safe-and-unsafe.md b/nomicon/meet-safe-and-unsafe.md index 978d051..4d0bb70 100644 --- a/nomicon/meet-safe-and-unsafe.md +++ b/nomicon/meet-safe-and-unsafe.md @@ -1,4 +1,6 @@ -% Meet Safe and Unsafe +# Meet Safe and Unsafe + +![safe and unsafe](img/safeandunsafe.svg) Programmers in safe "high-level" languages face a fundamental dilemma. On one hand, it would be *really* great to just say what you want and not worry about @@ -22,7 +24,7 @@ Well, Rust *has* a safe programming language. Let's step back a bit. Rust can be thought of as being composed of two programming languages: *Safe Rust* and *Unsafe Rust*. Safe Rust is For Reals Totally Safe. Unsafe Rust, unsurprisingly, is *not* For Reals Totally Safe. In fact, Unsafe Rust lets you -do some really crazy unsafe things. +do some really, *really* unsafe things. Safe Rust is the *true* Rust programming language. If all you do is write Safe Rust, you will never have to worry about type-safety or memory-safety. You will diff --git a/nomicon/obrm.md b/nomicon/obrm.md index 2c49524..19e5ec3 100644 --- a/nomicon/obrm.md +++ b/nomicon/obrm.md @@ -1,4 +1,4 @@ -% The Perils Of Ownership Based Resource Management (OBRM) +# The Perils Of Ownership Based Resource Management (OBRM) OBRM (AKA RAII: Resource Acquisition Is Initialization) is something you'll interact with a lot in Rust. Especially if you use the standard library. diff --git a/nomicon/other-reprs.md b/nomicon/other-reprs.md index b124f3f..02f39e3 100644 --- a/nomicon/other-reprs.md +++ b/nomicon/other-reprs.md @@ -1,4 +1,4 @@ -% Alternative representations +# Alternative representations Rust allows you to specify alternative data layout strategies from the default. diff --git a/nomicon/ownership.md b/nomicon/ownership.md index 6be8d3b..dd9e9db 100644 --- a/nomicon/ownership.md +++ b/nomicon/ownership.md @@ -1,4 +1,4 @@ -% Ownership and Lifetimes +# Ownership and Lifetimes Ownership is the breakout feature of Rust. It allows Rust to be completely memory-safe and efficient, while avoiding garbage collection. Before getting @@ -52,7 +52,7 @@ let mut data = vec![1, 2, 3]; let x = &data[0]; // OH NO! `push` causes the backing storage of `data` to be reallocated. -// Dangling pointer! User after free! Alas! +// Dangling pointer! Use after free! Alas! // (this does not compile in Rust) data.push(4); diff --git a/nomicon/phantom-data.md b/nomicon/phantom-data.md index 0d7ec7f..32539c2 100644 --- a/nomicon/phantom-data.md +++ b/nomicon/phantom-data.md @@ -1,4 +1,4 @@ -% PhantomData +# PhantomData When working with unsafe code, we can often end up in a situation where types or lifetimes are logically associated with a struct, but not actually @@ -50,13 +50,13 @@ struct Vec { } ``` -Unlike the previous example it *appears* that everything is exactly as we -want. Every generic argument to Vec shows up in the at least one field. +Unlike the previous example, it *appears* that everything is exactly as we +want. Every generic argument to Vec shows up in at least one field. Good to go! Nope. -The drop checker will generously determine that Vec does not own any values +The drop checker will generously determine that `Vec` does not own any values of type T. This will in turn make it conclude that it doesn't need to worry about Vec dropping any T's in its destructor for determining drop check soundness. This will in turn allow people to create unsoundness using @@ -81,7 +81,24 @@ Raw pointers that own an allocation is such a pervasive pattern that the standard library made a utility for itself called `Unique` which: * wraps a `*const T` for variance -* includes a `PhantomData`, -* auto-derives Send/Sync as if T was contained -* marks the pointer as NonZero for the null-pointer optimization - +* includes a `PhantomData` +* auto-derives `Send`/`Sync` as if T was contained +* marks the pointer as `NonZero` for the null-pointer optimization + +## Table of `PhantomData` patterns + +Here’s a table of all the wonderful ways `PhantomData` could be used: + +| Phantom type | `'a` | `T` | +|-----------------------------|-----------|---------------------------| +| `PhantomData` | - | variant (with drop check) | +| `PhantomData<&'a T>` | variant | variant | +| `PhantomData<&'a mut T>` | variant | invariant | +| `PhantomData<*const T>` | - | variant | +| `PhantomData<*mut T>` | - | invariant | +| `PhantomData` | - | contravariant (*) | +| `PhantomData T>` | - | variant | +| `PhantomData T>` | - | invariant | +| `PhantomData>` | invariant | - | + +(*) If contravariance gets scrapped, this would be invariant. diff --git a/nomicon/poisoning.md b/nomicon/poisoning.md index 70de91a..9b5dec3 100644 --- a/nomicon/poisoning.md +++ b/nomicon/poisoning.md @@ -1,4 +1,4 @@ -% Poisoning +# Poisoning Although all unsafe code *must* ensure it has minimal exception safety, not all types ensure *maximal* exception safety. Even if the type does, your code may diff --git a/nomicon/races.md b/nomicon/races.md index f0732cf..c9b8c3d 100644 --- a/nomicon/races.md +++ b/nomicon/races.md @@ -1,4 +1,4 @@ -% Data Races and Race Conditions +# Data Races and Race Conditions Safe Rust guarantees an absence of data races, which are defined as: @@ -21,11 +21,11 @@ prevent *all* race conditions would be pretty awful to use, if not just incorrect. So it's perfectly "fine" for a Safe Rust program to get deadlocked or do -something incredibly stupid with incorrect synchronization. Obviously such a -program isn't very good, but Rust can only hold your hand so far. Still, a -race condition can't violate memory safety in a Rust program on -its own. Only in conjunction with some other unsafe code can a race condition -actually violate memory safety. For instance: +something nonsensical with incorrect synchronization. Obviously such a program +isn't very good, but Rust can only hold your hand so far. Still, a race +condition can't violate memory safety in a Rust program on its own. Only in +conjunction with some other unsafe code can a race condition actually violate +memory safety. For instance: ```rust,no_run use std::thread; diff --git a/nomicon/references.md b/nomicon/references.md index 3d7369e..5d80f1e 100644 --- a/nomicon/references.md +++ b/nomicon/references.md @@ -1,4 +1,4 @@ -% References +# References This section gives a high-level view of the memory model that *all* Rust programs must satisfy to be correct. Safe code is statically verified diff --git a/nomicon/repr-rust.md b/nomicon/repr-rust.md index effeaf8..c02cf44 100644 --- a/nomicon/repr-rust.md +++ b/nomicon/repr-rust.md @@ -1,4 +1,4 @@ -% repr(Rust) +# repr(Rust) First and foremost, all types have an alignment specified in bytes. The alignment of a type specifies what addresses are valid to store the value at. A diff --git a/nomicon/safe-unsafe-meaning.md b/nomicon/safe-unsafe-meaning.md index 5fd61eb..0a655a3 100644 --- a/nomicon/safe-unsafe-meaning.md +++ b/nomicon/safe-unsafe-meaning.md @@ -1,150 +1,123 @@ -% How Safe and Unsafe Interact - -So what's the relationship between Safe and Unsafe Rust? How do they interact? - -Rust models the separation between Safe and Unsafe Rust with the `unsafe` -keyword, which can be thought as a sort of *foreign function interface* (FFI) -between Safe and Unsafe Rust. This is the magic behind why we can say Safe Rust -is a safe language: all the scary unsafe bits are relegated exclusively to FFI -*just like every other safe language*. - -However because one language is a subset of the other, the two can be cleanly -intermixed as long as the boundary between Safe and Unsafe Rust is denoted with -the `unsafe` keyword. No need to write headers, initialize runtimes, or any of -that other FFI boiler-plate. - -There are several places `unsafe` can appear in Rust today, which can largely be -grouped into two categories: - -* There are unchecked contracts here. To declare you understand this, I require -you to write `unsafe` elsewhere: - * On functions, `unsafe` is declaring the function to be unsafe to call. - Users of the function must check the documentation to determine what this - means, and then have to write `unsafe` somewhere to identify that they're - aware of the danger. - * On trait declarations, `unsafe` is declaring that *implementing* the trait - is an unsafe operation, as it has contracts that other unsafe code is free - to trust blindly. (More on this below.) - -* I am declaring that I have, to the best of my knowledge, adhered to the -unchecked contracts: - * On trait implementations, `unsafe` is declaring that the contract of the - `unsafe` trait has been upheld. - * On blocks, `unsafe` is declaring any unsafety from an unsafe - operation within to be handled, and therefore the parent function is safe. - -There is also `#[unsafe_no_drop_flag]`, which is a special case that exists for -historical reasons and is in the process of being phased out. See the section on -[drop flags] for details. - -Some examples of unsafe functions: - -* `slice::get_unchecked` will perform unchecked indexing, allowing memory - safety to be freely violated. -* every raw pointer to sized type has intrinsic `offset` method that invokes - Undefined Behavior if it is not "in bounds" as defined by LLVM. -* `mem::transmute` reinterprets some value as having the given type, - bypassing type safety in arbitrary ways. (see [conversions] for details) -* All FFI functions are `unsafe` because they can do arbitrary things. - C being an obvious culprit, but generally any language can do something - that Rust isn't happy about. +# How Safe and Unsafe Interact + +What's the relationship between Safe Rust and Unsafe Rust? How do they +interact? + +The separation between Safe Rust and Unsafe Rust is controlled with the +`unsafe` keyword, which acts as an interface from one to the other. This is +why we can say Safe Rust is a safe language: all the unsafe parts are kept +exclusively behind the boundary. + +The `unsafe` keyword has two uses: to declare the existence of contracts the +compiler can't check, and to declare that the adherence of some code to +those contracts has been checked by the programmer. + +You can use `unsafe` to indicate the existence of unchecked contracts on +_functions_ and on _trait declarations_. On functions, `unsafe` means that +users of the function must check that function's documentation to ensure +they are using it in a way that maintains the contracts the function +requires. On trait declarations, `unsafe` means that implementors of the +trait must check the trait documentation to ensure their implementation +maintains the contracts the trait requires. + +You can use `unsafe` on a block to declare that all constraints required +by an unsafe function within the block have been adhered to, and the code +can therefore be trusted. You can use `unsafe` on a trait implementation +to declare that the implementation of that trait has adhered to whatever +contracts the trait's documentation requires. + +The standard library has a number of unsafe functions, including: + +* `slice::get_unchecked`, which performs unchecked indexing, allowing + memory safety to be freely violated. +* `mem::transmute` reinterprets some value as having a given type, bypassing + type safety in arbitrary ways (see [conversions] for details). +* Every raw pointer to a sized type has an intrinstic `offset` method that + invokes Undefined Behavior if the passed offset is not "in bounds" as + defined by LLVM. +* All FFI functions are `unsafe` because the other language can do arbitrary + operations that the Rust compiler can't check. As of Rust 1.0 there are exactly two unsafe traits: -* `Send` is a marker trait (it has no actual API) that promises implementors - are safe to send (move) to another thread. -* `Sync` is a marker trait that promises that threads can safely share - implementors through a shared reference. - -The need for unsafe traits boils down to the fundamental property of safe code: - -**No matter how completely awful Safe code is, it can't cause Undefined -Behavior.** - -This means that Unsafe Rust, **the royal vanguard of Undefined Behavior**, has to be -*super paranoid* about generic safe code. To be clear, Unsafe Rust is totally free to trust -specific safe code. Anything else would degenerate into infinite spirals of -paranoid despair. In particular it's generally regarded as ok to trust the standard library -to be correct. `std` is effectively an extension of the language, and you -really just have to trust the language. If `std` fails to uphold the -guarantees it declares, then it's basically a language bug. - -That said, it would be best to minimize *needlessly* relying on properties of -concrete safe code. Bugs happen! Of course, I must reinforce that this is only -a concern for Unsafe code. Safe code can blindly trust anyone and everyone -as far as basic memory-safety is concerned. - -On the other hand, safe traits are free to declare arbitrary contracts, but because -implementing them is safe, unsafe code can't trust those contracts to actually -be upheld. This is different from the concrete case because *anyone* can -randomly implement the interface. There is something fundamentally different -about trusting a particular piece of code to be correct, and trusting *all the -code that will ever be written* to be correct. - -For instance Rust has `PartialOrd` and `Ord` traits to try to differentiate -between types which can "just" be compared, and those that actually implement a -total ordering. Pretty much every API that wants to work with data that can be -compared wants Ord data. For instance, a sorted map like BTreeMap -*doesn't even make sense* for partially ordered types. If you claim to implement -Ord for a type, but don't actually provide a proper total ordering, BTreeMap will -get *really confused* and start making a total mess of itself. Data that is -inserted may be impossible to find! - -But that's okay. BTreeMap is safe, so it guarantees that even if you give it a -completely garbage Ord implementation, it will still do something *safe*. You -won't start reading uninitialized or unallocated memory. In fact, BTreeMap -manages to not actually lose any of your data. When the map is dropped, all the -destructors will be successfully called! Hooray! - -However BTreeMap is implemented using a modest spoonful of Unsafe Rust (most collections -are). That means that it's not necessarily *trivially true* that a bad Ord -implementation will make BTreeMap behave safely. BTreeMap must be sure not to rely -on Ord *where safety is at stake*. Ord is provided by safe code, and safety is not -safe code's responsibility to uphold. - -But wouldn't it be grand if there was some way for Unsafe to trust some trait -contracts *somewhere*? This is the problem that unsafe traits tackle: by marking -*the trait itself* as unsafe to implement, unsafe code can trust the implementation -to uphold the trait's contract. Although the trait implementation may be -incorrect in arbitrary other ways. - -For instance, given a hypothetical UnsafeOrd trait, this is technically a valid -implementation: +* `Send` is a marker trait (a trait with no API) that promises implementors are + safe to send (move) to another thread. +* `Sync` is a marker trait that promises threads can safely share implementors + through a shared reference. + +Much of the Rust standard library also uses Unsafe Rust internally, although +these implementations are rigorously manually checked, and the Safe Rust +interfaces provided on top of these implementations can be assumed to be safe. + +The need for all of this separation boils down a single fundamental property +of Safe Rust: + +**No matter what, Safe Rust can't cause Undefined Behavior.** + +The design of the safe/unsafe split means that Safe Rust inherently has to +trust that any Unsafe Rust it touches has been written correctly (meaning +the Unsafe Rust actually maintains whatever contracts it is supposed to +maintain). On the other hand, Unsafe Rust has to be very careful about +trusting Safe Rust. + +As an example, Rust has the `PartialOrd` and `Ord` traits to differentiate +between types which can "just" be compared, and those that provide a total +ordering (where every value of the type is either equal to, greater than, +or less than any other value of the same type). The sorted map type +`BTreeMap` doesn't make sense for partially-ordered types, and so it +requires that any key type for it implements the `Ord` trait. However, +`BTreeMap` has Unsafe Rust code inside of its implementation, and this +Unsafe Rust code cannot assume that any `Ord` implementation it gets makes +sense. The unsafe portions of `BTreeMap`'s internals have to be careful to +maintain all necessary contracts, even if a key type's `Ord` implementation +does not implement a total ordering. + +Unsafe Rust cannot automatically trust Safe Rust. When writing Unsafe Rust, +you must be careful to only rely on specific Safe Rust code, and not make +assumptions about potential future Safe Rust code providing the same +guarantees. + +This is the problem that `unsafe` traits exist to resolve. The `BTreeMap` +type could theoretically require that keys implement a new trait called +`UnsafeOrd`, rather than `Ord`, that might look like this: ```rust -# use std::cmp::Ordering; -# struct MyType; -# unsafe trait UnsafeOrd { fn cmp(&self, other: &Self) -> Ordering; } -unsafe impl UnsafeOrd for MyType { - fn cmp(&self, other: &Self) -> Ordering { - Ordering::Equal - } +use std::cmp::Ordering; + +unsafe trait UnsafeOrd { + fn cmp(&self, other: &Self) -> Ordering; } ``` -But it's probably not the implementation you want. - -Rust has traditionally avoided making traits unsafe because it makes Unsafe -pervasive, which is not desirable. The reason Send and Sync are unsafe is because thread -safety is a *fundamental property* that unsafe code cannot possibly hope to defend -against in the same way it would defend against a bad Ord implementation. The -only way to possibly defend against thread-unsafety would be to *not use -threading at all*. Making every load and store atomic isn't even sufficient, -because it's possible for complex invariants to exist between disjoint locations -in memory. For instance, the pointer and capacity of a Vec must be in sync. - -Even concurrent paradigms that are traditionally regarded as Totally Safe like -message passing implicitly rely on some notion of thread safety -- are you -really message-passing if you pass a pointer? Send and Sync therefore require -some fundamental level of trust that Safe code can't provide, so they must be -unsafe to implement. To help obviate the pervasive unsafety that this would -introduce, Send (resp. Sync) is automatically derived for all types composed only -of Send (resp. Sync) values. 99% of types are Send and Sync, and 99% of those -never actually say it (the remaining 1% is overwhelmingly synchronization -primitives). - - - +Then, a type would use `unsafe` to implement `UnsafeOrd`, indicating that +they've ensured their implementation maintains whatever contracts the +trait expects. In this situation, the Unsafe Rust in the internals of +`BTreeMap` could trust that the key type's `UnsafeOrd` implementation is +correct. If it isn't, it's the fault of the unsafe trait implementation +code, which is consistent with Rust's safety guarantees. + +The decision of whether to mark a trait `unsafe` is an API design choice. +Rust has traditionally avoided marking traits unsafe because it makes Unsafe +Rust pervasive, which is not desirable. `Send` and `Sync` are marked unsafe +because thread safety is a *fundamental property* that unsafe code can't +possibly hope to defend against in the way it could defend against a bad +`Ord` implementation. The decision of whether to mark your own traits `unsafe` +depends on the same sort of consideration. If `unsafe` code cannot reasonably +expect to defend against a bad implementation of the trait, then marking the +trait `unsafe` is a reasonable choice. + +As an aside, while `Send` and `Sync` are `unsafe` traits, they are +automatically implemented for types when such derivations are provably safe +to do. `Send` is automatically derived for all types composed only of values +whose types also implement `Send`. `Sync` is automatically derived for all +types composed only of values whose types also implement `Sync`. + +This is the dance of Safe Rust and Unsafe Rust. It is designed to make using +Safe Rust as ergonomic as possible, but requires extra effort and care when +writing Unsafe Rust. The rest of the book is largely a discussion of the sort +of care that must be taken, and what contracts it is expected of Unsafe Rust +to uphold. [drop flags]: drop-flags.html [conversions]: conversions.html + diff --git a/nomicon/send-and-sync.md b/nomicon/send-and-sync.md index 134e47f..ecc4e53 100644 --- a/nomicon/send-and-sync.md +++ b/nomicon/send-and-sync.md @@ -1,7 +1,7 @@ -% Send and Sync +# Send and Sync Not everything obeys inherited mutability, though. Some types allow you to -multiply alias a location in memory while mutating it. Unless these types use +have multiple aliases of a location in memory while mutating it. Unless these types use synchronization to manage this access, they are absolutely not thread safe. Rust captures this through the `Send` and `Sync` traits. diff --git a/nomicon/subtyping.md b/nomicon/subtyping.md index eb940e8..d771712 100644 --- a/nomicon/subtyping.md +++ b/nomicon/subtyping.md @@ -1,4 +1,4 @@ -% Subtyping and Variance +# Subtyping and Variance Although Rust doesn't have any notion of structural inheritance, it *does* include subtyping. In Rust, subtyping derives entirely from lifetimes. Since diff --git a/nomicon/transmutes.md b/nomicon/transmutes.md index f1478b7..043c8fe 100644 --- a/nomicon/transmutes.md +++ b/nomicon/transmutes.md @@ -1,4 +1,4 @@ -% Transmutes +# Transmutes Get out of our way type system! We're going to reinterpret these bits or die trying! Even though this book is all about doing things that are unsafe, I diff --git a/nomicon/unbounded-lifetimes.md b/nomicon/unbounded-lifetimes.md index 1f2961b..b41cf8b 100644 --- a/nomicon/unbounded-lifetimes.md +++ b/nomicon/unbounded-lifetimes.md @@ -1,4 +1,4 @@ -% Unbounded Lifetimes +# Unbounded Lifetimes Unsafe code can often end up producing references or lifetimes out of thin air. Such lifetimes come into the world as *unbounded*. The most common source of this @@ -11,7 +11,7 @@ lifetime can be regarded as `'static`. Almost no reference is `'static`, so this is probably wrong. `transmute` and `transmute_copy` are the two other primary offenders. One should endeavor to -bound an unbounded lifetime as quick as possible, especially across function +bound an unbounded lifetime as quickly as possible, especially across function boundaries. Given a function, any output lifetimes that don't derive from inputs are diff --git a/nomicon/unchecked-uninit.md b/nomicon/unchecked-uninit.md index c72ed8a..ef31a35 100644 --- a/nomicon/unchecked-uninit.md +++ b/nomicon/unchecked-uninit.md @@ -1,4 +1,4 @@ -% Unchecked Uninitialized Memory +# Unchecked Uninitialized Memory One interesting exception to this rule is working with arrays. Safe Rust doesn't permit you to partially initialize an array. When you initialize an array, you diff --git a/nomicon/uninitialized.md b/nomicon/uninitialized.md index 05615d8..eafc679 100644 --- a/nomicon/uninitialized.md +++ b/nomicon/uninitialized.md @@ -1,4 +1,4 @@ -% Working With Uninitialized Memory +# Working With Uninitialized Memory All runtime-allocated memory in a Rust program begins its life as *uninitialized*. In this state the value of the memory is an indeterminate pile diff --git a/nomicon/unwinding.md b/nomicon/unwinding.md index e81f06b..6dc396d 100644 --- a/nomicon/unwinding.md +++ b/nomicon/unwinding.md @@ -1,4 +1,4 @@ -% Unwinding +# Unwinding Rust has a *tiered* error-handling scheme: diff --git a/nomicon/vec-alloc.md b/nomicon/vec-alloc.md index bc60a57..349cb50 100644 --- a/nomicon/vec-alloc.md +++ b/nomicon/vec-alloc.md @@ -1,4 +1,4 @@ -% Allocating Memory +# Allocating Memory Using Unique throws a wrench in an important feature of Vec (and indeed all of the std collections): an empty Vec doesn't actually allocate at all. So if we @@ -7,16 +7,12 @@ can't allocate, but also can't put a null pointer in `ptr`, what do we do in This is perfectly fine because we already have `cap == 0` as our sentinel for no allocation. We don't even need to handle it specially in almost any code because -we usually need to check if `cap > len` or `len > 0` anyway. The traditional -Rust value to put here is `0x01`. The standard library actually exposes this -as `alloc::heap::EMPTY`. There are quite a few places where we'll -want to use `heap::EMPTY` because there's no real allocation to talk about but +we usually need to check if `cap > len` or `len > 0` anyway. The recommended +Rust value to put here is `mem::align_of::()`. Unique provides a convenience +for this: `Unique::empty()`. There are quite a few places where we'll +want to use `empty` because there's no real allocation to talk about but `null` would make the compiler do bad things. -All of the `heap` API is totally unstable under the `heap_api` feature, though. -We could trivially define `heap::EMPTY` ourselves, but we'll want the rest of -the `heap` API anyway, so let's just get that dependency over with. - So: ```rust,ignore @@ -24,16 +20,10 @@ So: use std::mem; -use alloc::heap::EMPTY; - impl Vec { fn new() -> Self { assert!(mem::size_of::() != 0, "We're not ready to handle ZSTs"); - unsafe { - // need to cast EMPTY to the actual ptr type we want, let - // inference handle it. - Vec { ptr: Unique::new(heap::EMPTY as *mut _), len: 0, cap: 0 } - } + Vec { ptr: Unique::empty(), len: 0, cap: 0 } } } ``` @@ -202,7 +192,7 @@ fn grow(&mut self) { "capacity overflow"); let new_num_bytes = old_num_bytes * 2; - let ptr = heap::reallocate(*self.ptr as *mut _, + let ptr = heap::reallocate(self.ptr.as_ptr() as *mut _, old_num_bytes, new_num_bytes, align); diff --git a/nomicon/vec-dealloc.md b/nomicon/vec-dealloc.md index 706fe68..2f1b0b5 100644 --- a/nomicon/vec-dealloc.md +++ b/nomicon/vec-dealloc.md @@ -1,4 +1,4 @@ -% Deallocating +# Deallocating Next we should implement Drop so that we don't massively leak tons of resources. The easiest way is to just call `pop` until it yields None, and then deallocate @@ -21,7 +21,7 @@ impl Drop for Vec { let elem_size = mem::size_of::(); let num_bytes = elem_size * self.cap; unsafe { - heap::deallocate(*self.ptr as *mut _, num_bytes, align); + heap::deallocate(self.ptr.as_ptr() as *mut _, num_bytes, align); } } } diff --git a/nomicon/vec-deref.md b/nomicon/vec-deref.md index 6460eab..1000909 100644 --- a/nomicon/vec-deref.md +++ b/nomicon/vec-deref.md @@ -1,4 +1,4 @@ -% Deref +# Deref Alright! We've got a decent minimal stack implemented. We can push, we can pop, and we can clean up after ourselves. However there's a whole mess of @@ -18,7 +18,7 @@ impl Deref for Vec { type Target = [T]; fn deref(&self) -> &[T] { unsafe { - ::std::slice::from_raw_parts(*self.ptr, self.len) + ::std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) } } } @@ -32,7 +32,7 @@ use std::ops::DerefMut; impl DerefMut for Vec { fn deref_mut(&mut self) -> &mut [T] { unsafe { - ::std::slice::from_raw_parts_mut(*self.ptr, self.len) + ::std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) } } } diff --git a/nomicon/vec-drain.md b/nomicon/vec-drain.md index 6e732ee..5bd2bf0 100644 --- a/nomicon/vec-drain.md +++ b/nomicon/vec-drain.md @@ -1,4 +1,4 @@ -% Drain +# Drain Let's move on to Drain. Drain is largely the same as IntoIter, except that instead of consuming the Vec, it borrows the Vec and leaves its allocation diff --git a/nomicon/vec-final.md b/nomicon/vec-final.md index 1f4377a..cfea0d6 100644 --- a/nomicon/vec-final.md +++ b/nomicon/vec-final.md @@ -1,4 +1,4 @@ -% The Final Code +# The Final Code ```rust #![feature(unique)] @@ -20,13 +20,11 @@ struct RawVec { impl RawVec { fn new() -> Self { - unsafe { - // !0 is usize::MAX. This branch should be stripped at compile time. - let cap = if mem::size_of::() == 0 { !0 } else { 0 }; + // !0 is usize::MAX. This branch should be stripped at compile time. + let cap = if mem::size_of::() == 0 { !0 } else { 0 }; - // heap::EMPTY doubles as "unallocated" and "zero-sized allocation" - RawVec { ptr: Unique::new(heap::EMPTY as *mut T), cap: cap } - } + // Unique::empty() doubles as "unallocated" and "zero-sized allocation" + RawVec { ptr: Unique::empty(), cap: cap } } fn grow(&mut self) { @@ -44,7 +42,7 @@ impl RawVec { (1, ptr) } else { let new_cap = 2 * self.cap; - let ptr = heap::reallocate(*self.ptr as *mut _, + let ptr = heap::reallocate(self.ptr.as_ptr() as *mut _, self.cap * elem_size, new_cap * elem_size, align); @@ -68,7 +66,7 @@ impl Drop for RawVec { let num_bytes = elem_size * self.cap; unsafe { - heap::deallocate(*self.ptr as *mut _, num_bytes, align); + heap::deallocate(self.ptr.as_ptr() as *mut _, num_bytes, align); } } } @@ -84,7 +82,7 @@ pub struct Vec { } impl Vec { - fn ptr(&self) -> *mut T { *self.buf.ptr } + fn ptr(&self) -> *mut T { self.buf.ptr.as_ptr() } fn cap(&self) -> usize { self.buf.cap } diff --git a/nomicon/vec-insert-remove.md b/nomicon/vec-insert-remove.md index bcecd78..2c14bc4 100644 --- a/nomicon/vec-insert-remove.md +++ b/nomicon/vec-insert-remove.md @@ -1,4 +1,4 @@ -% Insert and Remove +# Insert and Remove Something *not* provided by slice is `insert` and `remove`, so let's do those next. diff --git a/nomicon/vec-into-iter.md b/nomicon/vec-into-iter.md index ebb0a79..df36757 100644 --- a/nomicon/vec-into-iter.md +++ b/nomicon/vec-into-iter.md @@ -1,4 +1,4 @@ -% IntoIter +# IntoIter Let's move on to writing iterators. `iter` and `iter_mut` have already been written for us thanks to The Magic of Deref. However there's two interesting @@ -139,7 +139,7 @@ impl Drop for IntoIter { let elem_size = mem::size_of::(); let num_bytes = elem_size * self.cap; unsafe { - heap::deallocate(*self.buf as *mut _, num_bytes, align); + heap::deallocate(self.buf.as_ptr() as *mut _, num_bytes, align); } } } diff --git a/nomicon/vec-layout.md b/nomicon/vec-layout.md index 7ca369d..795f1ac 100644 --- a/nomicon/vec-layout.md +++ b/nomicon/vec-layout.md @@ -1,4 +1,4 @@ -% Layout +# Layout First off, we need to come up with the struct layout. A Vec has three parts: a pointer to the allocation, the size of the allocation, and the number of @@ -32,7 +32,6 @@ As a recap, Unique is a wrapper around a raw pointer that declares that: * We are variant over `T` * We may own a value of type `T` (for drop check) * We are Send/Sync if `T` is Send/Sync -* We deref to `*mut T` (so it largely acts like a `*mut` in our code) * Our pointer is never null (so `Option>` is null-pointer-optimized) We can implement all of the above requirements except for the last @@ -57,17 +56,12 @@ impl Unique { pub fn new(ptr: *mut T) -> Self { Unique { ptr: ptr, _marker: PhantomData } } -} -impl Deref for Unique { - type Target = *mut T; - fn deref(&self) -> &*mut T { - // There's no way to cast the *const to a *mut - // while also taking a reference. So we just - // transmute it since it's all "just pointers". - unsafe { mem::transmute(&self.ptr) } + pub fn as_ptr(&self) -> *mut T { + self.ptr as *mut T } } + # fn main() {} ``` @@ -92,7 +86,7 @@ pub struct Vec { If you don't care about the null-pointer optimization, then you can use the stable code. However we will be designing the rest of the code around enabling -the optimization. In particular, `Unique::new` is unsafe to call, because +this optimization. It should be noted that `Unique::new` is unsafe to call, because putting `null` inside of it is Undefined Behavior. Our stable Unique doesn't need `new` to be unsafe because it doesn't make any interesting guarantees about its contents. diff --git a/nomicon/vec-push-pop.md b/nomicon/vec-push-pop.md index 5e747a8..d31a74c 100644 --- a/nomicon/vec-push-pop.md +++ b/nomicon/vec-push-pop.md @@ -1,4 +1,4 @@ -% Push and Pop +# Push and Pop Alright. We can initialize. We can allocate. Let's actually implement some functionality! Let's start with `push`. All it needs to do is check if we're diff --git a/nomicon/vec-raw.md b/nomicon/vec-raw.md index 8f78462..ad24b61 100644 --- a/nomicon/vec-raw.md +++ b/nomicon/vec-raw.md @@ -1,4 +1,5 @@ -% RawVec + +# RawVec We've actually reached an interesting situation here: we've duplicated the logic for specifying a buffer and freeing its memory in Vec and IntoIter. Now that @@ -17,9 +18,7 @@ struct RawVec { impl RawVec { fn new() -> Self { assert!(mem::size_of::() != 0, "TODO: implement ZST support"); - unsafe { - RawVec { ptr: Unique::new(heap::EMPTY as *mut T), cap: 0 } - } + RawVec { ptr: Unique::empty(), cap: 0 } } // unchanged from Vec @@ -33,7 +32,7 @@ impl RawVec { (1, ptr) } else { let new_cap = 2 * self.cap; - let ptr = heap::reallocate(*self.ptr as *mut _, + let ptr = heap::reallocate(self.ptr.as_ptr() as *mut _, self.cap * elem_size, new_cap * elem_size, align); @@ -57,7 +56,7 @@ impl Drop for RawVec { let elem_size = mem::size_of::(); let num_bytes = elem_size * self.cap; unsafe { - heap::deallocate(*self.ptr as *mut _, num_bytes, align); + heap::deallocate(self.ptr.as_mut() as *mut _, num_bytes, align); } } } @@ -73,7 +72,7 @@ pub struct Vec { } impl Vec { - fn ptr(&self) -> *mut T { *self.buf.ptr } + fn ptr(&self) -> *mut T { self.buf.ptr.as_ptr() } fn cap(&self) -> usize { self.buf.cap } diff --git a/nomicon/vec-zsts.md b/nomicon/vec-zsts.md index 5f3b2a8..7334404 100644 --- a/nomicon/vec-zsts.md +++ b/nomicon/vec-zsts.md @@ -1,4 +1,4 @@ -% Handling Zero-Sized Types +# Handling Zero-Sized Types It's time. We're going to fight the specter that is zero-sized types. Safe Rust *never* needs to care about this, but Vec is very intensive on raw pointers and @@ -19,7 +19,7 @@ RawValIter and RawVec respectively. How mysteriously convenient. ## Allocating Zero-Sized Types So if the allocator API doesn't support zero-sized allocations, what on earth -do we store as our allocation? Why, `heap::EMPTY` of course! Almost every operation +do we store as our allocation? `Unique::empty()` of course! Almost every operation with a ZST is a no-op since ZSTs have exactly one value, and therefore no state needs to be considered to store or load them. This actually extends to `ptr::read` and `ptr::write`: they won't actually look at the pointer at all. As such we never need @@ -35,13 +35,11 @@ method of RawVec. ```rust,ignore impl RawVec { fn new() -> Self { - unsafe { - // !0 is usize::MAX. This branch should be stripped at compile time. - let cap = if mem::size_of::() == 0 { !0 } else { 0 }; + // !0 is usize::MAX. This branch should be stripped at compile time. + let cap = if mem::size_of::() == 0 { !0 } else { 0 }; - // heap::EMPTY doubles as "unallocated" and "zero-sized allocation" - RawVec { ptr: Unique::new(heap::EMPTY as *mut T), cap: cap } - } + // Unique::empty() doubles as "unallocated" and "zero-sized allocation" + RawVec { ptr: Unique::empty(), cap: cap } } fn grow(&mut self) { @@ -59,7 +57,7 @@ impl RawVec { (1, ptr) } else { let new_cap = 2 * self.cap; - let ptr = heap::reallocate(*self.ptr as *mut _, + let ptr = heap::reallocate(self.ptr.as_ptr() as *mut _, self.cap * elem_size, new_cap * elem_size, align); @@ -85,7 +83,7 @@ impl Drop for RawVec { let num_bytes = elem_size * self.cap; unsafe { - heap::deallocate(*self.ptr as *mut _, num_bytes, align); + heap::deallocate(self.ptr.as_ptr() as *mut _, num_bytes, align); } } } diff --git a/nomicon/vec.md b/nomicon/vec.md index 6913019..ad98e45 100644 --- a/nomicon/vec.md +++ b/nomicon/vec.md @@ -1,4 +1,4 @@ -% Example: Implementing Vec +# Example: Implementing Vec To bring everything together, we're going to write `std::Vec` from scratch. Because all the best tools for writing unsafe code are unstable, this diff --git a/nomicon/working-with-unsafe.md b/nomicon/working-with-unsafe.md index b20dff7..5724f3d 100644 --- a/nomicon/working-with-unsafe.md +++ b/nomicon/working-with-unsafe.md @@ -1,4 +1,4 @@ -% Working with Unsafe +# Working with Unsafe Rust generally only gives us the tools to talk about Unsafe Rust in a scoped and binary manner. Unfortunately, reality is significantly more complicated than From 7fb6b47b916ebdc4533071537194be3e7003ae41 Mon Sep 17 00:00:00 2001 From: Nick Hahn Date: Tue, 23 May 2017 19:38:46 +0200 Subject: [PATCH 3/3] Update build date --- src/convert_book/options.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/convert_book/options.rs b/src/convert_book/options.rs index f04e857..46bb297 100644 --- a/src/convert_book/options.rs +++ b/src/convert_book/options.rs @@ -1,4 +1,4 @@ -pub const RELEASE_DATE: &'static str = "2016-10-01"; +pub const RELEASE_DATE: &'static str = "2017-05-23"; pub const MARKDOWN: &'static str = "markdown+grid_tables+pipe_tables-simple_tables+raw_html+implicit_figures+footnotes+intraword_underscores+auto_identifiers-inline_code_attributes";