From 51a1e83cb064484260110609834f8ecbc8f3f9a8 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 8 May 2015 13:18:04 -0700 Subject: [PATCH 01/26] doc: Remove mention of 30 minute intro --- src/doc/index.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/doc/index.md b/src/doc/index.md index 5a437e959b7fb..355297685a169 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -5,15 +5,14 @@ to jump to any particular section. # Getting Started -If you haven't seen Rust at all yet, the first thing you should read is the [30 -minute intro](intro.html). It will give you an overview of the basic ideas of Rust -at a high level. - -Once you know you really want to learn Rust, the next step is reading [The -Rust Programming Language](book/index.html). It is a lengthy explanation of -Rust, its syntax, and its concepts. Upon completing the book, you'll be an -intermediate Rust developer, and will have a good grasp of the fundamental -ideas behind Rust. +If you haven't seen Rust at all yet, the first thing you should read is the +introduction to [The Rust Programming Language](book/index.html). It'll give +you a good idea of what Rust is like. + +The book provides a lengthy explanation of Rust, its syntax, and its +concepts. Upon completing the book, you'll be an intermediate Rust +developer, and will have a good grasp of the fundamental ideas behind +Rust. [Rust By Example][rbe] was originally a community resource, but was then donated to the Rust project. As the name implies, it teaches you Rust through a From 9b3d315fff2e7009d3ebd945bb848c4afa2ebfb4 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 8 May 2015 15:15:03 -0700 Subject: [PATCH 02/26] std: Update crate docs Attempted to organize them in a way more relevant to what newbies would be interested in hearing. --- src/libstd/lib.rs | 98 +++++++++++++++++++-------------------- src/libstd/prelude/mod.rs | 2 +- src/libstd/prelude/v1.rs | 2 +- 3 files changed, 49 insertions(+), 53 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 6a84c6ace47b4..1b99b2989370a 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -12,33 +12,35 @@ //! //! The Rust Standard Library provides the essential runtime //! functionality for building portable Rust software. -//! It is linked to all Rust crates by default. //! -//! ## Intrinsic types and operations +//! It is linked to all Rust crates by default as though they +//! contained a crate-level `extern crate std` crate import. Therefore +//! the standard library can be accessed in `use` statements through +//! the path `std`, as in `use std::thread`, or in expressions through +//! the absolute path `::std`, as in `::std::thread::sleep_ms(100)`. //! -//! The [`ptr`](ptr/index.html) and [`mem`](mem/index.html) -//! modules deal with unsafe pointers and memory manipulation. -//! [`marker`](marker/index.html) defines the special built-in traits, -//! and [`raw`](raw/index.html) the runtime representation of Rust types. -//! These are some of the lowest-level building blocks in Rust. +//! Furthermore, the standard library defines [The Rust +//! Prelude](prelude/index.html), a small collection of items, mostly +//! traits, that are imported into and available in every module. //! -//! ## Math on primitive types and math traits +//! ## What is in the standard library //! -//! Although basic operations on primitive types are implemented -//! directly by the compiler, the standard library additionally -//! defines many common operations through traits defined in -//! mod [`num`](num/index.html). +//! The standard library is minimal, a set of battle-tested +//! core types and shared abstractions for the [broader Rust +//! ecosystem][https://crates.io] to build on. //! -//! ## Pervasive types +//! The [primitive types](#primitives), though not defined in the +//! standard library, are documented here, as are the predefined +//! [macros](#macros). //! -//! The [`option`](option/index.html) and [`result`](result/index.html) -//! modules define optional and error-handling types, `Option` and `Result`. -//! [`iter`](iter/index.html) defines Rust's iterator protocol -//! along with a wide variety of iterators. -//! [`Cell` and `RefCell`](cell/index.html) are for creating types that -//! manage their own mutability. +//! ## Containers and collections //! -//! ## Vectors, slices and strings +//! The [`option`](option/index.html) and +//! [`result`](result/index.html) modules define optional and +//! error-handling types, `Option` and `Result`. The +//! [`iter`](iter/index.html) module defines Rust's iterator trait, +//! [`Iterater`](iter/trait.Iterator.html), which works with the `for` +//! loop to access collections. //! //! The common container type, `Vec`, a growable vector backed by an array, //! lives in the [`vec`](vec/index.html) module. Contiguous, unsized regions @@ -56,42 +58,36 @@ //! macro, and for converting from strings use the //! [`FromStr`](str/trait.FromStr.html) trait. //! -//! ## Platform abstractions +//! Data may be shared by placing it a reference-counted box, the +//! [`Rc`][rc/index.html] type, and if further contained in a [`Cell` +//! or `RefCell`](cell/index.html), may be mutated as well as shared. +//! Likewise, in a concurrent setting it is common to pair an +//! atomically-reference-counted box, [`Arc`](sync/struct.Arc.html), +//! with a [`Mutex`](sync/struct.Mutex.html) to get the same effect. //! -//! Besides basic data types, the standard library is largely concerned -//! with abstracting over differences in common platforms, most notably -//! Windows and Unix derivatives. The [`os`](os/index.html) module -//! provides a number of basic functions for interacting with the -//! operating environment, including program arguments, environment -//! variables, and directory navigation. The [`path`](path/index.html) -//! module encapsulates the platform-specific rules for dealing -//! with file paths. -//! -//! `std` also includes the [`ffi`](ffi/index.html) module for interoperating -//! with the C language. -//! -//! ## Concurrency, I/O, and the runtime +//! The [`collections`](collections/index.html) module defines maps, +//! sets, linked lists and other typical collection types, including +//! the common [`HashMap`](collections/struct.HashMap.html). //! -//! The [`thread`](thread/index.html) module contains Rust's threading abstractions. -//! [`sync`](sync/index.html) contains further, primitive, shared memory types, -//! including [`atomic`](sync/atomic/index.html), and [`mpsc`](sync/mpsc/index.html), -//! which contains the channel types for message passing. +//! ## Platform abstractions and I/O //! -//! Common types of I/O, including files, TCP, UDP, pipes, Unix domain sockets, and -//! process spawning, are defined in the [`io`](io/index.html) module. -//! -//! Rust's I/O and concurrency depends on a small runtime interface -//! that lives, along with its support code, in mod [`rt`](rt/index.html). -//! While a notable part of the standard library's architecture, this -//! module is not intended for public use. +//! Besides basic data types, the standard library is largely concerned +//! with abstracting over differences in common platforms, most notably +//! Windows and Unix derivatives. //! -//! ## The Rust prelude and macros +//! Common types of I/O, including [files](fs/struct.File.html), +//! [TCP](net/struct.TcpStream.html), +//! [UDP](net/struct.UdpSocket.html), are defined in the +//! [`io`](io/index.html), [`fs`](fs/index.html), and +//! [`net`](net/index.html) modulesu. //! -//! Finally, the [`prelude`](prelude/index.html) defines a -//! common set of traits, types, and functions that are made available -//! to all code by default. [`macros`](macros/index.html) contains -//! all the standard macros, such as `assert!`, `panic!`, `println!`, -//! and `format!`, also available to all Rust code. +//! The [`thread`](thread/index.html) module contains Rust's threading +//! abstractions. [`sync`](sync/index.html) contains further, +//! primitive, shared memory types, including +//! [`atomic`](sync/atomic/index.html), and +//! [`mpsc`](sync/mpsc/index.html), which contains the channel types +//! for message passing. + // Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364) #![cfg_attr(stage0, feature(custom_attribute))] #![crate_name = "std"] diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs index 09fa10dacf98c..7bfe1cdd7294d 100644 --- a/src/libstd/prelude/mod.rs +++ b/src/libstd/prelude/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The Rust prelude +//! The Rust Prelude //! //! Because `std` is required by most serious Rust software, it is //! imported at the topmost level of every crate by default, as if the diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index 6dc11c505a914..46c0103e08764 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The first version of the prelude of the standard library. +//! The first version of the prelude of The Rust Standard Library. #![stable(feature = "rust1", since = "1.0.0")] From 7d9e605b93eb3ac359b3470dce829ed8432012d1 Mon Sep 17 00:00:00 2001 From: Ricardo Martins Date: Sun, 10 May 2015 10:43:30 +0100 Subject: [PATCH 03/26] Add error explanation for E0317. --- src/librustc_resolve/diagnostics.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index a896bd311698c..3e7ee714ea9f9 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -10,6 +10,24 @@ #![allow(non_snake_case)] +// Error messages for EXXXX errors. +// Each message should start and end with a new line, and be wrapped to 80 characters. +// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. +register_long_diagnostics! { + +E0317: r##" +User-defined types or type parameters cannot shadow the primitive types. +This error indicates you tried to define a type, struct or enum with the same +name as an existing primitive type, and is therefore invalid. + +See the Types section of the reference for more information about the primitive +types: + +http://doc.rust-lang.org/nightly/reference.html#types +"## + +} + register_diagnostics! { E0154, E0157, @@ -24,7 +42,6 @@ register_diagnostics! { E0258, // import conflicts with existing submodule E0259, // an extern crate has already been imported into this module E0260, // name conflicts with an external crate that has been imported into this module - E0317, // user-defined types or type parameters cannot shadow the primitive types E0364, // item is private E0365 // item is private } From c0412bcad69d95e217211bf6be925802004e4b17 Mon Sep 17 00:00:00 2001 From: Ricardo Martins Date: Sun, 10 May 2015 12:16:33 +0100 Subject: [PATCH 04/26] Fix documentation URL in diagnostic message. --- src/librustc_resolve/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 3e7ee714ea9f9..dd867d676ed2f 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -23,7 +23,7 @@ name as an existing primitive type, and is therefore invalid. See the Types section of the reference for more information about the primitive types: -http://doc.rust-lang.org/nightly/reference.html#types +http://doc.rust-lang.org/reference.html#types "## } From f3a3684614c0baf01e2d22e662b67e6a1408b718 Mon Sep 17 00:00:00 2001 From: Ricardo Martins Date: Sun, 10 May 2015 11:40:43 +0100 Subject: [PATCH 05/26] Add error explanation for E0154. --- src/librustc_resolve/diagnostics.rs | 33 ++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index dd867d676ed2f..4b754913bd9fb 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -15,6 +15,38 @@ // In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. register_long_diagnostics! { +E0154: r##" +Imports (`use` statements) are not allowed after non-item statements, such as +variable declarations and expression statements. + +Wrong example: +``` +fn f() { + // Variable declaration before import + let x = 0; + use std::io::Read; + ... +} +``` + +The solution is to declare the imports at the top of the block, function, or +file. + +Here is the previous example again, with the correct order: +``` +fn f() { + use std::io::Read; + let x = 0; + ... +} +``` + +See the Declaration Statements section of the reference for more information +about what constitutes an Item declaration and what does not: + +http://doc.rust-lang.org/reference.html#statements +"##, + E0317: r##" User-defined types or type parameters cannot shadow the primitive types. This error indicates you tried to define a type, struct or enum with the same @@ -29,7 +61,6 @@ http://doc.rust-lang.org/reference.html#types } register_diagnostics! { - E0154, E0157, E0153, E0251, // a named type or value has already been imported in this module From e7fa00a3e24f094012f878945bef8a62df1678c1 Mon Sep 17 00:00:00 2001 From: Ricardo Martins Date: Sun, 10 May 2015 12:09:41 +0100 Subject: [PATCH 06/26] Add error explanation for E0259. --- src/librustc_resolve/diagnostics.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 4b754913bd9fb..47f9b024fd051 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -47,6 +47,26 @@ about what constitutes an Item declaration and what does not: http://doc.rust-lang.org/reference.html#statements "##, +E0259: r##" +The name chosen for an external crate conflicts with another external crate that +has been imported into the current module. + +Wrong example: +``` +extern a; +extern crate_a as a; +``` + +The solution is to choose a different name that doesn't conflict with any +external crate imported into the current module. + +Correct example: +``` +extern a; +extern crate_a as other_name; +``` +"##, + E0317: r##" User-defined types or type parameters cannot shadow the primitive types. This error indicates you tried to define a type, struct or enum with the same @@ -71,7 +91,6 @@ register_diagnostics! { E0256, // import conflicts with type in this module E0257, // inherent implementations are only allowed on types defined in the current module E0258, // import conflicts with existing submodule - E0259, // an extern crate has already been imported into this module E0260, // name conflicts with an external crate that has been imported into this module E0364, // item is private E0365 // item is private From 60ec4ab220385be1ad2aef237733d7f38c2196b3 Mon Sep 17 00:00:00 2001 From: Ricardo Martins Date: Sun, 10 May 2015 12:26:19 +0100 Subject: [PATCH 07/26] Add error explanation for E0260. --- src/librustc_resolve/diagnostics.rs | 35 ++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 47f9b024fd051..5f0b5af9a0532 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -67,6 +67,40 @@ extern crate_a as other_name; ``` "##, +E0260: r##" +The name for an item declaration conflicts with an external crate's name. + +For instance, +``` +extern abc; + +struct abc; +``` + +There are two possible solutions: + +Solution #1: Rename the item. + +``` +extern abc; + +struct xyz; +``` + +Solution #2: Import the crate with a different name. + +``` +extern abc as xyz; + +struct abc; +``` + +See the Declaration Statements section of the reference for more information +about what constitutes an Item declaration and what does not: + +http://doc.rust-lang.org/reference.html#statements +"##, + E0317: r##" User-defined types or type parameters cannot shadow the primitive types. This error indicates you tried to define a type, struct or enum with the same @@ -91,7 +125,6 @@ register_diagnostics! { E0256, // import conflicts with type in this module E0257, // inherent implementations are only allowed on types defined in the current module E0258, // import conflicts with existing submodule - E0260, // name conflicts with an external crate that has been imported into this module E0364, // item is private E0365 // item is private } From bff170786cd99bfca7669430fdcc0889a01d2906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Czardybon?= Date: Fri, 8 May 2015 22:15:14 +0200 Subject: [PATCH 08/26] Fixed one textual mistake and one casing error. Corrected "Ownership": - [`Variable bindings`] link was not processed properly. - Changed the paragraph about move semantics with two vectors, because it was confusing. - Removed "So it may not be as inefficient as it initially seems", because there is nothing that seems inefficient in copying pointers only. - Other text corrections. Fixed copied-and-pasted text mistakes. Revised the paragraph about moving a vector (taking into account suggestions by echochamber). Fixed markdown. Fixes requested by steveklabnik. Brought back a sentence about supposed inefficiency. --- src/doc/trpl/lifetimes.md | 2 +- src/doc/trpl/ownership.md | 28 ++++++++++++------------ src/doc/trpl/references-and-borrowing.md | 4 ++-- src/doc/trpl/while-loops.md | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/doc/trpl/lifetimes.md b/src/doc/trpl/lifetimes.md index 86164a08a430f..25d5122b4e49e 100644 --- a/src/doc/trpl/lifetimes.md +++ b/src/doc/trpl/lifetimes.md @@ -5,7 +5,7 @@ Rust’s most unique and compelling features, with which Rust developers should become quite acquainted. Ownership is how Rust achieves its largest goal, memory safety. There are a few distinct concepts, each with its own chapter: -* [ownership][ownership], ownership, the key concept +* [ownership][ownership], the key concept * [borrowing][borrowing], and their associated feature ‘references’ * lifetimes, which you’re reading now diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index 971bb7cd700db..b210f1c643f43 100644 --- a/src/doc/trpl/ownership.md +++ b/src/doc/trpl/ownership.md @@ -6,7 +6,7 @@ become quite acquainted. Ownership is how Rust achieves its largest goal, memory safety. There are a few distinct concepts, each with its own chapter: -* ownership, which you’re reading now. +* ownership, which you’re reading now * [borrowing][borrowing], and their associated feature ‘references’ * [lifetimes][lifetimes], an advanced concept of borrowing @@ -23,7 +23,7 @@ Before we get to the details, two important notes about the ownership system. Rust has a focus on safety and speed. It accomplishes these goals through many ‘zero-cost abstractions’, which means that in Rust, abstractions cost as little as possible in order to make them work. The ownership system is a prime example -of a zero cost abstraction. All of the analysis we’ll talk about in this guide +of a zero-cost abstraction. All of the analysis we’ll talk about in this guide is _done at compile time_. You do not pay any run-time cost for any of these features. @@ -41,7 +41,7 @@ With that in mind, let’s learn about ownership. # Ownership -[`Variable bindings`][bindings] have a property in Rust: they ‘have ownership’ +[Variable bindings][bindings] have a property in Rust: they ‘have ownership’ of what they’re bound to. This means that when a binding goes out of scope, the resource that they’re bound to are freed. For example: @@ -106,8 +106,8 @@ take(v); println!("v[0] is: {}", v[0]); ``` -Same error: “use of moved value.” When we transfer ownership to something else, -we say that we’ve ‘moved’ the thing we refer to. You don’t need some sort of +Same error: ‘use of moved value’. When we transfer ownership to something else, +we say that we’ve ‘moved’ the thing we refer to. You don’t need any sort of special annotation here, it’s the default thing that Rust does. ## The details @@ -121,19 +121,19 @@ let v = vec![1, 2, 3]; let v2 = v; ``` -The first line creates some data for the vector on the [stack][sh], `v`. The -vector’s data, however, is stored on the [heap][sh], and so it contains a -pointer to that data. When we move `v` to `v2`, it creates a copy of that pointer, -for `v2`. Which would mean two pointers to the contents of the vector on the -heap. That would be a problem: it would violate Rust’s safety guarantees by -introducing a data race. Therefore, Rust forbids using `v` after we’ve done the -move. +The first line allocates memory for the vector object, `v`, and for the data it +contains. The vector object is stored on the [stack][sh] and contains a pointer +to the content (`[1, 2, 3]`) stored on the [heap][sh]. When we move `v` to `v2`, +it creates a copy of that pointer, for `v2`. Which means that there would be two +pointers to the content of the vector on the heap. It would violate Rust’s +safety guarantees by introducing a data race. Therefore, Rust forbids using `v` +after we’ve done the move. [sh]: the-stack-and-the-heap.html It’s also important to note that optimizations may remove the actual copy of -the bytes, depending on circumstances. So it may not be as inefficient as it -initially seems. +the bytes on the stack, depending on circumstances. So it may not be as +inefficient as it initially seems. ## `Copy` types diff --git a/src/doc/trpl/references-and-borrowing.md b/src/doc/trpl/references-and-borrowing.md index da416e994c4c5..c434371ce59d3 100644 --- a/src/doc/trpl/references-and-borrowing.md +++ b/src/doc/trpl/references-and-borrowing.md @@ -6,7 +6,7 @@ become quite acquainted. Ownership is how Rust achieves its largest goal, memory safety. There are a few distinct concepts, each with its own chapter: -* [ownership][ownership], ownership, the key concept +* [ownership][ownership], the key concept * borrowing, which you’re reading now * [lifetimes][lifetimes], an advanced concept of borrowing @@ -368,4 +368,4 @@ statement 1 at 3:14 println!("{}", y); } -``` \ No newline at end of file +``` diff --git a/src/doc/trpl/while-loops.md b/src/doc/trpl/while-loops.md index f2e2f6b6f49a7..e71d2033f49ed 100644 --- a/src/doc/trpl/while-loops.md +++ b/src/doc/trpl/while-loops.md @@ -1,4 +1,4 @@ -% while loops +% while Loops Rust also has a `while` loop. It looks like this: From ef030555c67988878e1a68743da25b5107bd2787 Mon Sep 17 00:00:00 2001 From: Ricardo Martins Date: Mon, 11 May 2015 09:10:19 +0100 Subject: [PATCH 09/26] Improve wording in error explanation. --- src/librustc_resolve/diagnostics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 5f0b5af9a0532..2ac6ffdea2d65 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -19,7 +19,7 @@ E0154: r##" Imports (`use` statements) are not allowed after non-item statements, such as variable declarations and expression statements. -Wrong example: +Here is an example that demonstrates the error: ``` fn f() { // Variable declaration before import @@ -104,7 +104,7 @@ http://doc.rust-lang.org/reference.html#statements E0317: r##" User-defined types or type parameters cannot shadow the primitive types. This error indicates you tried to define a type, struct or enum with the same -name as an existing primitive type, and is therefore invalid. +name as an existing primitive type. See the Types section of the reference for more information about the primitive types: From aa529ef52e54039fcfaa8aa7914be4c581179497 Mon Sep 17 00:00:00 2001 From: Ricardo Martins Date: Mon, 11 May 2015 09:10:49 +0100 Subject: [PATCH 10/26] Add missing keyword in `extern crate` declarations. --- src/librustc_resolve/diagnostics.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 2ac6ffdea2d65..7e7af8006805d 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -53,8 +53,8 @@ has been imported into the current module. Wrong example: ``` -extern a; -extern crate_a as a; +extern crate a; +extern crate crate_a as a; ``` The solution is to choose a different name that doesn't conflict with any @@ -62,8 +62,8 @@ external crate imported into the current module. Correct example: ``` -extern a; -extern crate_a as other_name; +extern crate a; +extern crate crate_a as other_name; ``` "##, @@ -72,7 +72,7 @@ The name for an item declaration conflicts with an external crate's name. For instance, ``` -extern abc; +extern crate abc; struct abc; ``` @@ -82,7 +82,7 @@ There are two possible solutions: Solution #1: Rename the item. ``` -extern abc; +extern crate abc; struct xyz; ``` @@ -90,7 +90,7 @@ struct xyz; Solution #2: Import the crate with a different name. ``` -extern abc as xyz; +extern crate abc as xyz; struct abc; ``` From f6119f18d29cefab2e7e36daab033bf40f5c0fda Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 11 May 2015 15:05:57 -0700 Subject: [PATCH 11/26] Update rust-installer --- src/rust-installer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust-installer b/src/rust-installer index ebc6b04c29591..e54d4823d26cd 160000 --- a/src/rust-installer +++ b/src/rust-installer @@ -1 +1 @@ -Subproject commit ebc6b04c29591108d3f28e724b4b9b74cd1232e6 +Subproject commit e54d4823d26cdb3f98e5a1b17e1c257cd329aa61 From d13f765be8d202450bf106057e19d6bd57f51f6c Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 12 May 2015 00:33:22 -0400 Subject: [PATCH 12/26] Make mention of `if` more generic `if` can be a statement or also an expression. --- src/doc/trpl/primitive-types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/trpl/primitive-types.md b/src/doc/trpl/primitive-types.md index bb2bf028700d2..22483816769c3 100644 --- a/src/doc/trpl/primitive-types.md +++ b/src/doc/trpl/primitive-types.md @@ -15,7 +15,7 @@ let x = true; let y: bool = false; ``` -A common use of booleans is in [`if` statements][if]. +A common use of booleans is in [`if` conditionals][if]. [if]: if.html From 93c21c7bcad447fb4834d9013815ef44827328c9 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Tue, 12 May 2015 10:52:36 +0200 Subject: [PATCH 13/26] Correct claims about &T's Copyness. --- src/librustc_typeck/diagnostics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index ea872d1014425..f9565d528e89a 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -186,7 +186,7 @@ struct Foo<'a> { ``` This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this -differs from the behavior for `&T`, which is `Copy` when `T` is `Copy`). +differs from the behavior for `&T`, which is always `Copy`). "##, E0205: r##" @@ -216,7 +216,7 @@ enum Foo<'a> { ``` This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this -differs from the behavior for `&T`, which is `Copy` when `T` is `Copy`). +differs from the behavior for `&T`, which is always `Copy`). "##, E0206: r##" From a5cac55be451a32a5956339009c49ac4fcaaef5c Mon Sep 17 00:00:00 2001 From: Mike Sampson Date: Tue, 12 May 2015 19:57:09 +1000 Subject: [PATCH 14/26] Add wait and waitpid to libc. --- src/liblibc/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 55934da00a37c..69ab34fee5a1f 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -5722,6 +5722,9 @@ pub mod funcs { pub fn tcgetpgrp(fd: c_int) -> pid_t; pub fn ttyname(fd: c_int) -> *mut c_char; pub fn unlink(c: *const c_char) -> c_int; + pub fn wait(status: *const c_int) -> pid_t; + pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int) + -> pid_t; pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t; pub fn pread(fd: c_int, buf: *mut c_void, count: size_t, @@ -5773,6 +5776,9 @@ pub mod funcs { pub fn sysconf(name: c_int) -> c_long; pub fn ttyname(fd: c_int) -> *mut c_char; pub fn unlink(c: *const c_char) -> c_int; + pub fn wait(status: *const c_int) -> pid_t; + pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int) + -> pid_t; pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t; pub fn pread(fd: c_int, buf: *mut c_void, count: size_t, From 1d1570acc9ac9d76394da05f63fa7881b6492ab9 Mon Sep 17 00:00:00 2001 From: Johannes Oertel Date: Mon, 11 May 2015 22:51:31 +0200 Subject: [PATCH 15/26] Add regression test for #18075 Closes #18075. --- src/test/run-pass/issue-18075.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/test/run-pass/issue-18075.rs diff --git a/src/test/run-pass/issue-18075.rs b/src/test/run-pass/issue-18075.rs new file mode 100644 index 0000000000000..5f07ba2235fd5 --- /dev/null +++ b/src/test/run-pass/issue-18075.rs @@ -0,0 +1,16 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// exec-env:RUST_LOG=rustc::middle=debug + +fn main() { + let b = 1isize; + println!("{}", b); +} From 23300a39a1ceffdba4c4695fc2e527e47ea2c95d Mon Sep 17 00:00:00 2001 From: Johannes Oertel Date: Tue, 12 May 2015 11:02:47 +0200 Subject: [PATCH 16/26] Add regression test for #20413 Closes #20413. --- src/test/compile-fail/issue-20413.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/test/compile-fail/issue-20413.rs diff --git a/src/test/compile-fail/issue-20413.rs b/src/test/compile-fail/issue-20413.rs new file mode 100644 index 0000000000000..a48c03aa178c3 --- /dev/null +++ b/src/test/compile-fail/issue-20413.rs @@ -0,0 +1,25 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { + fn answer(self); +} + +struct NoData; +//~^ ERROR: parameter `T` is never used + +impl Foo for T where NoData: Foo { +//~^ ERROR: overflow evaluating the requirement + fn answer(self) { + let val: NoData = NoData; + } +} + +fn main() {} From 6faa8d6793e9136cbc2d852504f499144ddd1097 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 12 May 2015 21:21:26 +1000 Subject: [PATCH 17/26] Add a link to the error index to the main doc page. I also capitalised "The Standard Library" and neatened a few bits of grammar. Also fixed: `#[main]` inside one of the error descriptions. --- src/doc/index.md | 13 +++++++++---- src/librustc/diagnostics.rs | 4 ++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/doc/index.md b/src/doc/index.md index 5a437e959b7fb..85ee561801687 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -24,7 +24,7 @@ series of small examples. # Community & Getting Help If you need help with something, or just want to talk about Rust with others, -there's a few places you can do that: +there are a few places you can do that: The Rust IRC channels on [irc.mozilla.org](http://irc.mozilla.org/) are the fastest way to get help. @@ -59,7 +59,7 @@ the language in as much detail as possible is in [the reference](reference.html) # Tools -Rust's still a young language, so there isn't a ton of tooling yet, but the +Rust is still a young language, so there isn't a ton of tooling yet, but the tools we have are really nice. [Cargo](http://crates.io) is Rust's package manager, and its website contains @@ -69,16 +69,21 @@ lots of good documentation. # FAQs -There are questions that are asked quite often, and so we've made FAQs for them: +There are questions that are asked quite often, so we've made FAQs for them: * [Language Design FAQ](complement-design-faq.html) * [Language FAQ](complement-lang-faq.html) * [Project FAQ](complement-project-faq.html) * [How to submit a bug report](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports) -# The standard library +# The Standard Library We have [API documentation for the entire standard library](std/index.html). There's a list of crates on the left with more specific sections, or you can use the search bar at the top to search for something if you know its name. + +# The Error Index + +If you encounter an error while compiling your code you may be able to look it +up in the [Rust Compiler Error Index](error-index.html). diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 0f1e55544e1af..6690e6831afee 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -273,8 +273,8 @@ See also http://doc.rust-lang.org/book/unsafe.html E0137: r##" This error indicates that the compiler found multiple functions with the -#[main] attribute. This is an error because there must be a unique entry point -into a Rust program. +`#[main]` attribute. This is an error because there must be a unique entry +point into a Rust program. "##, E0152: r##" From e780fb270c5296a87ff9dc1442fc141f69e77fcd Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 30 Apr 2015 14:40:38 -0400 Subject: [PATCH 18/26] TRPL: Borrow and AsRef These two traits are commonly confused. As such, explain the difference. Fixes #24163 --- src/doc/trpl/SUMMARY.md | 1 + src/doc/trpl/borrow-and-asref.md | 93 ++++++++++++++++++++++++++++++++ src/libcollections/borrow.rs | 5 ++ src/libcore/convert.rs | 5 ++ 4 files changed, 104 insertions(+) create mode 100644 src/doc/trpl/borrow-and-asref.md diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index de7ded76280f6..3f97928a56e3f 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -15,6 +15,7 @@ * [Concurrency](concurrency.md) * [Error Handling](error-handling.md) * [FFI](ffi.md) + * [Borrow and AsRef](borrow-and-asref.md) * [Syntax and Semantics](syntax-and-semantics.md) * [Variable Bindings](variable-bindings.md) * [Functions](functions.md) diff --git a/src/doc/trpl/borrow-and-asref.md b/src/doc/trpl/borrow-and-asref.md new file mode 100644 index 0000000000000..f5f314f1c21d6 --- /dev/null +++ b/src/doc/trpl/borrow-and-asref.md @@ -0,0 +1,93 @@ +% 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 + +The `Borrow` trait is used when you’re writing a datastructure, 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`: + +```rust,ignore +fn get(&self, k: &Q) -> Option<&V> + where K: Borrow, + Q: Hash + Eq +``` + +[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: + +```rust,ignore +struct HashMap { +``` + +The `K` parameter is the type of _key_ the `HashMap` uses. So, looking at +the signature of `get()` again, we can use `get()` when the key implements +`Borrow`. That way, we can make a `HashMap` which uses `String` keys, +but use `&str`s when we’re searching: + +```rust +use std::collections::HashMap; + +let mut map = HashMap::new(); +map.insert("Foo".to_string(), 42); + +assert_eq!(map.get("Foo"), Some(&42)); +``` + +This is because the standard library has `impl Borrow for String`. + +For most types, when you want to take an owned or borrowed type, a `&T` is +enough. But one area where `Borrow` is effective is when there’s more than one +kind of borrowed value. Slices are an area where this is especially true: you +can have both an `&[T]` or a `&mut [T]`. If we wanted to accept both of these +types, `Borrow` is up for it: + +``` +use std::borrow::Borrow; +use std::fmt::Display; + +fn foo + Display>(a: T) { + println!("a is borrowed: {}", a); +} + +let mut i = 5; + +foo(&i); +foo(&mut i); +``` + +This will print out `a is borrowed: 5` twice. + +# AsRef + +The `AsRef` trait is a conversion trait. It’s used for converting some value to +a reference in generic code. Like this: + +```rust +let s = "Hello".to_string(); + +fn foo>(s: T) { + let slice = s.as_ref(); +} +``` + +# Which should I use? + +We can see how they’re kind of the same: they both deal with owned and borrowed +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 +equivalent ways, such as hashing and comparison. + +Choose `AsRef` when you want to convert something to a reference directly, and +you’re writing generic code. diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 7332bf4670ae5..a86a4b4215f23 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -37,6 +37,11 @@ use self::Cow::*; /// trait: if `T: Borrow`, then `&U` can be borrowed from `&T`. A given /// type can be borrowed as multiple different types. In particular, `Vec: /// Borrow>` and `Vec: Borrow<[T]>`. +/// +/// `Borrow` is very similar to, but different than, `AsRef`. See +/// [the book][book] for more. +/// +/// [book]: ../../book/borrow-and-asref.html #[stable(feature = "rust1", since = "1.0.0")] pub trait Borrow { /// Immutably borrows from an owned value. diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index da6ac6bd752bf..f6987c1966493 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -24,6 +24,11 @@ use marker::Sized; /// A cheap, reference-to-reference conversion. /// +/// `AsRef` is very similar to, but different than, `Borrow`. See +/// [the book][book] for more. +/// +/// [book]: ../../book/borrow-and-asref.html +/// /// # Examples /// /// Both `String` and `&str` implement `AsRef`: From a22b3270b8dd0c2d23cb420b07ad1feb9691db2d Mon Sep 17 00:00:00 2001 From: Shmuale Mark Date: Tue, 12 May 2015 10:47:14 -0400 Subject: [PATCH 19/26] book: typo fixes, wording improvements. The text in iterators.md wasn't wrong, but it read awkwardly to my ear. --- src/doc/trpl/enums.md | 3 ++- src/doc/trpl/error-handling.md | 2 +- src/doc/trpl/iterators.md | 6 +++--- src/doc/trpl/lifetimes.md | 2 +- src/doc/trpl/ownership.md | 2 +- src/doc/trpl/primitive-types.md | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/doc/trpl/enums.md b/src/doc/trpl/enums.md index 80ea25eb35ce9..dade9044fdbe8 100644 --- a/src/doc/trpl/enums.md +++ b/src/doc/trpl/enums.md @@ -56,7 +56,8 @@ Character::Digit(10); Hand::Digit; ``` -Both variants are named `Digit`, but since they’re scoped to the `enum` name, +Both variants are named `Digit`, but since they’re scoped to the `enum` name +there's no ambiguity. Not supporting these operations may seem rather limiting, but it’s a limitation which we can overcome. There are two ways: by implementing equality ourselves, diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index 95b39a660636a..b3689968b7fd1 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -204,7 +204,7 @@ Because these kinds of situations are relatively rare, use panics sparingly. In certain circumstances, even though a function may fail, we may want to treat it as a panic instead. For example, `io::stdin().read_line(&mut buffer)` returns -an `Result`, when there is an error reading the line. This allows us to +a `Result`, when there is an error reading the line. This allows us to handle and possibly recover from error. If we don't want to handle this error, and would rather just abort the program, diff --git a/src/doc/trpl/iterators.md b/src/doc/trpl/iterators.md index abb14a6020524..e0cc45c254b99 100644 --- a/src/doc/trpl/iterators.md +++ b/src/doc/trpl/iterators.md @@ -212,9 +212,9 @@ see why consumers matter. As we've said before, an iterator is something that we can call the `.next()` method on repeatedly, and it gives us a sequence of things. Because you need to call the method, this means that iterators -are *lazy* and don't need to generate all of the values upfront. -This code, for example, does not actually generate the numbers -`1-100`, and just creates a value that represents the sequence: +can be *lazy* and not generate all of the values upfront. This code, +for example, does not actually generate the numbers `1-100`, instead +creating a value that merely represents the sequence: ```rust let nums = 1..100; diff --git a/src/doc/trpl/lifetimes.md b/src/doc/trpl/lifetimes.md index 86164a08a430f..40def201dcc94 100644 --- a/src/doc/trpl/lifetimes.md +++ b/src/doc/trpl/lifetimes.md @@ -41,7 +41,7 @@ With that in mind, let’s learn about lifetimes. # Lifetimes Lending out a reference to a resource that someone else owns can be -complicated, however. For example, imagine this set of operations: +complicated. For example, imagine this set of operations: - I acquire a handle to some kind of resource. - I lend you a reference to the resource. diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index 971bb7cd700db..2dabfa917fbd0 100644 --- a/src/doc/trpl/ownership.md +++ b/src/doc/trpl/ownership.md @@ -108,7 +108,7 @@ println!("v[0] is: {}", v[0]); Same error: “use of moved value.” When we transfer ownership to something else, we say that we’ve ‘moved’ the thing we refer to. You don’t need some sort of -special annotation here, it’s the default thing that Rust does. +special annotation here; it’s the default thing that Rust does. ## The details diff --git a/src/doc/trpl/primitive-types.md b/src/doc/trpl/primitive-types.md index bb2bf028700d2..fc307413c5eff 100644 --- a/src/doc/trpl/primitive-types.md +++ b/src/doc/trpl/primitive-types.md @@ -82,7 +82,7 @@ Let’s go over them by category: Integer types come in two varieties: signed and unsigned. To understand the difference, let’s consider a number with four bits of size. A signed, four-bit number would let you store numbers from `-8` to `+7`. Signed numbers use -“two’s compliment representation”. An unsigned four bit number, since it does +“two’s complement representation”. An unsigned four bit number, since it does not need to store negatives, can store values from `0` to `+15`. Unsigned types use a `u` for their category, and signed types use `i`. The `i` From 393a37ecbd5fbeda49246dc7f3885af69130151a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 12 May 2015 12:02:39 -0400 Subject: [PATCH 20/26] Correct various small points, expand some sections, while avoiding too much detail. --- src/doc/reference.md | 203 ++++++++++++++++++++++++++++++++----------- 1 file changed, 151 insertions(+), 52 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 7501796227469..2ddec9ba424f2 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -426,12 +426,12 @@ x; x::y::z; ``` -Path components are usually [identifiers](#identifiers), but the trailing -component of a path may be an angle-bracket-enclosed list of type arguments. In -[expression](#expressions) context, the type argument list is given after a -final (`::`) namespace qualifier in order to disambiguate it from a relational -expression involving the less-than symbol (`<`). In type expression context, -the final namespace qualifier is omitted. +Path components are usually [identifiers](#identifiers), but they may +also include angle-bracket-enclosed lists of type arguments. In +[expression](#expressions) context, the type argument list is given +after a `::` namespace qualifier in order to disambiguate it from a +relational expression involving the less-than symbol (`<`). In type +expression context, the final namespace qualifier is omitted. Two examples of paths with type arguments: @@ -497,8 +497,9 @@ names, and invoked through a consistent syntax: `some_extension!(...)`. Users of `rustc` can define new syntax extensions in two ways: -* [Compiler plugins][plugin] can include arbitrary - Rust code that manipulates syntax trees at compile time. +* [Compiler plugins][plugin] can include arbitrary Rust code that + manipulates syntax trees at compile time. Note that the interface + for compiler plugins is considered highly unstable. * [Macros](book/macros.html) define new syntax in a higher-level, declarative way. @@ -560,14 +561,18 @@ Nested repetitions are allowed. The parser used by the macro system is reasonably powerful, but the parsing of Rust syntax is restricted in two ways: -1. The parser will always parse as much as possible. If it attempts to match - `$i:expr [ , ]` against `8 [ , ]`, it will attempt to parse `i` as an array - index operation and fail. Adding a separator can solve this problem. +1. Macro definitions are required to include suitable separators after parsing + expressions and other bits of the Rust grammar. This implies that + a macro definition like `$i:expr [ , ]` is not legal, because `[` could be part + of an expression. A macro definition like `$i:expr,` or `$i:expr;` would be legal, + however, because `,` and `;` are legal separators. See [RFC 550] for more information. 2. The parser must have eliminated all ambiguity by the time it reaches a `$` _name_ `:` _designator_. This requirement most often affects name-designator pairs when they occur at the beginning of, or immediately after, a `$(...)*`; requiring a distinctive token in front can solve the problem. +[RFC 550]: https://github.com/rust-lang/rfcs/blob/master/text/0550-macro-future-proofing.md + # Crates and source files Although Rust, like any other language, can be implemented by an interpreter as @@ -686,7 +691,8 @@ type arguments as a list of comma-separated types enclosed within angle brackets, in order to refer to the type-parameterized item. In practice, the type-inference system can usually infer such argument types from context. There are no general type-parametric types, only type-parametric items. That is, Rust -has no notion of type abstraction: there are no first-class "forall" types. +has no notion of type abstraction: there are no higher-ranked (or "forall") types +abstracted over other types, though higher-ranked types do exist for lifetimes. ### Modules @@ -732,6 +738,7 @@ mod vec; mod thread { // Load the `local_data` module from `thread/local_data.rs` + // or `thread/local_data/mod.rs`. mod local_data; } ``` @@ -1004,7 +1011,8 @@ the guarantee that these issues are never caused by safe code. * `&mut` and `&` follow LLVM’s scoped [noalias] model, except if the `&T` contains an `UnsafeCell`. Unsafe code must not violate these aliasing guarantees. -* Mutating an immutable value/reference without `UnsafeCell` +* Mutating non-mutable data (that is, data reached through a shared reference or + data owned by a `let` binding), unless that data is contained within an `UnsafeCell`. * Invoking undefined behavior via compiler intrinsics: * Indexing outside of the bounds of an object with `std::ptr::offset` (`offset` intrinsic), with @@ -1034,9 +1042,13 @@ be undesired. * Exiting without calling destructors * Sending signals * Accessing/modifying the file system -* Unsigned integer overflow (well-defined as wrapping) -* Signed integer overflow (well-defined as two’s complement representation - wrapping) +* Integer overflow + - Overflow is considered "unexpected" behavior and is always user-error, + unless the `wrapping` primitives are used. In non-optimized builds, the compiler + will insert debug checks that panic on overflow, but in optimized builds overflow + instead results in wrapped values. See [RFC 560] for the rationale and more details. + +[RFC 560]: https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md #### Diverging functions @@ -1310,11 +1322,26 @@ type of the value is not required to ascribe to `Sync`. ### Traits -A _trait_ describes a set of method types. +A _trait_ describes an abstract interface that types can +implement. This interface consists of associated items, which come in +three varieties: + +- functions +- constants +- types + +Associated functions whose first parameter is named `self` are called +methods and may be invoked using `.` notation (e.g., `x.foo()`). + +All traits define an implicit type parameter `Self` that refers to +"the type that is implementing this interface". Traits may also +contain additional type parameters. These type parameters (including +`Self`) may be constrained by other traits and so forth as usual. -Traits can include default implementations of methods, written in terms of some -unknown [`self` type](#self-types); the `self` type may either be completely -unspecified, or constrained by some other trait. +Trait bounds on `Self` are considered "supertraits". These are +required to be acyclic. Supertraits are somewhat different from other +constraints in that they affect what methods are available in the +vtable when the trait is used as a [trait object](#trait-objects). Traits are implemented for specific types through separate [implementations](#implementations). @@ -1359,15 +1386,18 @@ fn draw_twice(surface: Surface, sh: T) { } ``` -Traits also define an [trait object](#trait-objects) with the same name as the -trait. Values of this type are created by [casting](#type-cast-expressions) -pointer values (pointing to a type for which an implementation of the given -trait is in scope) to pointers to the trait name, used as a type. +Traits also define an [trait object](#trait-objects) with the same +name as the trait. Values of this type are created by coercing from a +pointer of some specific type to a pointer of trait type. For example, +`&T` could be coerced to `&Shape` if `T: Shape` holds (and similarly +for `Box`). This coercion can either be implicit or +[explicit](#type-cast-expressions). Here is an example of an explicit +coercion: ``` -# trait Shape { fn dummy(&self) { } } -# impl Shape for i32 { } -# let mycircle = 0i32; +trait Shape { } +impl Shape for i32 { } +let mycircle = 0i32; let myshape: Box = Box::new(mycircle) as Box; ``` @@ -2041,7 +2071,8 @@ The name `str_eq` has a special meaning to the Rust compiler, and the presence of this definition means that it will use this definition when generating calls to the string equality function. -A complete list of the built-in language items will be added in the future. +The set of language items is currently considered unstable. A complete +list of the built-in language items will be added in the future. ### Inline attributes @@ -2053,11 +2084,6 @@ The compiler automatically inlines functions based on internal heuristics. Incorrectly inlining functions can actually make the program slower, so it should be used with care. -Immutable statics are always considered inlineable unless marked with -`#[inline(never)]`. It is undefined whether two different inlineable statics -have the same memory address. In other words, the compiler is free to collapse -duplicate inlineable statics together. - `#[inline]` and `#[inline(always)]` always cause the function to be serialized into the crate metadata to allow cross-crate inlining. @@ -2259,10 +2285,6 @@ The currently implemented features of the reference compiler are: * `unboxed_closures` - Rust's new closure design, which is currently a work in progress feature with many known bugs. -* `unsafe_destructor` - Allows use of the `#[unsafe_destructor]` attribute, - which is considered wildly unsafe and will be - obsoleted by language improvements. - * `unsafe_no_drop_flag` - Allows use of the `#[unsafe_no_drop_flag]` attribute, which removes hidden flag added to a type that implements the `Drop` trait. The design for the @@ -2382,18 +2404,54 @@ expressions](#index-expressions) (`expr[expr]`), and [field references](#field-expressions) (`expr.f`). All other expressions are rvalues. The left operand of an [assignment](#assignment-expressions) or -[compound-assignment](#compound-assignment-expressions) expression is an lvalue -context, as is the single operand of a unary -[borrow](#unary-operator-expressions). All other expression contexts are -rvalue contexts. +[compound-assignment](#compound-assignment-expressions) expression is +an lvalue context, as is the single operand of a unary +[borrow](#unary-operator-expressions). The discriminant or subject of +a [match expression](#match-expressions) may be an lvalue context, if +ref bindings are made, but is otherwise an rvalue context. All other +expression contexts are rvalue contexts. When an lvalue is evaluated in an _lvalue context_, it denotes a memory location; when evaluated in an _rvalue context_, it denotes the value held _in_ that memory location. -When an rvalue is used in an lvalue context, a temporary un-named lvalue is -created and used instead. A temporary's lifetime equals the largest lifetime -of any reference that points to it. +##### Temporary lifetimes + +When an rvalue is used in an lvalue context, a temporary un-named +lvalue is created and used instead. The lifetime of temporary values +is typically the innermost enclosing statement; the tail expression of +a block is considered part of the statement that encloses the block. + +When a temporary rvalue is being created that is assigned into a `let` +declaration, however, the temporary is created with the lifetime of +the enclosing block instead, as using the enclosing statement (the +`let` declaration) would be a guaranteed error (since a pointer to the +temporary would be stored into a variable, but the temporary would be +freed before the variable could be used). The compiler uses simple +syntactic rules to decide which values are being assigned into a `let` +binding, and therefore deserve a longer temporary lifetime. + +Here are some examples: + +- `let x = foo(&temp())`. The expression `temp()` is an rvalue. As it + is being borrowed, a temporary is created which will be freed after + the innermost enclosing statement (the `let` declaration, in this case). +- `let x = temp().foo()`. This is the same as the previous example, + except that the value of `temp()` is being borrowed via autoref on a + method-call. Here we are assuming that `foo()` is an `&self` method + defined in some trait, say `Foo`. In other words, the expression + `temp().foo()` is equivalent to `Foo::foo(&temp())`. +- `let x = &temp()`. Here, the same temporary is being assigned into + `x`, rather than being passed as a parameter, and hence the + temporary's lifetime is considered to be the enclosing block. +- `let x = SomeStruct { foo: &temp() }`. As in the previous case, the + temporary is assigned into a struct which is then assigned into a + binding, and hence it is given the lifetime of the enclosing block. +- `let x = [ &temp() ]`. As in the previous case, the + temporary is assigned into an array which is then assigned into a + binding, and hence it is given the lifetime of the enclosing block. +- `let ref x = temp()`. In this case, the temporary is created using a ref binding, + but the result is the same: the lifetime is extended to the enclosing block. #### Moved and copied types @@ -2535,8 +2593,10 @@ A field access is an [lvalue](#lvalues,-rvalues-and-temporaries) referring to the value of that field. When the type providing the field inherits mutability, it can be [assigned](#assignment-expressions) to. -Also, if the type of the expression to the left of the dot is a pointer, it is -automatically dereferenced to make the field access possible. +Also, if the type of the expression to the left of the dot is a +pointer, it is automatically dereferenced as many times as necessary +to make the field access possible. In cases of ambiguity, we prefer +fewer autoderefs to more. ### Array expressions @@ -2577,6 +2637,11 @@ let arr = ["a", "b"]; arr[10]; // panics ``` +Also, if the type of the expression to the left of the brackets is a +pointer, it is automatically dereferenced as many times as necessary +to make the indexing possible. In cases of ambiguity, we prefer fewer +autoderefs to more. + ### Range expressions The `..` operator will construct an object of one of the `std::ops::Range` variants. @@ -2599,7 +2664,7 @@ assert_eq!(x,y); ### Unary operator expressions -Rust defines three unary operators. They are all written as prefix operators, +Rust defines the following unary operators. They are all written as prefix operators, before the expression they apply to. * `-` @@ -2613,11 +2678,20 @@ before the expression they apply to. implemented by the type and required for an outer expression that will or could mutate the dereference), and produces the result of dereferencing the `&` or `&mut` borrowed pointer returned from the overload method. - * `!` : Logical negation. On the boolean type, this flips between `true` and `false`. On integer types, this inverts the individual bits in the two's complement representation of the value. +* `&` and `&mut` + : Borrowing. When applied to an lvalue, these operators produce a + reference (pointer) to the lvalue. The lvalue is also placed into + a borrowed state for the duration of the reference. For a shared + borrow (`&`), this implies that the lvalue may not be mutated, but + it may be read or shared again. For a mutable borrow (`&mut`), the + lvalue may not be accessed in any way until the borrow expires. + If the `&` or `&mut` operators are applied to an rvalue, a + temporary value is created; the lifetime of this temporary value + is defined by [syntactic rules](#temporary-lifetimes). ### Binary operator expressions @@ -2727,6 +2801,13 @@ fn avg(v: &[f64]) -> f64 { } ``` +Some of the conversions which can be done through the `as` operator +can also be done implicitly at various points in the program, such as +argument passing and assignment to a `let` binding with an explicit +type. Implicit conversions are limited to "harmless" conversions that +do not lose information and which have minimal or no risk of +surprising side-effects on the dynamic execution semantics. + #### Assignment expressions An _assignment expression_ consists of an @@ -3348,6 +3429,22 @@ let bo: Binop = add; x = bo(5,7); ``` +#### Function types for specific items + +Internally to the compiler, there are also function types that are specific to a particular +function item. In the following snippet, for example, the internal types of the functions +`foo` and `bar` are different, despite the fact that they have the same signature: + +``` +fn foo() { } +fn bar() { } +``` + +The types of `foo` and `bar` can both be implicitly coerced to the fn +pointer type `fn()`. There is currently no syntax for unique fn types, +though the compiler will emit a type like `fn() {foo}` in error +messages to indicate "the unique fn type for the function `foo`". + ### Closure types A [lambda expression](#lambda-expressions) produces a closure value with @@ -3432,8 +3529,9 @@ has type `Vec`, a vector with element type `A`. ### Self types -The special type `self` has a meaning within methods inside an impl item. It -refers to the type of the implicit `self` argument. For example, in: +The special type `Self` has a meaning within traits and impls. In a trait definition, it refers +to an implicit type parameter representing the "implementing" type. In an impl, +it is an alias for the implementing type. For example, in: ``` trait Printable { @@ -3447,8 +3545,9 @@ impl Printable for String { } ``` -`self` refers to the value of type `String` that is the receiver for a call to -the method `make_string`. +The notation `&self` is a shorthand for `self: &Self`. In this case, +in the impl, `Self` refers to the value of type `String` that is the +receiver for a call to the method `make_string`. # Special traits From 6f3701d604d604126c7e511c53cd05856dbc27fc Mon Sep 17 00:00:00 2001 From: Richo Healey Date: Mon, 11 May 2015 23:43:58 -0700 Subject: [PATCH 21/26] readme: Rework the arch support matrix --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f92fc653e0ef3..da59629b049f3 100644 --- a/README.md +++ b/README.md @@ -87,9 +87,11 @@ fetch snapshots, and an OS that can execute the available snapshot binaries. Snapshot binaries are currently built and tested on several platforms: -* Windows (7, 8, Server 2008 R2), x86 and x86-64 (64-bit support added in Rust 0.12.0) -* Linux (2.6.18 or later, various distributions), x86 and x86-64 -* OSX 10.7 (Lion) or greater, x86 and x86-64 +| Platform \ Architecture | x86 | x86_64 | +|--------------------------------|-----|--------| +| Windows (7, 8, Server 2008 R2) | ✓ | ✓ | +| Linux (2.6.18 or later) | ✓ | ✓ | +| OSX (10.7 Lion or later) | ✓ | ✓ | You may find that other platforms work, but these are our officially supported build environments that are most likely to work. From 6ebba71a75986271e537ab4363f905787a0a222a Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 12 May 2015 10:53:57 -0700 Subject: [PATCH 22/26] doc: Address feedback --- src/libstd/lib.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 1b99b2989370a..c0d8d8eacf797 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -13,11 +13,12 @@ //! The Rust Standard Library provides the essential runtime //! functionality for building portable Rust software. //! -//! It is linked to all Rust crates by default as though they -//! contained a crate-level `extern crate std` crate import. Therefore -//! the standard library can be accessed in `use` statements through -//! the path `std`, as in `use std::thread`, or in expressions through -//! the absolute path `::std`, as in `::std::thread::sleep_ms(100)`. +//! The rust standard library is available to all rust crates by +//! default, just as if contained an `extern crate std` import at the +//! crate root. Therefore the standard library can be accessed in +//! `use` statements through the path `std`, as in `use std::thread`, +//! or in expressions through the absolute path `::std`, as in +//! `::std::thread::sleep_ms(100)`. //! //! Furthermore, the standard library defines [The Rust //! Prelude](prelude/index.html), a small collection of items, mostly @@ -58,7 +59,7 @@ //! macro, and for converting from strings use the //! [`FromStr`](str/trait.FromStr.html) trait. //! -//! Data may be shared by placing it a reference-counted box, the +//! Data may be shared by placing it in a reference-counted box or the //! [`Rc`][rc/index.html] type, and if further contained in a [`Cell` //! or `RefCell`](cell/index.html), may be mutated as well as shared. //! Likewise, in a concurrent setting it is common to pair an @@ -79,12 +80,12 @@ //! [TCP](net/struct.TcpStream.html), //! [UDP](net/struct.UdpSocket.html), are defined in the //! [`io`](io/index.html), [`fs`](fs/index.html), and -//! [`net`](net/index.html) modulesu. +//! [`net`](net/index.html) modules. //! //! The [`thread`](thread/index.html) module contains Rust's threading -//! abstractions. [`sync`](sync/index.html) contains further, -//! primitive, shared memory types, including -//! [`atomic`](sync/atomic/index.html), and +//! abstractions. [`sync`](sync/index.html) contains further +//! primitive shared memory types, including +//! [`atomic`](sync/atomic/index.html) and //! [`mpsc`](sync/mpsc/index.html), which contains the channel types //! for message passing. From 0ad15bbc2b80a07e130a61a770e439256afa2e9a Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 7 May 2015 06:15:49 -0400 Subject: [PATCH 23/26] TRPL: release channels --- src/doc/trpl/SUMMARY.md | 1 + src/doc/trpl/release-channels.md | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/doc/trpl/release-channels.md diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index de7ded76280f6..fef61dcc70229 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -15,6 +15,7 @@ * [Concurrency](concurrency.md) * [Error Handling](error-handling.md) * [FFI](ffi.md) + * [Release Channels](release-channels.md) * [Syntax and Semantics](syntax-and-semantics.md) * [Variable Bindings](variable-bindings.md) * [Functions](functions.md) diff --git a/src/doc/trpl/release-channels.md b/src/doc/trpl/release-channels.md new file mode 100644 index 0000000000000..03e65539a2042 --- /dev/null +++ b/src/doc/trpl/release-channels.md @@ -0,0 +1,45 @@ +% 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 +your project should use. + +# Overview + +There are three channels for Rust releases: + +* Nightly +* Beta +* Stable + +New nightly releases are created once a day. Every six weeks, the latest +nightly release is promoted to ‘Beta’. At that point, it will only receive +patches to fix serious errors. Six weeks later, the beta is promoted to +‘Stable’, and becomes the next release of `1.x`. + +This process happens in parallel. So every six weeks, on the same day, +nightly goes to beta, beta goes to stable. When `1.x` is released, at +the same time, `1.(x + 1)-beta` is released, and the nightly becomes the +first version of `1.(x + 2)-nightly`. + +# Choosing a version + +Generally speaking, unless you have a specific reason, you should be using the +stable release channel. These releases are intended for a general audience. + +However, depending on your interest in Rust, you may choose to use nightly +instead. The basic tradeoff is this: in the nightly channel, you can use +unstable, new Rust features. However, unstable features are subject to change, +and so any new nightly release may break your code. If you use the stable +release, you cannot use experimental features, but the next release of Rust +will not cause significant issues through breaking changes. + +# Helping the ecosystem through CI + +What about beta? We encourage all Rust users who use the stable release channel +to also test against the beta channel in their continuous integration systems. +This will help alert the team in case there’s an accidental regression. + +Additionally, testing against nightly can catch regressions even sooner, and so +if you don’t mind a third build, we’d appreciate testing against all channels. + From 9a3e98be1c20781e566d12d14940c8dd3d237b15 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 11 May 2015 18:53:37 -0400 Subject: [PATCH 24/26] TRPL: Drop --- src/doc/trpl/drop.md | 68 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/src/doc/trpl/drop.md b/src/doc/trpl/drop.md index af58e23561c36..8bc25ef90d382 100644 --- a/src/doc/trpl/drop.md +++ b/src/doc/trpl/drop.md @@ -1,3 +1,67 @@ -% `Drop` +% Drop -Coming soon! +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 + +```rust +struct HasDrop; + +impl Drop for HasDrop { + fn drop(&mut self) { + println!("Dropping!"); + } +} + +fn main() { + let x = HasDrop; + + // do stuff + +} // x goes out of scope here +``` + +When `x` goes out of scope at the end of `main()`, the code for `Drop` will +run. `Drop` has one method, which is also called `drop()`. It takes a mutable +reference to `self`. + +That’s it! The mechanics of `Drop` are very simple, but there are some +subtleties. For example, values are dropped in the opposite order they are +declared. Here’s another example: + +```rust +struct Firework { + strength: i32, +} + +impl Drop for Firework { + fn drop(&mut self) { + println!("BOOM times {}!!!", self.strength); + } +} + +fn main() { + let firecracker = Firework { strength: 1 }; + let tnt = Firework { strength: 100 }; +} +``` + +This will output: + +```text +BOOM times 100!!! +BOOM times 1!!! +``` + +The TNT goes off before the firecracker does, because it was declared +afterwards. Last in, first out. + +So what is `Drop` good for? Generally, `Drop` is used to clean up any resources +associated with a `struct`. For example, the [`Arc` type][arc] is a +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 From fc6372ea1f3ab98ab1a0252843a93a7045e95849 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 12 May 2015 13:34:29 -0400 Subject: [PATCH 25/26] TRPL: Rust inside other languages --- src/doc/trpl/SUMMARY.md | 1 + src/doc/trpl/rust-inside-other-languages.md | 353 ++++++++++++++++++++ 2 files changed, 354 insertions(+) create mode 100644 src/doc/trpl/rust-inside-other-languages.md diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index de7ded76280f6..29ec66861f153 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -6,6 +6,7 @@ * [Hello, Cargo!](hello-cargo.md) * [Learn Rust](learn-rust.md) * [Guessing Game](guessing-game.md) + * [Rust inside other languages](rust-inside-other-languages.md) * [Effective Rust](effective-rust.md) * [The Stack and the Heap](the-stack-and-the-heap.md) * [Testing](testing.md) diff --git a/src/doc/trpl/rust-inside-other-languages.md b/src/doc/trpl/rust-inside-other-languages.md new file mode 100644 index 0000000000000..a1ae50a0c5396 --- /dev/null +++ b/src/doc/trpl/rust-inside-other-languages.md @@ -0,0 +1,353 @@ +% Rust Inside Other Languages + +For our third project, we’re going to choose something that shows off one of +Rust’s greatest strengths: a lack of a substantial runtime. + +As organizations grow, they increasingly rely on a multitude of programming +languages. Different programming languages have different strengths and +weaknesses, and a polyglot stack lets you use a particular language where +its strengths make sense, and use a different language where it’s weak. + +A very common area where many programming languages are weak is in runtime +performance of programs. Often, using a language that is slower, but offers +greater programmer productivity is a worthwhile trade-off. To help mitigate +this, they provide a way to write some of your system in C, and then call +the C code as though it were written in the higher-level language. This is +called a ‘foreign function interface’, often shortened to ‘FFI’. + +Rust has support for FFI in both directions: it can call into C code easily, +but crucially, it can also be called _into_ as easily as C. Combined with +Rust’s lack of a garbage collector and low runtime requirements, this makes +Rust a great candidate to embed inside of other languages when you need +some extra oomph. + +There is a whole [chapter devoted to FFI][ffi] and its specifics elsewhere in +the book, but in this chapter, we’ll examine this particular use-case of FFI, +with three examples, in Ruby, Python, and JavaScript. + +[ffi]: ffi.html + +# The problem + +There are many different projects we could choose here, but we’re going to +pick an example where Rust has a clear advantage over many other languages: +numeric computing and threading. + +Many languages, for the sake of consistency, place numbers on the heap, rather +than on the stack. Especially in languages that focus on object-oriented +programming and use garbage collection, heap allocation is the default. Sometimes +optimizations can stack allocate particular numbers, but rather than relying +on an optimizer to do its job, we may want to ensure that we’re always using +primitive number types rather than some sort of object type. + +Second, many languages have a ‘global interpreter lock’, which limits +concurrency in many situations. This is done in the name of safety, which is +a positive effect, but it limits the amount of work that can be done at the +same time, which is a big negative. + +To emphasize these two aspects, we’re going to create a little project that +uses these two aspects heavily. Since the focus of the example is the embedding +of Rust into the languages, rather than the problem itself, we’ll just use a +toy example: + +> Start ten threads. Inside each thread, count from one to five million. After +> All ten threads are finished, print out ‘done!’. + +I chose five million based on my particular computer. Here’s an example of this +code in Ruby: + +```ruby +threads = [] + +10.times do + threads << Thread.new do + count = 0 + + 5_000_000.times do + count += 1 + end + end +end + +threads.each {|t| t.join } +puts "done!" +``` + +Try running this example, and choose a number that runs for a few seconds. +Depending on your computer’s hardware, you may have to increase or decrease the +number. + +On my system, running this program takes `2.156` seconds. And, if I use some +sort of process monitoring tool, like `top`, I can see that it only uses one +core on my machine. That’s the GIL kicking in. + +While it’s true that this is a synthetic program, one can imagine many problems +that are similar to this in the real world. For our purposes, spinning up some +busy threads represents some sort of parallel, expensive computation. + +# A Rust library + +Let’s re-write this problem in Rust. First, let’s make a new project with +Cargo: + +```bash +$ cargo new embed +$ cd embed +``` + +This program is fairly easy to write in Rust: + +```rust +use std::thread; + +fn process() { + let handles: Vec<_> = (0..10).map(|_| { + thread::spawn(|| { + let mut _x = 0; + for _ in (0..5_000_001) { + _x += 1 + } + }) + }).collect(); + + for h in handles { + h.join().ok().expect("Could not join a thread!"); + } +} +``` + +Some of this should look familiar from previous examples. We spin up ten +threads, collecting them into a `handles` vector. Inside of each thread, we +loop five million times, and add one to `_x` each time. Why the underscore? +Well, if we remove it and compile: + +```bash +$ cargo build + Compiling embed v0.1.0 (file:///home/steve/src/embed) +src/lib.rs:3:1: 16:2 warning: function is never used: `process`, #[warn(dead_code)] on by default +src/lib.rs:3 fn process() { +src/lib.rs:4 let handles: Vec<_> = (0..10).map(|_| { +src/lib.rs:5 thread::spawn(|| { +src/lib.rs:6 let mut x = 0; +src/lib.rs:7 for _ in (0..5_000_001) { +src/lib.rs:8 x += 1 + ... +src/lib.rs:6:17: 6:22 warning: variable `x` is assigned to, but never used, #[warn(unused_variables)] on by default +src/lib.rs:6 let mut x = 0; + ^~~~~ +``` + +That first warning is because we are building a library. If we had a test +for this function, the warning would go away. But for now, it’s never +called. + +The second is related to `x` versus `_x`. Because we never actually _do_ +anything with `x`, we get a warning about it. In our case, that’s perfectly +okay, as we’re just trying to waste CPU cycles. Prefixing `x` with the +underscore removes the warning. + +Finally, we join on each thread. + +Right now, however, this is a Rust library, and it doesn’t expose anything +that’s callable from C. If we tried to hook this up to another language right +now, it wouldn’t work. We only need to make two small changes to fix this, +though. The first is modify the beginning of our code: + +```rust,ignore +#[no_mangle] +pub extern fn process() { +``` + +We have to add a new attribute, `no_mangle`. When you create a Rust library, it +changes the name of the function in the compiled output. The reasons for this +are outside the scope of this tutorial, but in order for other languages to +know how to call the function, we need to not do that. This attribute turns +that behavior off. + +The other change is the `pub extern`. The `pub` means that this function should +be callable from outside of this module, and the `extern` says that it should +be able to be called from C. That’s it! Not a whole lot of change. + +The second thing we need to do is to change a setting in our `Cargo.toml`. Add +this at the bottom: + +```toml +[lib] +name = "embed" +crate-type = ["dylib"] +``` + +This tells Rust that we want to compile our library into a standard dynamic +library. By default, Rust compiles into an ‘rlib’, a Rust-specific format. + +Let’s build the project now: + +```bash +$ cargo build --release + Compiling embed v0.1.0 (file:///home/steve/src/embed) +``` + +We’ve chosen `cargo build --release`, which builds with optimizations on. We +want this to be as fast as possible! You can find the output of the library in +`target/release`: + +```bash +$ ls target/release/ +build deps examples libembed.so native +``` + +That `libembed.so` is our ‘shared object’ library. We can use this file +just like any shared object library written in C! As an aside, this may be +`embed.dll` or `libembed.dylib`, depending on the platform. + +Now that we’ve got our Rust library built, let’s use it from our Ruby. + +# Ruby + +Open up a `embed.rb` file inside of our project, and do this: + +```ruby +require 'ffi' + +module Hello + extend FFI::Library + ffi_lib 'target/release/libembed.so' + attach_function :process, [], :void +end + +Hello.process + +puts "done!” +``` + +Before we can run this, we need to install the `ffi` gem: + +```bash +$ gem install ffi # this may need sudo +Fetching: ffi-1.9.8.gem (100%) +Building native extensions. This could take a while... +Successfully installed ffi-1.9.8 +Parsing documentation for ffi-1.9.8 +Installing ri documentation for ffi-1.9.8 +Done installing documentation for ffi after 0 seconds +1 gem installed +``` + +And finally, we can try running it: + +```bash +$ ruby embed.rb +done! +$ +``` + +Whoah, that was fast! On my system, this took `0.086` seconds, rather than +the two seconds the pure Ruby version took. Let’s break down this Ruby +code: + +```ruby +require 'ffi' +``` + +We first need to require the `ffi` gem. This lets us interface with our +Rust library like a C library. + +```ruby +module Hello + extend FFI::Library + ffi_lib 'target/release/libembed.so' +``` + +The `ffi` gem’s authors recommend using a module to scope the functions +we’ll import from the shared library. Inside, we `extend` the necessary +`FFI::Library` module, and then call `ffi_lib` to load up our shared +object library. We just pass it the path that our library is stored, +which as we saw before, is `target/release/libembed.so`. + +```ruby +attach_function :process, [], :void +``` + +The `attach_function` method is provided by the FFI gem. It’s what +connects our `process()` function in Rust to a Ruby function of the +same name. Since `process()` takes no arguments, the second parameter +is an empty array, and since it returns nothing, we pass `:void` as +the final argument. + +```ruby +Hello.process +``` + +This is the actual call into Rust. The combination of our `module` +and the call to `attach_function` sets this all up. It looks like +a Ruby function, but is actually Rust! + +```ruby +puts "done!" +``` + +Finally, as per our project’s requirements, we print out `done!`. + +That’s it! As we’ve seen, bridging between the two languages is really easy, +and buys us a lot of performance. + +Next, let’s try Python! + +# Python + +Create an `embed.py` file in this directory, and put this in it: + +```python +from ctypes import cdll + +lib = cdll.LoadLibrary("target/release/libembed.so") + +lib.process() + +print("done!") +``` + +Even easier! We use `cdll` from the `ctypes` module. A quick call +to `LoadLibrary` later, and we can call `process()`. + +On my system, this takes `0.017` seconds. Speedy! + +# Node.js + +Node isn’t a language, but it’s currently the dominant implementation of +server-side JavaScript. + +In order to do FFI with Node, we first need to install the library: + +```bash +$ npm install ffi +``` + +After that installs, we can use it: + +```javascript +var ffi = require('ffi'); + +var lib = ffi.Library('target/release/libembed', { + 'process': [ 'void', [] ] +}); + +lib.process(); + +console.log("done!"); +``` + +It looks more like the Ruby example than the Python example. We use +the `ffi` module to get access to `ffi.Library()`, which loads up +our shared object. We need to annotate the return type and argument +types of the function, which are 'void' for return, and an empty +array to signify no arguments. From there, we just call it and +print the result. + +On my system, this takes a quick `0.092` seconds. + +# Conclusion + +As you can see, the basics of doing this are _very_ easy. Of course, +there's a lot more that we could do here. Check out the [FFI][ffi] +chapter for more details. From 2ba61698ccb2c43ad1ea081988ef499735bfa62d Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 11 May 2015 18:21:49 -0400 Subject: [PATCH 26/26] TRPL: dining philosophers --- src/doc/trpl/SUMMARY.md | 1 + src/doc/trpl/dining-philosophers.md | 690 ++++++++++++++++++++++++++++ 2 files changed, 691 insertions(+) create mode 100644 src/doc/trpl/dining-philosophers.md diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index de7ded76280f6..4f099d1fd73e2 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -6,6 +6,7 @@ * [Hello, Cargo!](hello-cargo.md) * [Learn Rust](learn-rust.md) * [Guessing Game](guessing-game.md) + * [Dining Philosophers](dining-philosophers.md) * [Effective Rust](effective-rust.md) * [The Stack and the Heap](the-stack-and-the-heap.md) * [Testing](testing.md) diff --git a/src/doc/trpl/dining-philosophers.md b/src/doc/trpl/dining-philosophers.md new file mode 100644 index 0000000000000..b1bea4f819ef4 --- /dev/null +++ b/src/doc/trpl/dining-philosophers.md @@ -0,0 +1,690 @@ +% Dining Philosophers + +For our second project, let’s look at a classic concurrency problem. It’s +called ‘the dining philosophers’. It was originally conceived by Dijkstra in +1965, but we’ll use the version from [this paper][paper] by Tony Hoare in 1985. + +[paper]: http://www.usingcsp.com/cspbook.pdf + +> In ancient times, a wealthy philanthropist endowed a College to accommodate +> five eminent philosophers. Each philosopher had a room in which he could +> engage in his professional activity of thinking; there was also a common +> dining room, furnished with a circular table, surrounded by five chairs, each +> labelled by the name of the philosopher who was to sit in it. They sat +> anticlockwise around the table. To the left of each philosopher there was +> laid a golden fork, and in the centre stood a large bowl of spaghetti, which +> was constantly replenished. A philosopher was expected to spend most of his +> time thinking; but when he felt hungry, he went to the dining room, sat down +> in his own chair, picked up his own fork on his left, and plunged it into the +> spaghetti. But such is the tangled nature of spaghetti that a second fork is +> required to carry it to the mouth. The philosopher therefore had also to pick +> up the fork on his right. When we was finished he would put down both his +> forks, get up from his chair, and continue thinking. Of course, a fork can be +> used by only one philosopher at a time. If the other philosopher wants it, he +> just has to wait until the fork is available again. + +This classic problem shows off a few different elements of concurrency. The +reason is that it's actually slightly tricky to implement: a simple +implementation can deadlock. For example, let's consider a simple algorithm +that would solve this problem: + +1. A philosopher picks up the fork on their left. +2. They then pick up the fork on their right. +3. They eat. +4. They return the forks. + +Now, let’s imagine this sequence of events: + +1. Philosopher 1 begins the algorithm, picking up the fork on their left. +2. Philosopher 2 begins the algorithm, picking up the fork on their left. +3. Philosopher 3 begins the algorithm, picking up the fork on their left. +4. Philosopher 4 begins the algorithm, picking up the fork on their left. +5. Philosopher 5 begins the algorithm, picking up the fork on their left. +6. ... ? All the forks are taken, but nobody can eat! + +There are different ways to solve this problem. We’ll get to our solution in +the tutorial itself. For now, let’s get started modelling the problem itself. +We’ll start with the philosophers: + +```rust +struct Philosopher { + name: String, +} + +impl Philosopher { + fn new(name: &str) -> Philosopher { + Philosopher { + name: name.to_string(), + } + } +} + +fn main() { + let p1 = Philosopher::new("Baruch Spinoza"); + let p2 = Philosopher::new("Gilles Deleuze"); + let p3 = Philosopher::new("Karl Marx"); + let p4 = Philosopher::new("Friedrich Nietzsche"); + let p5 = Philosopher::new("Michel Foucault"); +} +``` + +Here, we make a [`struct`][struct] to represent a philosopher. For now, +a name is all we need. We choose the [`String`][string] type for the name, +rather than `&str`. Generally speaking, working with a type which owns its +data is easier than working with one that uses references. + +Let’s continue: + +```rust +# struct Philosopher { +# name: String, +# } +impl Philosopher { + fn new(name: &str) -> Philosopher { + Philosopher { + name: name.to_string(), + } + } +} +``` + +This `impl` block lets us define things on `Philosopher` structs. In this case, +we define an ‘associated function’ called `new`. The first line looks like this: + +```rust +# struct Philosopher { +# name: String, +# } +# impl Philosopher { +fn new(name: &str) -> Philosopher { +# Philosopher { +# name: name.to_string(), +# } +# } +# } +``` + +We take one argument, a `name`, of type `&str`. This is a reference to another +string. It returns an instance of our `Philosopher` struct. + +```rust +# struct Philosopher { +# name: String, +# } +# impl Philosopher { +# fn new(name: &str) -> Philosopher { +Philosopher { + name: name.to_string(), +} +# } +# } +``` + +This creates a new `Philosopher`, and sets its `name` to our `name` argument. +Not just the argument itself, though, as we call `.to_string()` on it. This +will create a copy of the string that our `&str` points to, and give us a new +`String`, which is the type of the `name` field of `Philosopher`. + +Why not accept a `String` directly? It’s nicer to call. If we took a `String`, +but our caller had a `&str`, they’d have to call this method themselves. The +downside of this flexibility is that we _always_ make a copy. For this small +program, that’s not particularly important, as we know we’ll just be using +short strings anyway. + +One last thing you’ll notice: we just define a `Philosopher`, and seemingly +don’t do anything with it. Rust is an ‘expression based’ language, which means +that almost everything in Rust is an expression which returns a value. This is +true of functions as well, the last expression is automatically returned. Since +we create a new `Philosopher` as the last expression of this function, we end +up returning it. + +This name, `new()`, isn’t anything special to Rust, but it is a convention for +functions that create new instances of structs. Before we talk about why, let’s +look at `main()` again: + +```rust +# struct Philosopher { +# name: String, +# } +# +# impl Philosopher { +# fn new(name: &str) -> Philosopher { +# Philosopher { +# name: name.to_string(), +# } +# } +# } +# +fn main() { + let p1 = Philosopher::new("Baruch Spinoza"); + let p2 = Philosopher::new("Gilles Deleuze"); + let p3 = Philosopher::new("Karl Marx"); + let p4 = Philosopher::new("Friedrich Nietzsche"); + let p5 = Philosopher::new("Michel Foucault"); +} +``` + +Here, we create five variable bindings with five new philosophers. These are my +favorite five, but you can substitute anyone you want. If we _didn’t_ define +that `new()` function, it would look like this: + +```rust +# struct Philosopher { +# name: String, +# } +fn main() { + let p1 = Philosopher { name: "Baruch Spinoza".to_string() }; + let p2 = Philosopher { name: "Gilles Deleuze".to_string() }; + let p3 = Philosopher { name: "Karl Marx".to_string() }; + let p4 = Philosopher { name: "Friedrich Nietzche".to_string() }; + let p5 = Philosopher { name: "Michel Foucault".to_string() }; +} +``` + +That’s much noisier. Using `new` has other advantages too, but even in +this simple case, it ends up being nicer to use. + +Now that we’ve got the basics in place, there’s a number of ways that we can +tackle the broader problem here. I like to start from the end first: let’s +set up a way for each philosopher to finish eating. As a tiny step, let’s make +a method, and then loop through all the philosophers, calling it: + +```rust +struct Philosopher { + name: String, +} + +impl Philosopher { + fn new(name: &str) -> Philosopher { + Philosopher { + name: name.to_string(), + } + } + + fn eat(&self) { + println!("{} is done eating.", self.name); + } +} + +fn main() { + let philosophers = vec![ + Philosopher::new("Baruch Spinoza"), + Philosopher::new("Gilles Deleuze"), + Philosopher::new("Karl Marx"), + Philosopher::new("Friedrich Nietzsche"), + Philosopher::new("Michel Foucault"), + ]; + + for p in &philosophers { + p.eat(); + } +} +``` + +Let’s look at `main()` first. Rather than have five individual variable +bindings for our philosophers, we make a `Vec` of them instead. `Vec` is +also called a ‘vector’, and it’s a growable array type. We then use a +[`for`][for] loop to iterate through the vector, getting a reference to each +philosopher in turn. + +[for]: for-loops.html + +In the body of the loop, we call `p.eat()`, which is defined above: + +```rust,ignore +fn eat(&self) { + println!("{} is done eating.", self.name); +} +``` + +In Rust, methods take an explicit `self` parameter. That’s why `eat()` is a +method, but `new` is an associated function: `new()` has no `self`. For our +first version of `eat()`, we just print out the name of the philosopher, and +mention they’re done eating. Running this program should give you the following +output: + +```text +Baruch Spinoza is done eating. +Gilles Deleuze is done eating. +Karl Marx is done eating. +Friedrich Nietzsche is done eating. +Michel Foucault is done eating. +``` + +Easy enough, they’re all done! We haven’t actually implemented the real problem +yet, though, so we’re not done yet! + +Next, we want to make our philosophers not just finish eating, but actually +eat. Here’s the next version: + +```rust +use std::thread; + +struct Philosopher { + name: String, +} + +impl Philosopher { + fn new(name: &str) -> Philosopher { + Philosopher { + name: name.to_string(), + } + } + + fn eat(&self) { + println!("{} is eating.", self.name); + + thread::sleep_ms(1000); + + println!("{} is done eating.", self.name); + } +} + +fn main() { + let philosophers = vec![ + Philosopher::new("Baruch Spinoza"), + Philosopher::new("Gilles Deleuze"), + Philosopher::new("Karl Marx"), + Philosopher::new("Friedrich Nietzsche"), + Philosopher::new("Michel Foucault"), + ]; + + for p in &philosophers { + p.eat(); + } +} +``` + +Just a few changes. Let’s break it down. + +```rust,ignore +use std::thread; +``` + +`use` brings names into scope. We’re going to start using the `thread` module +from the standard library, and so we need to `use` it. + +```rust,ignore + fn eat(&self) { + println!("{} is eating.", self.name); + + thread::sleep_ms(1000); + + println!("{} is done eating.", self.name); + } +``` + +We now print out two messages, with a `sleep_ms()` in the middle. This will +simulate the time it takes a philosopher to eat. + +If you run this program, You should see each philosopher eat in turn: + +```text +Baruch Spinoza is eating. +Baruch Spinoza is done eating. +Gilles Deleuze is eating. +Gilles Deleuze is done eating. +Karl Marx is eating. +Karl Marx is done eating. +Friedrich Nietzsche is eating. +Friedrich Nietzsche is done eating. +Michel Foucault is eating. +Michel Foucault is done eating. +``` + +Excellent! We’re getting there. There’s just one problem: we aren’t actually +operating in a concurrent fashion, which is a core part of the problem! + +To make our philosophers eat concurrently, we need to make a small change. +Here’s the next iteration: + +```rust +use std::thread; + +struct Philosopher { + name: String, +} + +impl Philosopher { + fn new(name: &str) -> Philosopher { + Philosopher { + name: name.to_string(), + } + } + + fn eat(&self) { + println!("{} is eating.", self.name); + + thread::sleep_ms(1000); + + println!("{} is done eating.", self.name); + } +} + +fn main() { + let philosophers = vec![ + Philosopher::new("Baruch Spinoza"), + Philosopher::new("Gilles Deleuze"), + Philosopher::new("Karl Marx"), + Philosopher::new("Friedrich Nietzsche"), + Philosopher::new("Michel Foucault"), + ]; + + let handles: Vec<_> = philosophers.into_iter().map(|p| { + thread::spawn(move || { + p.eat(); + }) + }).collect(); + + for h in handles { + h.join().unwrap(); + } +} +``` + +All we’ve done is change the loop in `main()`, and added a second one! Here’s the +first change: + +```rust,ignore +let handles: Vec<_> = philosophers.into_iter().map(|p| { + thread::spawn(move || { + p.eat(); + }) +}).collect(); +``` + +While this is only five lines, they’re a dense four. Let’s break it down. + +```rust,ignore +let handles: Vec<_> = +``` + +We introduce a new binding, called `handles`. We’ve given it this name because +we are going to make some new threads, and that will return some handles to those +threads that let us control their operation. We need to explicitly annotate +the type here, though, due to an issue we’ll talk about later. The `_` is +a type placeholder. We’re saying “`handles` is a vector of something, but you +can figure out what that something is, Rust.” + +```rust,ignore +philosophers.into_iter().map(|p| { +``` + +We take our list of philosophers and call `into_iter()` on it. This creates an +iterator that takes ownership of each philosopher. We need to do this to pass +them to our threads. We take that iterator and call `map` on it, which takes a +closure as an argument and calls that closure on each element in turn. + +```rust,ignore + thread::spawn(move || { + p.eat(); + }) +``` + +Here’s where the concurrency happens. The `thread::spawn` function takes a closure +as an argument and executes that closure in a new thread. This closure needs +an extra annotation, `move`, to indicate that the closure is going to take +ownership of the values it’s capturing. Primarily, the `p` variable of the +`map` function. + +Inside the thread, all we do is call `eat()` on `p`. + +```rust,ignore +}).collect(); +``` + +Finally, we take the result of all those `map` calls and collect them up. +`collect()` will make them into a collection of some kind, which is why we +needed to annotate the return type: we want a `Vec`. The elements are the +return values of the `thread::spawn` calls, which are handles to those threads. +Whew! + +```rust,ignore +for h in handles { + h.join().unwrap(); +} +``` + +At the end of `main()`, we loop through the handles and call `join()` on them, +which blocks execution until the thread has completed execution. This ensures +that the threads complete their work before the program exits. + +If you run this program, you’ll see that the philosophers eat out of order! +We have mult-threading! + +```text +Gilles Deleuze is eating. +Gilles Deleuze is done eating. +Friedrich Nietzsche is eating. +Friedrich Nietzsche is done eating. +Michel Foucault is eating. +Baruch Spinoza is eating. +Baruch Spinoza is done eating. +Karl Marx is eating. +Karl Marx is done eating. +Michel Foucault is done eating. +``` + +But what about the forks? We haven’t modeled them at all yet. + +To do that, let’s make a new `struct`: + +```rust +use std::sync::Mutex; + +struct Table { + forks: Vec>, +} +``` + +This `Table` has an vector of `Mutex`es. A mutex is a way to control +concurrency: only one thread can access the contents at once. This is exactly +the property we need with our forks. We use an empty tuple, `()`, inside the +mutex, since we’re not actually going to use the value, just hold onto it. + +Let’s modify the program to use the `Table`: + +```rust +use std::thread; +use std::sync::{Mutex, Arc}; + +struct Philosopher { + name: String, + left: usize, + right: usize, +} + +impl Philosopher { + fn new(name: &str, left: usize, right: usize) -> Philosopher { + Philosopher { + name: name.to_string(), + left: left, + right: right, + } + } + + fn eat(&self, table: &Table) { + let _left = table.forks[self.left].lock().unwrap(); + let _right = table.forks[self.right].lock().unwrap(); + + println!("{} is eating.", self.name); + + thread::sleep_ms(1000); + + println!("{} is done eating.", self.name); + } +} + +struct Table { + forks: Vec>, +} + +fn main() { + let table = Arc::new(Table { forks: vec![ + Mutex::new(()), + Mutex::new(()), + Mutex::new(()), + Mutex::new(()), + Mutex::new(()), + ]}); + + let philosophers = vec![ + Philosopher::new("Baruch Spinoza", 0, 1), + Philosopher::new("Gilles Deleuze", 1, 2), + Philosopher::new("Karl Marx", 2, 3), + Philosopher::new("Friedrich Nietzsche", 3, 4), + Philosopher::new("Michel Foucault", 0, 4), + ]; + + let handles: Vec<_> = philosophers.into_iter().map(|p| { + let table = table.clone(); + + thread::spawn(move || { + p.eat(&table); + }) + }).collect(); + + for h in handles { + h.join().unwrap(); + } +} +``` + +Lots of changes! However, with this iteration, we’ve got a working program. +Let’s go over the details: + +```rust,ignore +use std::sync::{Mutex, Arc}; +``` + +We’re going to use another structure from the `std::sync` package: `Arc`. +We’ll talk more about it when we use it. + +```rust,ignore +struct Philosopher { + name: String, + left: usize, + right: usize, +} +``` + +We need to add two more fields to our `Philosopher`. Each philosopher is going +to have two forks: the one on their left, and the one on their right. +We’ll use the `usize` type to indicate them, as it’s the type that you index +vectors with. These two values will be the indexes into the `forks` our `Table` +has. + +```rust,ignore +fn new(name: &str, left: usize, right: usize) -> Philosopher { + Philosopher { + name: name.to_string(), + left: left, + right: right, + } +} +``` + +We now need to construct those `left` and `right` values, so we add them to +`new()`. + +```rust,ignore +fn eat(&self, table: &Table) { + let _left = table.forks[self.left].lock().unwrap(); + let _right = table.forks[self.right].lock().unwrap(); + + println!("{} is eating.", self.name); + + thread::sleep_ms(1000); + + println!("{} is done eating.", self.name); +} +``` + +We have two new lines. We’ve also added an argument, `table`. We access the +`Table`’s list of forks, and then use `self.left` and `self.right` to access +the fork at that particular index. That gives us access to the `Mutex` at that +index, and we call `lock()` on it. If the mutex is currently being accessed by +someone else, we’ll block until it becomes available. + +The call to `lock()` might fail, and if it does, we want to crash. In this +case, the error that could happen is that the mutex is [‘poisoned’][poison], +which is what happens when the thread panics while the lock is held. Since this +shouldn’t happen, we just use `unwrap()`. + +[poison]: ../std/sync/struct.Mutex.html#poisoning + +One other odd thing about these lines: we’ve named the results `_left` and +`_right`. What’s up with that underscore? Well, we aren’t planning on +_using_ the value inside the lock. We just want to acquire it. As such, +Rust will warn us that we never use the value. By using the underscore, +we tell Rust that this is what we intended, and it won’t throw a warning. + +What about releasing the lock? Well, that will happen when `_left` and +`_right` go out of scope, automatically. + +```rust,ignore + let table = Arc::new(Table { forks: vec![ + Mutex::new(()), + Mutex::new(()), + Mutex::new(()), + Mutex::new(()), + Mutex::new(()), + ]}); +``` + +Next, in `main()`, we make a new `Table` and wrap it in an `Arc`. +‘arc’ stands for ‘atomic reference count’, and we need that to share +our `Table` across multiple threads. As we share it, the reference +count will go up, and when each thread ends, it will go back down. + + +```rust,ignore +let philosophers = vec![ + Philosopher::new("Baruch Spinoza", 0, 1), + Philosopher::new("Gilles Deleuze", 1, 2), + Philosopher::new("Karl Marx", 2, 3), + Philosopher::new("Friedrich Nietzsche", 3, 4), + Philosopher::new("Michel Foucault", 0, 4), +]; +``` + +We need to pass in our `left` and `right` values to the constructors for our +`Philosopher`s. But there’s one more detail here, and it’s _very_ important. If +you look at the pattern, it’s all consistent until the very end. Monsieur +Foucault should have `4, 0` as arguments, but instead, has `0, 4`. This is what +prevents deadlock, actually: one of our philosophers is left handed! This is +one way to solve the problem, and in my opinion, it’s the simplest. + +```rust,ignore +let handles: Vec<_> = philosophers.into_iter().map(|p| { + let table = table.clone(); + + thread::spawn(move || { + p.eat(&table); + }) +}).collect(); +``` + +Finally, inside of our `map()`/`collect()` loop, we call `table.clone()`. The +`clone()` method on `Arc` is what bumps up the reference count, and when it +goes out of scope, it decrements the count. You’ll notice we can introduce a +new binding to `table` here, and it will shadow the old one. This is often used +so that you don’t need to come up with two unique names. + +With this, our program works! Only two philosophers can eat at any one time, +and so you’ll get some output like this: + +```text +Gilles Deleuze is eating. +Friedrich Nietzsche is eating. +Friedrich Nietzsche is done eating. +Gilles Deleuze is done eating. +Baruch Spinoza is eating. +Karl Marx is eating. +Baruch Spinoza is done eating. +Michel Foucault is eating. +Karl Marx is done eating. +Michel Foucault is done eating. +``` + +Congrats! You’ve implemented a classic concurrency problem in Rust.