Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ fn main() {
process::exit(1);
});


if let Err(e) = run(config) {
eprintln!("Application error: {e}");
process::exit(1);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
There's no Rust code in here; just us Cargo.tomls.
6 changes: 3 additions & 3 deletions listings/ch19-patterns-and-matching/listing-19-29/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ fn main() {
let msg = Message::Hello { id: 5 };

match msg {
Message::Hello {
id: id @ 3..=7,
} => println!("Found an id in range: {id}"),
Message::Hello { id: id @ 3..=7 } => {
println!("Found an id in range: {id}")
}
Message::Hello { id: 10..=12 } => {
println!("Found an id in another range")
}
Expand Down
33 changes: 33 additions & 0 deletions listings/ch20-advanced-features/listing-20-07/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
$ cargo +nightly miri run
Compiling unsafe-example v0.1.0 (file:///projects/unsafe-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
Running `file:///home/.rustup/toolchains/nightly/bin/cargo-miri runner target/miri/debug/unsafe-example`
warning: integer-to-pointer cast
--> src/main.rs:5:13
|
5 | let r = address as *mut i32;
| ^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
|
= help: this program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program
= help: see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation
= help: to ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead
= help: you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics
= help: alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning
= note: BACKTRACE:
= note: inside `main` at src/main.rs:5:13: 5:32

error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 40000 bytes, but got 0x1234[noalloc] which is a dangling pointer (it has no provenance)
--> src/main.rs:7:35
|
7 | let values: &[i32] = unsafe { slice::from_raw_parts_mut(r, 10000) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `main` at src/main.rs:7:35: 7:70

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error; 1 warning emitted

2 changes: 1 addition & 1 deletion listings/ch20-advanced-features/listing-20-10/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
static HELLO_WORLD: &str = "Hello, world!";

fn main() {
println!("name is: {HELLO_WORLD}");
println!("value is: {HELLO_WORLD}");
}
5 changes: 0 additions & 5 deletions listings/ch20-advanced-features/listing-20-11/output.txt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ pub fn hello_macro_derive(input: TokenStream) -> TokenStream {

fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
let gen = quote! {
let generated = quote! {
impl HelloMacro for #name {
fn hello_macro() {
println!("Hello, Macro! My name is {}!", stringify!(#name));
}
}
};
gen.into()
generated.into()
}
730 changes: 427 additions & 303 deletions nostarch/chapter20.md

Large diffs are not rendered by default.

Binary file modified nostarch/docx/chapter20.docx
Binary file not shown.
2 changes: 1 addition & 1 deletion src/ch20-00-advanced-features.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Advanced Features

By now, you’ve learned the most commonly used parts of the Rust programming
language. Before we do one more project in Chapter 21, we’ll look at a few
language. Before we do one more project, in Chapter 21, we’ll look at a few
aspects of the language you might run into every once in a while, but may not
use every day. You can use this chapter as a reference for when you encounter
any unknowns. The features covered here are useful in very specific situations.
Expand Down
268 changes: 136 additions & 132 deletions src/ch20-01-unsafe-rust.md

Large diffs are not rendered by default.

84 changes: 44 additions & 40 deletions src/ch20-02-advanced-traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@ the concrete types of the generic type parameters each time. When we use the
indicate which implementation of `Iterator` we want to use.

With associated types, we don’t need to annotate types because we can’t
implement a trait on a type multiple times. In Listing 20-13 with the definition
that uses associated types, we can choose what the type of `Item` will be only
once, because there can be only one `impl Iterator for Counter`. We don’t have
to specify that we want an iterator of `u32` values everywhere that we call
`next` on `Counter`.
implement a trait on a type multiple times. In Listing 20-13 with the
definition that uses associated types, we can choose what the type of `Item`
will be only once because there can be only one `impl Iterator for Counter`. We
don’t have to specify that we want an iterator of `u32` values everywhere we
call `next` on `Counter`.

Associated types also become part of the trait’s contract: implementors of the
trait must provide a type to stand in for the associated type placeholder.
Expand Down Expand Up @@ -146,12 +146,12 @@ default.
We have two structs, `Millimeters` and `Meters`, holding values in different
units. This thin wrapping of an existing type in another struct is known as the
_newtype pattern_, which we describe in more detail in the [“Using the Newtype
Pattern to Implement External Traits on External Types”][newtype]<!-- ignore
Pattern to Implement External Traits”][newtype]<!-- ignore
--> section. We want to add values in millimeters to values in meters and have
the implementation of `Add` do the conversion correctly. We can implement `Add`
for `Millimeters` with `Meters` as the `Rhs`, as shown in Listing 20-16.

<Listing number="20-16" file-name="src/lib.rs" caption="Implementing the `Add` trait on `Millimeters` to add `Millimeters` to `Meters`">
<Listing number="20-16" file-name="src/lib.rs" caption="Implementing the `Add` trait on `Millimeters` to add `Millimeters` and `Meters`">

```rust,noplayground
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-16/src/lib.rs}}
Expand Down Expand Up @@ -196,7 +196,7 @@ want to use. Consider the code in Listing 20-17 where we’ve defined two traits
both traits on a type `Human` that already has a method named `fly` implemented
on it. Each `fly` method does something different.

<Listing number="20-17" file-name="src/main.rs" caption="Two traits are defined to have a ` method and are implemented on the `Human` type, and a `fly` method is implemented on `Human` directly.">
<Listing number="20-17" file-name="src/main.rs" caption="Two traits are defined to have a `fly` method and are implemented on the `Human` type, and a `fly` method is implemented on `Human` directly.">

```rust
{{#rustdoc_include ../listings/ch20-advanced-features/listing-20-17/src/main.rs:here}}
Expand Down Expand Up @@ -248,12 +248,12 @@ trait to use based on the type of `self`.

However, associated functions that are not methods don’t have a `self`
parameter. When there are multiple types or traits that define non-method
functions with the same function name, Rust doesn't always know which type you
mean unless you use _fully qualified syntax_. For example, in Listing 20-20 we
create a trait for an animal shelter that wants to name all baby dogs _Spot_.
We make an `Animal` trait with an associated non-method function `baby_name`.
The `Animal` trait is implemented for the struct `Dog`, on which we also
provide an associated non-method function `baby_name` directly.
functions with the same function name, Rust doesn’t always know which type you
mean unless you use fully qualified syntax. For example, in Listing 20-20 we
create a trait for an animal shelter that wants to name all baby dogs Spot. We
make an `Animal` trait with an associated non-method function `baby_name`. The
`Animal` trait is implemented for the struct `Dog`, on which we also provide an
associated non-method function `baby_name` directly.

<Listing number="20-20" file-name="src/main.rs" caption="A trait with an associated function and a type with an associated function of the same name that also implements the trait">

Expand Down Expand Up @@ -347,7 +347,7 @@ make use of the associated items of the second trait. The trait your trait
definition is relying on is called a _supertrait_ of your trait.

For example, let’s say we want to make an `OutlinePrint` trait with an
`outline_print` method that will print a given value formatted so that it's
`outline_print` method that will print a given value formatted so that it’s
framed in asterisks. That is, given a `Point` struct that implements the
standard library trait `Display` to result in `(x, y)`, when we call
`outline_print` on a `Point` instance that has `1` for `x` and `3` for `y`, it
Expand Down Expand Up @@ -416,20 +416,24 @@ Then, implementing the `OutlinePrint` trait on `Point` will compile
successfully, and we can call `outline_print` on a `Point` instance to display
it within an outline of asterisks.

### Using the Newtype Pattern to Implement External Traits on External Types

In [“Implementing a Trait on a Type”][implementing-a-trait-on-a-type]<!-- ignore
--> in Chapter 10, we mentioned the orphan rule that states we’re only allowed
to implement a trait on a type if either the trait or the type, or both, are
local to our crate. It’s possible to get around this restriction using the
_newtype pattern_, which involves creating a new type in a tuple struct. (We
covered tuple structs in [“Using Tuple Structs Without Named Fields to Create
Different Types”][tuple-structs]<!-- ignore --> in Chapter 5.) The tuple struct
will have one field and be a thin wrapper around the type for which we want to
implement a trait. Then the wrapper type is local to our crate, and we can
implement the trait on the wrapper. _Newtype_ is a term that originates from the
Haskell programming language. There is no runtime performance penalty for using
this pattern, and the wrapper type is elided at compile time.
<!-- Old link, do not remove -->
<a id="using-the-newtype-pattern-to-implement-external-traits-on-external-types"></a>

### Using the Newtype Pattern to Implement External Traits

In [“Implementing a Trait on a Type”][implementing-a-trait-on-a-type]<!--
ignore --> in Chapter 10, we mentioned the orphan rule that states we’re only
allowed to implement a trait on a type if either the trait or the type, or
both, are local to our crate. It’s possible to get around this restriction
using the _newtype pattern_, which involves creating a new type in a tuple
struct. (We covered tuple structs in [“Using Tuple Structs Without Named Fields
to Create Different Types”][tuple-structs]<!-- ignore --> in Chapter 5.) The
tuple struct will have one field and be a thin wrapper around the type for
which we want to implement a trait. Then the wrapper type is local to our
crate, and we can implement the trait on the wrapper. _Newtype_ is a term that
originates from the Haskell programming language. There is no runtime
performance penalty for using this pattern, and the wrapper type is elided at
compile time.

As an example, let’s say we want to implement `Display` on `Vec<T>`, which the
orphan rule prevents us from doing directly because the `Display` trait and the
Expand All @@ -445,26 +449,26 @@ that holds an instance of `Vec<T>`; then we can implement `Display` on

</Listing>

The implementation of `Display` uses `self.0` to access the inner `Vec<T>`,
The implementation of `Display` uses `self.0` to access the inner `Vec<T>`
because `Wrapper` is a tuple struct and `Vec<T>` is the item at index 0 in the
tuple. Then we can use the functionality of the `Display` trait on `Wrapper`.

The downside of using this technique is that `Wrapper` is a new type, so it
doesn’t have the methods of the value it’s holding. We would have to implement
all the methods of `Vec<T>` directly on `Wrapper` such that the methods delegate
to `self.0`, which would allow us to treat `Wrapper` exactly like a `Vec<T>`. If
we wanted the new type to have every method the inner type has, implementing the
`Deref` trait on the `Wrapper` to return the inner type would be a solution (we
discussed implementing the `Deref` trait in [“Treating Smart Pointers Like
Regular References with the `Deref` Trait”][smart-pointer-deref]<!-- ignore -->
in Chapter 15). If we didn’t want the `Wrapper` type to have all the methods of
the inner type—for example, to restrict the `Wrapper` type’s behavior—we would
have to implement just the methods we do want manually.
all the methods of `Vec<T>` directly on `Wrapper` such that the methods
delegate to `self.0`, which would allow us to treat `Wrapper` exactly like a
`Vec<T>`. If we wanted the new type to have every method the inner type has,
implementing the `Deref` trait on the `Wrapper` to return the inner type would
be a solution (we discussed implementing the `Deref` trait in [“Treating Smart
Pointers Like Regular References with `Deref`”][smart-pointer-deref]<!-- ignore
--> in Chapter 15). If we didn’t want the `Wrapper` type to have all the
methods of the inner type—for example, to restrict the `Wrapper` type’s
behavior—we would have to implement just the methods we do want manually.

This newtype pattern is also useful even when traits are not involved. Let’s
switch focus and look at some advanced ways to interact with Rust’s type system.

[newtype]: ch20-02-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits-on-external-types
[newtype]: ch20-02-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits
[implementing-a-trait-on-a-type]: ch10-02-traits.html#implementing-a-trait-on-a-type
[traits-defining-shared-behavior]: ch10-02-traits.html#traits-defining-shared-behavior
[smart-pointer-deref]: ch15-02-deref.html#treating-smart-pointers-like-regular-references-with-the-deref-trait
Expand Down
Loading