name = "trait_"
version = "0.1.0"
+[[package]]
+name = "trait_bounds"
+version = "0.1.0"
+
[[package]]
name = "tryfrom"
version = "0.1.0"
+++ /dev/null
-# String slices
-
-Throughout the previous chapters you've seen quite a few **string literals** being used in the code,
-like `"To-Do"` or `"A ticket description"`.
-They were always followed by a call to `.to_string()` or `.into()`. It's time to understand why!
-
-## String literals
-
-You define a string literal by enclosing the raw text in double quotes:
-
-```rust
-let s = "Hello, world!";
-```
-
-The type of `s` is `&str`, a **reference to a string slice**.
-
-## Memory layout
-
-`&str` and `String` are different types—they're not interchangeable.
-Let's recall the memory layout of a `String` from our
-[previous exploration](../03_ticket_v1/09_heap.md).
-If we run:
-
-```rust
-let mut s = String::with_capacity(5);
-s.push_str("Hello");
-```
-
-we'll get this scenario in memory:
-
-```text
- +---------+--------+----------+
-Stack | pointer | length | capacity |
- | | | 5 | 5 |
- +--|------+--------+----------+
- |
- |
- v
- +---+---+---+---+---+
-Heap: | H | e | l | l | o |
- +---+---+---+---+---+
-```
-
-If you remember, we've [also examined](../03_ticket_v1/10_references_in_memory.md)
-how a `&String` is laid out in memory:
-
-```text
- --------------------------------------
- | |
- +----v----+--------+----------+ +----|----+
- | pointer | length | capacity | | pointer |
- | | | 5 | 5 | | |
- +----|----+--------+----------+ +---------+
- | s &s
- |
- v
- +---+---+---+---+---+
- | H | e | l | l | o |
- +---+---+---+---+---+
-```
-
-`&String` points to the memory location where the `String`'s metadata is stored.
-If we follow the pointer, we get to the heap-allocated data. In particular, we get to the first byte of the string, `H`.
-
-What if we wanted a type that represents a **substring** of `s`? E.g. `ello` in `Hello`?
-
-## String slices
-
-A `&str` is a **view** into a string, a **reference** to a sequence of UTF-8 bytes stored elsewhere.
-You can, for example, create a `&str` from a `String` like this:
-
-```rust
-let mut s = String::with_capacity(5);
-s.push_str("Hello");
-// Create a string slice reference from the `String`, skipping the first byte.
-let slice: &str = &s[1..];
-```
-
-In memory, it'd look like this:
-
-```text
- s slice
- +---------+--------+----------+ +---------+--------+
-Stack | pointer | length | capacity | | pointer | length |
- | | | 5 | 5 | | | | 4 |
- +----|----+--------+----------+ +----|----+--------+
- | s |
- | |
- v |
- +---+---+---+---+---+ |
-Heap: | H | e | l | l | o | |
- +---+---+---+---+---+ |
- ^ |
- | |
- +--------------------------------+
-```
-
-`slice` stores two pieces of information on the stack:
-
-- A pointer to the first byte of the slice.
-- The length of the slice.
-
-`slice` doesn't own the data, it just points to it: it's a **reference** to the `String`'s heap-allocated data.
-When `slice` is dropped, the heap-allocated data won't be deallocated, because it's still owned by `s`.
-That's why `slice` doesn't have a `capacity` field: it doesn't own the data, so it doesn't need to know how much
-space it was allocated for it; it only cares about the data it references.
-
-## `&str` vs `&String`
-
-As a rule of thumb, use `&str` rather than `&String` whenever you need a reference to textual data.
-`&str` is more flexible and generally considered more idiomatic in Rust code.
-
-If a method returns a `&String`, you're promising that there is heap-allocated UTF-8 text somewhere that
-**matches exactly** the one you're returning a reference to.
-If a method returns a `&str`, instead, you have a lot more freedom: you're just saying that *somewhere* there's a
-bunch of text data and that a subset of it matches what you need, therefore you're returning a reference to it.
-
-## References
-
-- The exercise for this section is located in `exercises/04_traits/05_str_slice`
--- /dev/null
+# Trait bounds
+
+We've seen two use cases for traits so far:
+
+- Unlocking "built-in" behaviour (e.g. operator overloading)
+- Adding new behaviour to existing types (i.e. extension traits)
+
+There's a third use case: **generic programming**.
+
+## The problem
+
+All our functions and methods, so far, have been working with **concrete types**.
+Code that operates on concrete types is usually straightforward to write and understand. But it's also
+limited in its reusability.
+Let's imagine, for example, that we want to write a function that returns `true` if an integer is even.
+Working with concrete types, we'd have to write a separate function for each integer type we want to
+support:
+
+```rust
+fn is_even_i32(n: i32) -> bool {
+ n % 2 == 0
+}
+
+fn is_even_i64(n: i64) -> bool {
+ n % 2 == 0
+}
+
+// Etc.
+```
+
+Alternatively, we could write a single extension trait and then different implementations for each integer type:
+
+```rust
+trait IsEven {
+ fn is_even(&self) -> bool;
+}
+
+impl IsEven for i32 {
+ fn is_even(&self) -> bool {
+ self % 2 == 0
+ }
+}
+
+impl IsEven for i64 {
+ fn is_even(&self) -> bool {
+ self % 2 == 0
+ }
+}
+
+// Etc.
+```
+
+The duplication remains.
+
+## Generic programming
+
+We can do better using **generics**.
+Generics allow us to write that works with a **type parameter** instead of a concrete type:
+
+```rust
+fn print_if_even<T>(n: T)
+where
+ T: IsEven + Debug
+{
+ if n.is_even() {
+ println!("{n:?} is even");
+ }
+}
+```
+
+`print_if_even` is a **generic function**.
+It isn't tied to a specific input type. Instead, it works with any type `T` that:
+
+- Implements the `IsEven` trait.
+- Implements the `Debug` trait.
+
+This contract is expressed with a **trait bound**: `T: IsEven + Debug`.
+The `+` symbol is used to require that `T` implements multiple traits. `T: IsEven + Debug` is equivalent to
+"where `T` implements `IsEven` **and** `Debug`".
+
+## Trait bounds
+
+What purpose do trait bounds serve in `print_if_even`?
+To find out, let's try to remove them:
+
+```rust
+fn print_if_even<T>(n: T) {
+ if n.is_even() {
+ println!("{n:?} is even");
+ }
+}
+```
+
+This code won't compile:
+
+```text
+error[E0599]: no method named `is_even` found for type parameter `T` in the current scope
+ --> src/lib.rs:2:10
+ |
+1 | fn print_if_even<T>(n: T) {
+ | - method `is_even` not found for this type parameter
+2 | if n.is_even() {
+ | ^^^^^^^ method not found in `T`
+
+error[E0277]: `T` doesn't implement `Debug`
+ --> src/lib.rs:3:19
+ |
+3 | println!("{n:?} is even");
+ | ^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+ |
+help: consider restricting type parameter `T`
+ |
+1 | fn print_if_even<T: std::fmt::Debug>(n: T) {
+ | +++++++++++++++++
+```
+
+Without trait bounds, the compiler doesn't know what `T` **can do**.
+It doesn't know that `T` has an `is_even` method, and it doesn't know how to format `T` for printing.
+Trait bounds restrict the set of types that can be used by ensuring that the behaviour required by the function
+body is present.
+
+## Inlining trait bounds
+
+All the examples above used a **`where` clause** to specify trait bounds:
+
+```rust
+fn print_if_even<T>(n: T)
+where
+ T: IsEven + Debug
+// ^^^^^^^^^^^^^^^^^
+// This is a `where` clause
+{
+ // [...]
+}
+```
+
+If the trait bounds are simple, you can **inline** them directly next to the type parameter:
+
+```rust
+fn print_if_even<T: IsEven + Debug>(n: T) {
+ // ^^^^^^^^^^^^^^^^^
+ // This is an inline trait bound
+ // [...]
+}
+```
+
+## The function signature is king
+
+You may wonder why we need trait bounds at all. Can't the compiler infer the required traits from the function's body?
+It could, but it won't.
+The rationale is the same as for [explicit type annotations on function parameters](../02_basic_calculator/02_variables#function-arguments-are-variables):
+each function signature is a contract between the caller and the callee, and the terms must be explicitly stated.
+This allows for better error messages, better documentation, less unintentional breakages across versions,
+and faster compilation times.
+++ /dev/null
-# `Deref` trait
-
-In the previous exercise you didn't have to do much, did you?
-
-Changing
-
-```rust
-impl Ticket {
- pub fn title(&self) -> &String {
- &self.title
- }
-}
-```
-
-to
-
-```rust
-impl Ticket {
- pub fn title(&self) -> &str {
- &self.title
- }
-}
-```
-
-was all you needed to do to get the code to compile and the tests to pass.
-Some alarm bells should be ringing in your head though.
-
-## It shouldn't work, but it does
-
-Let's review the facts:
-
-- `self.title` is a `String`
-- `&self.title` is, therefore, a `&String`
-- The output of the (modified) `title` method is `&str`
-
-You would expect a compiler error, wouldn't you? `Expected &String, found &str` or something similar.
-Instead, it just works. **Why**?
-
-## `Deref` to the rescue
-
-The `Deref` trait is the mechanism behind the language feature known as [**deref coercion**](https://doc.rust-lang.org/std/ops/trait.Deref.html#deref-coercion).
-The trait is defined in the standard library, in the `std::ops` module:
-
-```rust
-// I've slightly simplified the definition for now.
-// We'll see the full definition later on.
-pub trait Deref {
- type Target;
-
- fn deref(&self) -> &Self::Target;
-}
-```
-
-`type Target` is an **associated type**.
-It's a placeholder for a concrete type that must be specified when the trait is implemented.
-
-## Deref coercion
-
-By implementing `Deref<Target = U>` for a type `T` you're telling the compiler that `&T` and `&U` are
-somewhat interchangeable.
-In particular, you get the following behavior:
-
-- References to `T` are implicitly converted into references to `U` (i.e. `&T` becomes `&U`)
-- You can call on `&T` all the methods defined on `U` that take `&self` as input.
-
-There is one more thing around the dereference operator, `*`, but we don't need it yet (see `std`'s docs
-if you're curious).
-
-## `String` implements `Deref`
-
-`String` implements `Deref` with `Target = str`:
-
-```rust
-impl Deref for String {
- type Target = str;
-
- fn deref(&self) -> &str {
- // [...]
- }
-}
-```
-
-Thanks to this implementation and deref coercion, a `&String` is automatically converted into a `&str` when needed.
-
-## Don't abuse deref coercion
-
-Deref coercion is a powerful feature, but it can lead to confusion.
-Automatically converting types can make the code harder to read and understand. If a method with the same name
-is defined on both `T` and `U`, which one will be called?
-
-We'll examine later in the course the "safest" use cases for deref coercion: smart pointers.
-
-## References
-
-- The exercise for this section is located in `exercises/04_traits/06_deref`
--- /dev/null
+# String slices
+
+Throughout the previous chapters you've seen quite a few **string literals** being used in the code,
+like `"To-Do"` or `"A ticket description"`.
+They were always followed by a call to `.to_string()` or `.into()`. It's time to understand why!
+
+## String literals
+
+You define a string literal by enclosing the raw text in double quotes:
+
+```rust
+let s = "Hello, world!";
+```
+
+The type of `s` is `&str`, a **reference to a string slice**.
+
+## Memory layout
+
+`&str` and `String` are different types—they're not interchangeable.
+Let's recall the memory layout of a `String` from our
+[previous exploration](../03_ticket_v1/09_heap.md).
+If we run:
+
+```rust
+let mut s = String::with_capacity(5);
+s.push_str("Hello");
+```
+
+we'll get this scenario in memory:
+
+```text
+ +---------+--------+----------+
+Stack | pointer | length | capacity |
+ | | | 5 | 5 |
+ +--|------+--------+----------+
+ |
+ |
+ v
+ +---+---+---+---+---+
+Heap: | H | e | l | l | o |
+ +---+---+---+---+---+
+```
+
+If you remember, we've [also examined](../03_ticket_v1/10_references_in_memory.md)
+how a `&String` is laid out in memory:
+
+```text
+ --------------------------------------
+ | |
+ +----v----+--------+----------+ +----|----+
+ | pointer | length | capacity | | pointer |
+ | | | 5 | 5 | | |
+ +----|----+--------+----------+ +---------+
+ | s &s
+ |
+ v
+ +---+---+---+---+---+
+ | H | e | l | l | o |
+ +---+---+---+---+---+
+```
+
+`&String` points to the memory location where the `String`'s metadata is stored.
+If we follow the pointer, we get to the heap-allocated data. In particular, we get to the first byte of the string, `H`.
+
+What if we wanted a type that represents a **substring** of `s`? E.g. `ello` in `Hello`?
+
+## String slices
+
+A `&str` is a **view** into a string, a **reference** to a sequence of UTF-8 bytes stored elsewhere.
+You can, for example, create a `&str` from a `String` like this:
+
+```rust
+let mut s = String::with_capacity(5);
+s.push_str("Hello");
+// Create a string slice reference from the `String`, skipping the first byte.
+let slice: &str = &s[1..];
+```
+
+In memory, it'd look like this:
+
+```text
+ s slice
+ +---------+--------+----------+ +---------+--------+
+Stack | pointer | length | capacity | | pointer | length |
+ | | | 5 | 5 | | | | 4 |
+ +----|----+--------+----------+ +----|----+--------+
+ | s |
+ | |
+ v |
+ +---+---+---+---+---+ |
+Heap: | H | e | l | l | o | |
+ +---+---+---+---+---+ |
+ ^ |
+ | |
+ +--------------------------------+
+```
+
+`slice` stores two pieces of information on the stack:
+
+- A pointer to the first byte of the slice.
+- The length of the slice.
+
+`slice` doesn't own the data, it just points to it: it's a **reference** to the `String`'s heap-allocated data.
+When `slice` is dropped, the heap-allocated data won't be deallocated, because it's still owned by `s`.
+That's why `slice` doesn't have a `capacity` field: it doesn't own the data, so it doesn't need to know how much
+space it was allocated for it; it only cares about the data it references.
+
+## `&str` vs `&String`
+
+As a rule of thumb, use `&str` rather than `&String` whenever you need a reference to textual data.
+`&str` is more flexible and generally considered more idiomatic in Rust code.
+
+If a method returns a `&String`, you're promising that there is heap-allocated UTF-8 text somewhere that
+**matches exactly** the one you're returning a reference to.
+If a method returns a `&str`, instead, you have a lot more freedom: you're just saying that *somewhere* there's a
+bunch of text data and that a subset of it matches what you need, therefore you're returning a reference to it.
+
+## References
+
+- The exercise for this section is located in `exercises/04_traits/05_str_slice`
--- /dev/null
+# `Deref` trait
+
+In the previous exercise you didn't have to do much, did you?
+
+Changing
+
+```rust
+impl Ticket {
+ pub fn title(&self) -> &String {
+ &self.title
+ }
+}
+```
+
+to
+
+```rust
+impl Ticket {
+ pub fn title(&self) -> &str {
+ &self.title
+ }
+}
+```
+
+was all you needed to do to get the code to compile and the tests to pass.
+Some alarm bells should be ringing in your head though.
+
+## It shouldn't work, but it does
+
+Let's review the facts:
+
+- `self.title` is a `String`
+- `&self.title` is, therefore, a `&String`
+- The output of the (modified) `title` method is `&str`
+
+You would expect a compiler error, wouldn't you? `Expected &String, found &str` or something similar.
+Instead, it just works. **Why**?
+
+## `Deref` to the rescue
+
+The `Deref` trait is the mechanism behind the language feature known as [**deref coercion**](https://doc.rust-lang.org/std/ops/trait.Deref.html#deref-coercion).
+The trait is defined in the standard library, in the `std::ops` module:
+
+```rust
+// I've slightly simplified the definition for now.
+// We'll see the full definition later on.
+pub trait Deref {
+ type Target;
+
+ fn deref(&self) -> &Self::Target;
+}
+```
+
+`type Target` is an **associated type**.
+It's a placeholder for a concrete type that must be specified when the trait is implemented.
+
+## Deref coercion
+
+By implementing `Deref<Target = U>` for a type `T` you're telling the compiler that `&T` and `&U` are
+somewhat interchangeable.
+In particular, you get the following behavior:
+
+- References to `T` are implicitly converted into references to `U` (i.e. `&T` becomes `&U`)
+- You can call on `&T` all the methods defined on `U` that take `&self` as input.
+
+There is one more thing around the dereference operator, `*`, but we don't need it yet (see `std`'s docs
+if you're curious).
+
+## `String` implements `Deref`
+
+`String` implements `Deref` with `Target = str`:
+
+```rust
+impl Deref for String {
+ type Target = str;
+
+ fn deref(&self) -> &str {
+ // [...]
+ }
+}
+```
+
+Thanks to this implementation and deref coercion, a `&String` is automatically converted into a `&str` when needed.
+
+## Don't abuse deref coercion
+
+Deref coercion is a powerful feature, but it can lead to confusion.
+Automatically converting types can make the code harder to read and understand. If a method with the same name
+is defined on both `T` and `U`, which one will be called?
+
+We'll examine later in the course the "safest" use cases for deref coercion: smart pointers.
+
+## References
+
+- The exercise for this section is located in `exercises/04_traits/06_deref`
+++ /dev/null
-# `Sized`
-
-There's more to `&str` than meets the eye, even after having
-investigated deref coercion.
-From our previous [discussion on memory layouts](../03_ticket_v1/10_references_in_memory.md),
-it would have been reasonable to expect `&str` to be represented as a single `usize` on
-the stack, a pointer. That's not the case though. `&str` stores some **metadata** next
-to the pointer: the length of the slice it points to. Going back to the example from
-[a previous section](05_str_slice.md):
-
-```rust
-let mut s = String::with_capacity(5);
-s.push_str("Hello");
-// Create a string slice reference from the `String`, skipping the first byte.
-let slice: &str = &s[1..];
-```
-
-In memory, we get:
-
-```text
- s slice
- +---------+--------+----------+ +---------+--------+
-Stack | pointer | length | capacity | | pointer | length |
- | | | 5 | 5 | | | | 4 |
- +----|----+--------+----------+ +----|----+--------+
- | s |
- | |
- v |
- +---+---+---+---+---+ |
-Heap: | H | e | l | l | o | |
- +---+---+---+---+---+ |
- ^ |
- | |
- +--------------------------------+
-```
-
-What's going on?
-
-## Dynamically sized types
-
-`str` is a **dynamically sized type** (DST).
-A DST is a type whose size is not known at compile time. Whenever you have a
-reference to a DST, like `&str`, it has to include additional
-information about the data it points to. It is a **fat pointer**.
-In the case of `&str`, it stores the length of the slice it points to.
-We'll see more examples of DSTs in the rest of the course.
-
-## The `Sized` trait
-
-Rust's `std` library defines a trait called `Sized`.
-
-```rust
-pub trait Sized {
- // This is an empty trait, no methods to implement.
-}
-```
-
-A type is `Sized` if its size is known at compile time. In other words, it's not a DST.
-
-### Marker traits
-
-`Sized` is your first example of a **marker trait**.
-A marker trait is a trait that doesn't require any methods to be implemented. It doesn't define any behavior.
-It only serves to **mark** a type as having certain properties.
-The mark is then leveraged by the compiler to enable certain behaviors or optimizations.
-
-### Auto traits
-
-In particular, `Sized` is also an **auto trait**.
-You don't need to implement it explicitly; the compiler implements it automatically for you
-based on the type's definition.
-
-### Examples
-
-All the types we've seen so far are `Sized`: `u32`, `String`, `bool`, etc.
-
-`str`, as we just saw, is not `Sized`.
-`&str` is `Sized` though! We know its size at compile time: two `usize`s, one for the pointer
-and one for the length.
-
-## References
-
-- The exercise for this section is located in `exercises/04_traits/07_sized`
+++ /dev/null
-# `From` and `Into`
-
-Let's go back to where our string journey started:
-
-```rust
-let ticket = Ticket::new("A title".into(), "A description".into(), "To-Do".into());
-```
-
-We can now know enough to start unpacking what `.into()` is doing here.
-
-## The problem
-
-This is the signature of the `new` method:
-
-```rust
-impl Ticket {
- pub fn new(title: String, description: String, status: String) -> Self {
- // [...]
- }
-}
-```
-
-We've also seen that string literals (such as `"A title"`) are of type `&str`.
-We have a type mismatch here: a `String` is expected, but we have a `&str`.
-No magical coercion will come to save us this time; we need **to perform a conversion**.
-
-## `From` and `Into`
-
-The Rust standard library defines two traits for **infallible conversions**: `From` and `Into`,
-in the `std::convert` module.
-
-```rust
-pub trait From<T>: Sized {
- fn from(value: T) -> Self;
-}
-
-pub trait Into<T>: Sized {
- fn into(self) -> T;
-}
-```
-
-These trait definitions showcase a few concepts that we haven't seen before: **supertraits**, **generics**,
-and **implicit trait bounds**. Let's unpack those first.
-
-### Supertrait / Subtrait
-
-The `From: Sized` syntax implies that `From` is a **subtrait** of `Sized`: any type that
-implements `From` must also implement `Sized`.
-Alternatively, you could say that `Sized` is a **supertrait** of `From`.
-
-### Generics
-
-Both `From` and `Into` are **generic traits**.
-They take a type parameter, `T`, to refer to the type being converted from or into.
-`T` is a placeholder for the actual type, which will be specified when the trait is implemented or used.
-
-### Implicit trait bounds
-
-Every time you have a generic type parameter, the compiler implicitly assumes that it's `Sized`.
-
-For example:
-
-```rust
-pub struct Foo<T> {
- inner: T,
-}
-```
-
-is actually equivalent to:
-
-```rust
-pub struct Foo<T>
-where
- T: Sized,
-// ^^^^^^^^^
-// This is known as a **trait bound**
-// It specifies that this implementation applies exclusively
-// to types `T` that implement `Sized`
-// You can require multiple traits to be implemented using
-// the `+` sign. E.g. `Sized + PartialEq<T>`
-{
- inner: T,
-}
-```
-
-You can opt out of this behavior by using a **negative trait bound**:
-
-```rust
-// You can also choose to inline trait bounds,
-// rather than using `where` clauses
-
-pub struct Foo<T: ?Sized> {
- // ^^^^^^^
- // This is a negative trait bound
- inner: T,
-}
-```
-
-This syntax reads as "`T` may or may not be `Sized`", and it allows you to
-bind `T` to a DST (e.g. `Foo<str>`).
-In the case of `From<T>`, we want _both_ `T` and the type implementing `From<T>` to be `Sized`, even
-though the former bound is implicit.
-
-## `&str` to `String`
-
-In [`std`'s documentation](https://doc.rust-lang.org/std/convert/trait.From.html#implementors)
-you can see which `std` types implement the `From` trait.
-You'll find that `String` implements `From<&str> for String`. Thus, we can write:
-
-```rust
-let title = String::from("A title");
-```
-
-We've been primarily using `.into()`, though.
-If you check out the [implementors of `Into`](https://doc.rust-lang.org/std/convert/trait.Into.html#implementors)
-you won't find `Into<&str> for String`. What's going on?
-
-`From` and `Into` are **dual traits**.
-In particular, `Into` is implemented for any type that implements `From` using a **blanket implementation**:
-
-```rust
-impl<T, U> Into<U> for T
-where
- U: From<T>,
-{
- fn into(self) -> U {
- U::from(self)
- }
-}
-```
-
-If a type `U` implements `From<T>`, then `Into<U> for T` is automatically implemented. That's why
-we can write `let title = "A title".into();`.
-
-## `.into()`
-
-Every time you see `.into()`, you're witnessing a conversion between types.
-What's the target type, though?
-
-In most cases, the target type is either:
-
-- Specified by the signature of a function/method (e.g. `Ticket::new` in our example above)
-- Specified in the variable declaration with a type annotation (e.g. `let title: String = "A title".into();`)
-
-`.into()` will work out of the box as long as the compiler can infer the target type from the context without ambiguity.
-
-## References
-
-- The exercise for this section is located in `exercises/04_traits/08_from`
--- /dev/null
+# `Sized`
+
+There's more to `&str` than meets the eye, even after having
+investigated deref coercion.
+From our previous [discussion on memory layouts](../03_ticket_v1/10_references_in_memory.md),
+it would have been reasonable to expect `&str` to be represented as a single `usize` on
+the stack, a pointer. That's not the case though. `&str` stores some **metadata** next
+to the pointer: the length of the slice it points to. Going back to the example from
+[a previous section](05_str_slice.md):
+
+```rust
+let mut s = String::with_capacity(5);
+s.push_str("Hello");
+// Create a string slice reference from the `String`, skipping the first byte.
+let slice: &str = &s[1..];
+```
+
+In memory, we get:
+
+```text
+ s slice
+ +---------+--------+----------+ +---------+--------+
+Stack | pointer | length | capacity | | pointer | length |
+ | | | 5 | 5 | | | | 4 |
+ +----|----+--------+----------+ +----|----+--------+
+ | s |
+ | |
+ v |
+ +---+---+---+---+---+ |
+Heap: | H | e | l | l | o | |
+ +---+---+---+---+---+ |
+ ^ |
+ | |
+ +--------------------------------+
+```
+
+What's going on?
+
+## Dynamically sized types
+
+`str` is a **dynamically sized type** (DST).
+A DST is a type whose size is not known at compile time. Whenever you have a
+reference to a DST, like `&str`, it has to include additional
+information about the data it points to. It is a **fat pointer**.
+In the case of `&str`, it stores the length of the slice it points to.
+We'll see more examples of DSTs in the rest of the course.
+
+## The `Sized` trait
+
+Rust's `std` library defines a trait called `Sized`.
+
+```rust
+pub trait Sized {
+ // This is an empty trait, no methods to implement.
+}
+```
+
+A type is `Sized` if its size is known at compile time. In other words, it's not a DST.
+
+### Marker traits
+
+`Sized` is your first example of a **marker trait**.
+A marker trait is a trait that doesn't require any methods to be implemented. It doesn't define any behavior.
+It only serves to **mark** a type as having certain properties.
+The mark is then leveraged by the compiler to enable certain behaviors or optimizations.
+
+### Auto traits
+
+In particular, `Sized` is also an **auto trait**.
+You don't need to implement it explicitly; the compiler implements it automatically for you
+based on the type's definition.
+
+### Examples
+
+All the types we've seen so far are `Sized`: `u32`, `String`, `bool`, etc.
+
+`str`, as we just saw, is not `Sized`.
+`&str` is `Sized` though! We know its size at compile time: two `usize`s, one for the pointer
+and one for the length.
+
+## References
+
+- The exercise for this section is located in `exercises/04_traits/07_sized`
+++ /dev/null
-# Generics and associated types
-
-Let's re-examine the definition for two of the traits we studied so far, `From` and `Deref`:
-
-```rust
-pub trait From<T> {
- fn from(value: T) -> Self;
-}
-
-pub trait Deref {
- type Target;
-
- fn deref(&self) -> &Self::Target;
-}
-```
-
-They both feature type parameters.
-In the case of `From`, it's a generic parameter, `T`.
-In the case of `Deref`, it's an associated type, `Target`.
-
-What's the difference? Why use one over the other?
-
-## At most one implementation
-
-Due to how deref coercion works, there can only be one "target" type for a given type. E.g. `String` can
-only deref to `str`.
-It's about avoiding ambiguity: if you could implement `Deref` multiple times for a type,
-which `Target` type should the compiler choose when you call a `&self` method?
-
-That's why `Deref` uses an associated type, `Target`.
-An associated type is uniquely determined **by the trait implementation**.
-Since you can't implement `Deref` more than once, you'll only be able to specify one `Target` for a given type
-and there won't be any ambiguity.
-
-## Generic traits
-
-On the other hand, you can implement `From` multiple times for a type, **as long as the input type `T` is different**.
-For example, you can implement `From` for `WrappingU32` using both `u32` and `u16` as input types:
-
-```rust
-impl From<u32> for WrappingU32 {
- fn from(value: u32) -> Self {
- WrappingU32 { inner: value }
- }
-}
-
-impl From<u16> for WrappingU32 {
- fn from(value: u16) -> Self {
- WrappingU32 { inner: value.into() }
- }
-}
-```
-
-This works because `From<u16>` and `From<u32>` are considered **different traits**.
-There is no ambiguity: the compiler can determine which implementation to use based on type of the value being converted.
-
-## Case study: `Add`
-
-As a closing example, consider the `Add` trait from the standard library:
-
-```rust
-pub trait Add<RHS = Self> {
- type Output;
-
- fn add(self, rhs: RHS) -> Self::Output;
-}
-```
-
-It uses both mechanisms:
-
-- it has a generic parameter, `RHS` (right-hand side), which defaults to `Self`
-- it has an associated type, `Output`, the type of the result of the addition
-
-### `RHS`
-
-`RHS` is a generic parameter to allow for different types to be added together.
-For example, you'll find these two implementations in the standard library:
-
-```rust
-impl Add<u32> for u32 {
- type Output = u32;
-
- fn add(self, rhs: u32) -> u32 {
- // [...]
- }
-}
-
-impl Add<&u32> for u32 {
- type Output = u32;
-
- fn add(self, rhs: &u32) -> u32 {
- // [...]
- }
-}
-```
-
-This allows the following code to compile:
-
-```rust
-let x = 5u32 + &5u32 + 6u32;
-```
-
-because `u32` implements `Add<&u32>` _as well as_ `Add<u32>`.
-
-### `Output`
-
-`Output`, on the other hand, **must** be uniquely determined once the types of the operands
-are known. That's why it's an associated type instead of a second generic parameter.
-
-To recap:
-
-- Use an **associated type** when the type must be uniquely determined for a given trait implementation.
-- Use a **generic parameter** when you want to allow multiple implementations of the trait for the same type,
- with different input types.
-
-## References
-
-- The exercise for this section is located in `exercises/04_traits/09_assoc_vs_generic`
--- /dev/null
+# `From` and `Into`
+
+Let's go back to where our string journey started:
+
+```rust
+let ticket = Ticket::new("A title".into(), "A description".into(), "To-Do".into());
+```
+
+We can now know enough to start unpacking what `.into()` is doing here.
+
+## The problem
+
+This is the signature of the `new` method:
+
+```rust
+impl Ticket {
+ pub fn new(title: String, description: String, status: String) -> Self {
+ // [...]
+ }
+}
+```
+
+We've also seen that string literals (such as `"A title"`) are of type `&str`.
+We have a type mismatch here: a `String` is expected, but we have a `&str`.
+No magical coercion will come to save us this time; we need **to perform a conversion**.
+
+## `From` and `Into`
+
+The Rust standard library defines two traits for **infallible conversions**: `From` and `Into`,
+in the `std::convert` module.
+
+```rust
+pub trait From<T>: Sized {
+ fn from(value: T) -> Self;
+}
+
+pub trait Into<T>: Sized {
+ fn into(self) -> T;
+}
+```
+
+These trait definitions showcase a few concepts that we haven't seen before: **supertraits** and **implicit trait bounds**.
+Let's unpack those first.
+
+### Supertrait / Subtrait
+
+The `From: Sized` syntax implies that `From` is a **subtrait** of `Sized`: any type that
+implements `From` must also implement `Sized`.
+Alternatively, you could say that `Sized` is a **supertrait** of `From`.
+
+### Implicit trait bounds
+
+Every time you have a generic type parameter, the compiler implicitly assumes that it's `Sized`.
+
+For example:
+
+```rust
+pub struct Foo<T> {
+ inner: T,
+}
+```
+
+is actually equivalent to:
+
+```rust
+pub struct Foo<T: Sized>
+{
+ inner: T,
+}
+```
+
+You can opt out of this behavior by using a **negative trait bound**:
+
+```rust
+pub struct Foo<T: ?Sized> {
+ // ^^^^^^^
+ // This is a negative trait bound
+ inner: T,
+}
+```
+
+This syntax reads as "`T` may or may not be `Sized`", and it allows you to
+bind `T` to a DST (e.g. `Foo<str>`). It is a special case, though: negative trait bounds are exclusive to `Sized`,
+you can't use them with other traits.
+In the case of `From<T>`, we want _both_ `T` and the type implementing `From<T>` to be `Sized`, even
+though the former bound is implicit.
+
+## `&str` to `String`
+
+In [`std`'s documentation](https://doc.rust-lang.org/std/convert/trait.From.html#implementors)
+you can see which `std` types implement the `From` trait.
+You'll find that `String` implements `From<&str> for String`. Thus, we can write:
+
+```rust
+let title = String::from("A title");
+```
+
+We've been primarily using `.into()`, though.
+If you check out the [implementors of `Into`](https://doc.rust-lang.org/std/convert/trait.Into.html#implementors)
+you won't find `Into<&str> for String`. What's going on?
+
+`From` and `Into` are **dual traits**.
+In particular, `Into` is implemented for any type that implements `From` using a **blanket implementation**:
+
+```rust
+impl<T, U> Into<U> for T
+where
+ U: From<T>,
+{
+ fn into(self) -> U {
+ U::from(self)
+ }
+}
+```
+
+If a type `U` implements `From<T>`, then `Into<U> for T` is automatically implemented. That's why
+we can write `let title = "A title".into();`.
+
+## `.into()`
+
+Every time you see `.into()`, you're witnessing a conversion between types.
+What's the target type, though?
+
+In most cases, the target type is either:
+
+- Specified by the signature of a function/method (e.g. `Ticket::new` in our example above)
+- Specified in the variable declaration with a type annotation (e.g. `let title: String = "A title".into();`)
+
+`.into()` will work out of the box as long as the compiler can infer the target type from the context without ambiguity.
+
+## References
+
+- The exercise for this section is located in `exercises/04_traits/08_from`
--- /dev/null
+# Generics and associated types
+
+Let's re-examine the definition for two of the traits we studied so far, `From` and `Deref`:
+
+```rust
+pub trait From<T> {
+ fn from(value: T) -> Self;
+}
+
+pub trait Deref {
+ type Target;
+
+ fn deref(&self) -> &Self::Target;
+}
+```
+
+They both feature type parameters.
+In the case of `From`, it's a generic parameter, `T`.
+In the case of `Deref`, it's an associated type, `Target`.
+
+What's the difference? Why use one over the other?
+
+## At most one implementation
+
+Due to how deref coercion works, there can only be one "target" type for a given type. E.g. `String` can
+only deref to `str`.
+It's about avoiding ambiguity: if you could implement `Deref` multiple times for a type,
+which `Target` type should the compiler choose when you call a `&self` method?
+
+That's why `Deref` uses an associated type, `Target`.
+An associated type is uniquely determined **by the trait implementation**.
+Since you can't implement `Deref` more than once, you'll only be able to specify one `Target` for a given type
+and there won't be any ambiguity.
+
+## Generic traits
+
+On the other hand, you can implement `From` multiple times for a type, **as long as the input type `T` is different**.
+For example, you can implement `From` for `WrappingU32` using both `u32` and `u16` as input types:
+
+```rust
+impl From<u32> for WrappingU32 {
+ fn from(value: u32) -> Self {
+ WrappingU32 { inner: value }
+ }
+}
+
+impl From<u16> for WrappingU32 {
+ fn from(value: u16) -> Self {
+ WrappingU32 { inner: value.into() }
+ }
+}
+```
+
+This works because `From<u16>` and `From<u32>` are considered **different traits**.
+There is no ambiguity: the compiler can determine which implementation to use based on type of the value being converted.
+
+## Case study: `Add`
+
+As a closing example, consider the `Add` trait from the standard library:
+
+```rust
+pub trait Add<RHS = Self> {
+ type Output;
+
+ fn add(self, rhs: RHS) -> Self::Output;
+}
+```
+
+It uses both mechanisms:
+
+- it has a generic parameter, `RHS` (right-hand side), which defaults to `Self`
+- it has an associated type, `Output`, the type of the result of the addition
+
+### `RHS`
+
+`RHS` is a generic parameter to allow for different types to be added together.
+For example, you'll find these two implementations in the standard library:
+
+```rust
+impl Add<u32> for u32 {
+ type Output = u32;
+
+ fn add(self, rhs: u32) -> u32 {
+ // [...]
+ }
+}
+
+impl Add<&u32> for u32 {
+ type Output = u32;
+
+ fn add(self, rhs: &u32) -> u32 {
+ // [...]
+ }
+}
+```
+
+This allows the following code to compile:
+
+```rust
+let x = 5u32 + &5u32 + 6u32;
+```
+
+because `u32` implements `Add<&u32>` _as well as_ `Add<u32>`.
+
+### `Output`
+
+`Output`, on the other hand, **must** be uniquely determined once the types of the operands
+are known. That's why it's an associated type instead of a second generic parameter.
+
+To recap:
+
+- Use an **associated type** when the type must be uniquely determined for a given trait implementation.
+- Use a **generic parameter** when you want to allow multiple implementations of the trait for the same type,
+ with different input types.
+
+## References
+
+- The exercise for this section is located in `exercises/04_traits/09_assoc_vs_generic`
+++ /dev/null
-# Copying values, pt. 1
-
-In the previous chapter we introduced ownership and borrowing.
-We stated, in particular, that:
-
-- Every value in Rust has a single owner at any given time.
-- When a function takes ownership of a value ("it consumes it"), the caller can't use that value anymore.
-
-These restrictions can be somewhat limiting.
-Sometimes we might have to call a function that takes ownership of a value, but we still need to use
-that value afterward.
-
-```rust
-fn consumer(s: String) { /* */ }
-
-fn example() {
- let mut s = String::from("hello");
- consumer(s);
- s.push_str(", world!"); // error: value borrowed here after move
-}
-```
-
-That's where `Clone` comes in.
-
-## `Clone`
-
-`Clone` is a trait defined in Rust's standard library:
-
-```rust
-pub trait Clone {
- fn clone(&self) -> Self;
-}
-```
-
-Its method, `clone`, takes a reference to `self` and returns a new **owned** instance of the same type.
-
-## In action
-
-Going back to the example above, we can use `clone` to create a new `String` instance before calling `consumer`:
-
-```rust
-fn consumer(s: String) { /* */ }
-
-fn example() {
- let mut s = String::from("hello");
- let t = s.clone();
- consumer(t);
- s.push_str(", world!"); // no error
-}
-```
-
-Instead of giving ownership of `s` to `consumer`, we create a new `String` (by cloning `s`) and give
-that to `consumer` instead.
-`s` remains valid and usable after the call to `consumer`.
-
-## In memory
-
-Let's look at what happened in memory in the example above.
-When `let mut s: String::from("hello");` is executed, the memory looks like this:
-
-```text
- s
- +---------+--------+----------+
-Stack | pointer | length | capacity |
- | | | 5 | 5 |
- +--|------+--------+----------+
- |
- |
- v
- +---+---+---+---+---+
-Heap: | H | e | l | l | o |
- +---+---+---+---+---+
-```
-
-When `let t = s.clone()` is executed, a whole new region is allocated on the heap to store a copy of the data:
-
-```text
- s t
- +---------+--------+----------+ +---------+--------+----------+
-Stack | pointer | length | capacity | | pointer | length | capacity |
- | | | 5 | 5 | | | | 5 | 5 |
- +--|------+--------+----------+ +--|------+--------+----------+
- | |
- | |
- v v
- +---+---+---+---+---+ +---+---+---+---+---+
-Heap: | H | e | l | l | o | | H | e | l | l | o |
- +---+---+---+---+---+ +---+---+---+---+---+
-```
-
-If you're coming from a language like Java, you can think of `clone` as a way to create a deep copy of an object.
-
-## Implementing `Clone`
-
-To make a type `Clone`-able, we have to implement the `Clone` trait for it.
-You almost always implement `Clone` by deriving it:
-
-```rust
-#[derive(Clone)]
-struct MyType {
- // fields
-}
-```
-
-The compiler implements `Clone` for `MyType` as you would expect: it clones each field of `MyType` individually and
-then constructs a new `MyType` instance using the cloned fields.
-Remember that you can use `cargo expand` (or your IDE) to explore the code generated by `derive` macros.
-
-## References
-
-- The exercise for this section is located in `exercises/04_traits/10_clone`
--- /dev/null
+# Copying values, pt. 1
+
+In the previous chapter we introduced ownership and borrowing.
+We stated, in particular, that:
+
+- Every value in Rust has a single owner at any given time.
+- When a function takes ownership of a value ("it consumes it"), the caller can't use that value anymore.
+
+These restrictions can be somewhat limiting.
+Sometimes we might have to call a function that takes ownership of a value, but we still need to use
+that value afterward.
+
+```rust
+fn consumer(s: String) { /* */ }
+
+fn example() {
+ let mut s = String::from("hello");
+ consumer(s);
+ s.push_str(", world!"); // error: value borrowed here after move
+}
+```
+
+That's where `Clone` comes in.
+
+## `Clone`
+
+`Clone` is a trait defined in Rust's standard library:
+
+```rust
+pub trait Clone {
+ fn clone(&self) -> Self;
+}
+```
+
+Its method, `clone`, takes a reference to `self` and returns a new **owned** instance of the same type.
+
+## In action
+
+Going back to the example above, we can use `clone` to create a new `String` instance before calling `consumer`:
+
+```rust
+fn consumer(s: String) { /* */ }
+
+fn example() {
+ let mut s = String::from("hello");
+ let t = s.clone();
+ consumer(t);
+ s.push_str(", world!"); // no error
+}
+```
+
+Instead of giving ownership of `s` to `consumer`, we create a new `String` (by cloning `s`) and give
+that to `consumer` instead.
+`s` remains valid and usable after the call to `consumer`.
+
+## In memory
+
+Let's look at what happened in memory in the example above.
+When `let mut s: String::from("hello");` is executed, the memory looks like this:
+
+```text
+ s
+ +---------+--------+----------+
+Stack | pointer | length | capacity |
+ | | | 5 | 5 |
+ +--|------+--------+----------+
+ |
+ |
+ v
+ +---+---+---+---+---+
+Heap: | H | e | l | l | o |
+ +---+---+---+---+---+
+```
+
+When `let t = s.clone()` is executed, a whole new region is allocated on the heap to store a copy of the data:
+
+```text
+ s t
+ +---------+--------+----------+ +---------+--------+----------+
+Stack | pointer | length | capacity | | pointer | length | capacity |
+ | | | 5 | 5 | | | | 5 | 5 |
+ +--|------+--------+----------+ +--|------+--------+----------+
+ | |
+ | |
+ v v
+ +---+---+---+---+---+ +---+---+---+---+---+
+Heap: | H | e | l | l | o | | H | e | l | l | o |
+ +---+---+---+---+---+ +---+---+---+---+---+
+```
+
+If you're coming from a language like Java, you can think of `clone` as a way to create a deep copy of an object.
+
+## Implementing `Clone`
+
+To make a type `Clone`-able, we have to implement the `Clone` trait for it.
+You almost always implement `Clone` by deriving it:
+
+```rust
+#[derive(Clone)]
+struct MyType {
+ // fields
+}
+```
+
+The compiler implements `Clone` for `MyType` as you would expect: it clones each field of `MyType` individually and
+then constructs a new `MyType` instance using the cloned fields.
+Remember that you can use `cargo expand` (or your IDE) to explore the code generated by `derive` macros.
+
+## References
+
+- The exercise for this section is located in `exercises/04_traits/10_clone`
+++ /dev/null
-# Copying values, pt. 2
-
-Let's consider the same example as before, but with a slight twist: using `u32` rather than `String` as a type.
-
-```rust
-fn consumer(s: u32) { /* */ }
-
-fn example() {
- let s: u32 = 5;
- consumer(s);
- let t = s + 1;
-}
-```
-
-It'll compile without errors! What's going on here? What's the difference between `String` and `u32`
-that makes the latter work without `.clone()`?
-
-## `Copy`
-
-`Copy` is another trait defined in Rust's standard library:
-
-```rust
-pub trait Copy: Clone { }
-```
-
-It is a marker trait, just like `Sized`.
-
-If a type implements `Copy`, there's no need to call `.clone()` to create a new instance of the type:
-Rust does it **implicitly** for you.
-`u32` is an example of a type that implements `Copy`, which is why the example above compiles without errors:
-when `consumer(s)` is called, Rust creates a new `u32` instance by performing a **bitwise copy** of `s`,
-and then passes that new instance to `consumer`. It all happens behind the scenes, without you having to do anything.
-
-## What can be `Copy`?
-
-`Copy` is not equivalent to "automatic cloning", although it implies it.
-Types must meet a few requirements in order to be allowed to implement `Copy`.
-
-First of all, it must implement `Clone`, since `Copy` is a subtrait of `Clone`.
-This makes sense: if Rust can create a new instance of a type _implicitly_, it should
-also be able to create a new instance _explicitly_ by calling `.clone()`.
-
-That's not all, though. A few more conditions must be met:
-
-1. The type doesn't manage any _additional_ resources (e.g. heap memory, file handles, etc.) beyond the `std::mem::size_of`
- bytes that it occupies in memory.
-2. The type is not a mutable reference (`&mut T`).
-
-If both conditions are met, then Rust can safely create a new instance of the type by performing a **bitwise copy**
-of the original instance—this is often referred to as a `memcpy` operation, after the C standard library function
-that performs the bitwise copy.
-
-### Case study 1: `String`
-
-`String` is a type that doesn't implement `Copy`.
-Why? Because it manages an additional resource: the heap-allocated memory buffer that stores the string's data.
-
-Let's imagine that Rust allowed `String` to implement `Copy`.
-Then, when a new `String` instance is created by performing a bitwise copy of the original instance, both the original
-and the new instance would point to the same memory buffer:
-
-```text
- s copied_s
- +---------+--------+----------+ +---------+--------+----------+
- | pointer | length | capacity | | pointer | length | capacity |
- | | | 5 | 5 | | | | 5 | 5 |
- +--|------+--------+----------+ +--|------+--------+----------+
- | |
- | |
- v |
- +---+---+---+---+---+ |
- | H | e | l | l | o | |
- +---+---+---+---+---+ |
- ^ |
- | |
- +------------------------------------+
-```
-
-This is bad!
-Both `String` instances would try to free the memory buffer when they go out of scope,
-leading to a double-free error.
-You could also create two distinct `&mut String` references that point to the same memory buffer,
-violating Rust's borrowing rules.
-
-### Case study 2: `u32`
-
-`u32` implements `Copy`. All integer types do, in fact.
-An integer is "just" the bytes that represent the number in memory. There's nothing more!
-If you copy those bytes, you get another perfectly valid integer instance.
-Nothing bad can happen, so Rust allows it.
-
-### Case study 3: `&mut u32`
-
-When we introduced ownership and mutable borrows, we stated one rule quite clearly: there
-can only ever be *one* mutable borrow of a value at any given time.
-That's why `&mut u32` doesn't implement `Copy`, even though `u32` does.
-
-If `&mut u32` implemented `Copy`, you could create multiple mutable references to
-the same value and modify it in multiple places at the same time.
-That'd be a violation of Rust's borrowing rules!
-It follows that `&mut T` never implements `Copy`, no matter what `T` is.
-
-## Implementing `Copy`
-
-In most cases, you don't need to manually implement `Copy`.
-You can just derive it, like this:
-
-```rust
-#[derive(Copy, Clone)]
-struct MyStruct {
- field: u32,
-}
-```
-
-## References
-
-- The exercise for this section is located in `exercises/04_traits/11_copy`
--- /dev/null
+# Copying values, pt. 2
+
+Let's consider the same example as before, but with a slight twist: using `u32` rather than `String` as a type.
+
+```rust
+fn consumer(s: u32) { /* */ }
+
+fn example() {
+ let s: u32 = 5;
+ consumer(s);
+ let t = s + 1;
+}
+```
+
+It'll compile without errors! What's going on here? What's the difference between `String` and `u32`
+that makes the latter work without `.clone()`?
+
+## `Copy`
+
+`Copy` is another trait defined in Rust's standard library:
+
+```rust
+pub trait Copy: Clone { }
+```
+
+It is a marker trait, just like `Sized`.
+
+If a type implements `Copy`, there's no need to call `.clone()` to create a new instance of the type:
+Rust does it **implicitly** for you.
+`u32` is an example of a type that implements `Copy`, which is why the example above compiles without errors:
+when `consumer(s)` is called, Rust creates a new `u32` instance by performing a **bitwise copy** of `s`,
+and then passes that new instance to `consumer`. It all happens behind the scenes, without you having to do anything.
+
+## What can be `Copy`?
+
+`Copy` is not equivalent to "automatic cloning", although it implies it.
+Types must meet a few requirements in order to be allowed to implement `Copy`.
+
+First of all, it must implement `Clone`, since `Copy` is a subtrait of `Clone`.
+This makes sense: if Rust can create a new instance of a type _implicitly_, it should
+also be able to create a new instance _explicitly_ by calling `.clone()`.
+
+That's not all, though. A few more conditions must be met:
+
+1. The type doesn't manage any _additional_ resources (e.g. heap memory, file handles, etc.) beyond the `std::mem::size_of`
+ bytes that it occupies in memory.
+2. The type is not a mutable reference (`&mut T`).
+
+If both conditions are met, then Rust can safely create a new instance of the type by performing a **bitwise copy**
+of the original instance—this is often referred to as a `memcpy` operation, after the C standard library function
+that performs the bitwise copy.
+
+### Case study 1: `String`
+
+`String` is a type that doesn't implement `Copy`.
+Why? Because it manages an additional resource: the heap-allocated memory buffer that stores the string's data.
+
+Let's imagine that Rust allowed `String` to implement `Copy`.
+Then, when a new `String` instance is created by performing a bitwise copy of the original instance, both the original
+and the new instance would point to the same memory buffer:
+
+```text
+ s copied_s
+ +---------+--------+----------+ +---------+--------+----------+
+ | pointer | length | capacity | | pointer | length | capacity |
+ | | | 5 | 5 | | | | 5 | 5 |
+ +--|------+--------+----------+ +--|------+--------+----------+
+ | |
+ | |
+ v |
+ +---+---+---+---+---+ |
+ | H | e | l | l | o | |
+ +---+---+---+---+---+ |
+ ^ |
+ | |
+ +------------------------------------+
+```
+
+This is bad!
+Both `String` instances would try to free the memory buffer when they go out of scope,
+leading to a double-free error.
+You could also create two distinct `&mut String` references that point to the same memory buffer,
+violating Rust's borrowing rules.
+
+### Case study 2: `u32`
+
+`u32` implements `Copy`. All integer types do, in fact.
+An integer is "just" the bytes that represent the number in memory. There's nothing more!
+If you copy those bytes, you get another perfectly valid integer instance.
+Nothing bad can happen, so Rust allows it.
+
+### Case study 3: `&mut u32`
+
+When we introduced ownership and mutable borrows, we stated one rule quite clearly: there
+can only ever be *one* mutable borrow of a value at any given time.
+That's why `&mut u32` doesn't implement `Copy`, even though `u32` does.
+
+If `&mut u32` implemented `Copy`, you could create multiple mutable references to
+the same value and modify it in multiple places at the same time.
+That'd be a violation of Rust's borrowing rules!
+It follows that `&mut T` never implements `Copy`, no matter what `T` is.
+
+## Implementing `Copy`
+
+In most cases, you don't need to manually implement `Copy`.
+You can just derive it, like this:
+
+```rust
+#[derive(Copy, Clone)]
+struct MyStruct {
+ field: u32,
+}
+```
+
+## References
+
+- The exercise for this section is located in `exercises/04_traits/11_copy`
+++ /dev/null
-# The `Drop` trait
-
-When we introduced [destructors](../03_ticket_v1/11_destructor),
-we mentioned that the `drop` function:
-
-1. reclaims the memory occupied by the type (i.e. `std::mem::size_of` bytes)
-2. cleans up any additional resources that the value might be managing (e.g. the heap buffer of a `String`)
-
-Step 2. is where the `Drop` trait comes in.
-
-```rust
-pub trait Drop {
- fn drop(&mut self);
-}
-```
-
-The `Drop` trait is a mechanism for you to define _additional_ cleanup logic for your types,
-beyond what the compiler does for you automatically.
-Whatever you put in the `drop` method will be executed when the value goes out of scope.
-
-## `Drop` and `Copy`
-
-When talking about the `Copy` trait, we said that a type can't implement `Copy` if it
-manages additional resources beyond the `std::mem::size_of` bytes that it occupies in memory.
-
-You might wonder: how does the compiler know if a type manages additional resources?
-That's right: `Drop` trait implementations!
-If your type has an explicit `Drop` implementation, the compiler will assume
-that your type has additional resources attached to it and won't allow you to implement `Copy`.
-
-```rust
-// This is a unit struct, i.e. a struct with no fields.
-#[derive(Clone, Copy)]
-struct MyType;
-
-impl Drop for MyType {
- fn drop(&mut self) {
- // We don't need to do anything here,
- // it's enough to have an "empty" Drop implementation
- }
-}
-```
-
-The compiler will complain with this error message:
-
-```text
-error[E0184]: the trait `Copy` cannot be implemented for this type; the type has a destructor
- --> src/lib.rs:2:17
- |
-2 | #[derive(Clone, Copy)]
- | ^^^^ `Copy` not allowed on types with destructors
-```
-
-## References
-
-- The exercise for this section is located in `exercises/04_traits/12_drop`
--- /dev/null
+# The `Drop` trait
+
+When we introduced [destructors](../03_ticket_v1/11_destructor),
+we mentioned that the `drop` function:
+
+1. reclaims the memory occupied by the type (i.e. `std::mem::size_of` bytes)
+2. cleans up any additional resources that the value might be managing (e.g. the heap buffer of a `String`)
+
+Step 2. is where the `Drop` trait comes in.
+
+```rust
+pub trait Drop {
+ fn drop(&mut self);
+}
+```
+
+The `Drop` trait is a mechanism for you to define _additional_ cleanup logic for your types,
+beyond what the compiler does for you automatically.
+Whatever you put in the `drop` method will be executed when the value goes out of scope.
+
+## `Drop` and `Copy`
+
+When talking about the `Copy` trait, we said that a type can't implement `Copy` if it
+manages additional resources beyond the `std::mem::size_of` bytes that it occupies in memory.
+
+You might wonder: how does the compiler know if a type manages additional resources?
+That's right: `Drop` trait implementations!
+If your type has an explicit `Drop` implementation, the compiler will assume
+that your type has additional resources attached to it and won't allow you to implement `Copy`.
+
+```rust
+// This is a unit struct, i.e. a struct with no fields.
+#[derive(Clone, Copy)]
+struct MyType;
+
+impl Drop for MyType {
+ fn drop(&mut self) {
+ // We don't need to do anything here,
+ // it's enough to have an "empty" Drop implementation
+ }
+}
+```
+
+The compiler will complain with this error message:
+
+```text
+error[E0184]: the trait `Copy` cannot be implemented for this type; the type has a destructor
+ --> src/lib.rs:2:17
+ |
+2 | #[derive(Clone, Copy)]
+ | ^^^^ `Copy` not allowed on types with destructors
+```
+
+## References
+
+- The exercise for this section is located in `exercises/04_traits/12_drop`
+++ /dev/null
-# Wrapping up
-
-We've covered quite a few different traits in this chapter—and we've only scratched the surface!
-It may feel like you have a lot to remember, but don't worry: you'll bump into these traits
-so often when writing Rust code that they'll soon become second nature.
-
-Before moving on, let's go through one last exercise to consolidate what we've learned.
-You'll have minimal guidance this time—just the exercise description and the tests to guide you.
-
-## References
-
-- The exercise for this section is located in `exercises/04_traits/13_outro`
--- /dev/null
+# Wrapping up
+
+We've covered quite a few different traits in this chapter—and we've only scratched the surface!
+It may feel like you have a lot to remember, but don't worry: you'll bump into these traits
+so often when writing Rust code that they'll soon become second nature.
+
+Before moving on, let's go through one last exercise to consolidate what we've learned.
+You'll have minimal guidance this time—just the exercise description and the tests to guide you.
+
+## References
+
+- The exercise for this section is located in `exercises/04_traits/13_outro`
+++ /dev/null
-[package]
-name = "str_slice"
-version = "0.1.0"
-edition = "2021"
-
-[dev-dependencies]
-common = { path = "../../../helpers/common" }
+++ /dev/null
-// TODO: Re-implement `Ticket`'s accessor methods. This time return a `&str` rather than a `&String`.
-
-pub struct Ticket {
- title: String,
- description: String,
- status: String,
-}
-
-impl Ticket {
- pub fn new(title: String, description: String, status: String) -> Ticket {
- if title.is_empty() {
- panic!("Title cannot be empty");
- }
- if title.len() > 50 {
- panic!("Title cannot be longer than 50 bytes");
- }
- if description.is_empty() {
- panic!("Description cannot be empty");
- }
- if description.len() > 500 {
- panic!("Description cannot be longer than 500 bytes");
- }
- if status != "To-Do" && status != "In Progress" && status != "Done" {
- panic!("Only `To-Do`, `In Progress`, and `Done` statuses are allowed");
- }
-
- Ticket {
- title,
- description,
- status,
- }
- }
-
- pub fn title(&self) -> &String {
- &self.title
- }
-
- pub fn description(&self) -> &String {
- &self.description
- }
-
- pub fn status(&self) -> &String {
- &self.status
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use common::{valid_description, valid_title};
- use std::any::{Any, TypeId};
-
- #[test]
- fn test_type() {
- let ticket = Ticket::new(valid_title(), valid_description(), "To-Do".to_string());
- // Some dark magic to verify that you used the expected return types
- assert_eq!(TypeId::of::<str>(), ticket.title().type_id());
- assert_eq!(TypeId::of::<str>(), ticket.description().type_id());
- assert_eq!(TypeId::of::<str>(), ticket.status().type_id());
- }
-}
--- /dev/null
+[package]
+name = "trait_bounds"
+version = "0.1.0"
+edition = "2021"
\ No newline at end of file
--- /dev/null
+// TODO: Add the necessary trait bounds to `min` so that it compiles successfully.
+// Refer to `std::cmp` for more information on the traits you might need.
+//
+// Note: there are different trait bounds that'll make the compiler happy, but they come with
+// different _semantics_. We'll cover those differences later in the course when we talk about ordered
+// collections (e.g. BTreeMap).
+
+/// Return the minimum of two values.
+pub fn min<T>(left: T, right: T) -> T {
+ if left <= right {
+ left
+ } else {
+ right
+ }
+}
+++ /dev/null
-[package]
-name = "deref"
-version = "0.1.0"
-edition = "2021"
\ No newline at end of file
+++ /dev/null
-// TODO: whenever `title` and `description` are returned via their accessor methods, they
-// should be normalized—i.e. leading and trailing whitespace should be removed.
-// There is a method in Rust's standard library that can help with this, but you won't
-// find it in the documentation for `String`.
-// Can you figure out where it is defined and how to use it?
-
-pub struct Ticket {
- title: String,
- description: String,
- status: String,
-}
-
-impl Ticket {
- pub fn title(&self) -> &str {
- todo!()
- }
-
- pub fn description(&self) -> &str {
- todo!()
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_normalization() {
- let ticket = Ticket {
- title: " A title ".to_string(),
- description: " A description ".to_string(),
- status: "To-Do".to_string(),
- };
-
- assert_eq!("A title", ticket.title());
- assert_eq!("A description", ticket.description());
- }
-}
--- /dev/null
+[package]
+name = "str_slice"
+version = "0.1.0"
+edition = "2021"
+
+[dev-dependencies]
+common = { path = "../../../helpers/common" }
--- /dev/null
+// TODO: Re-implement `Ticket`'s accessor methods. This time return a `&str` rather than a `&String`.
+
+pub struct Ticket {
+ title: String,
+ description: String,
+ status: String,
+}
+
+impl Ticket {
+ pub fn new(title: String, description: String, status: String) -> Ticket {
+ if title.is_empty() {
+ panic!("Title cannot be empty");
+ }
+ if title.len() > 50 {
+ panic!("Title cannot be longer than 50 bytes");
+ }
+ if description.is_empty() {
+ panic!("Description cannot be empty");
+ }
+ if description.len() > 500 {
+ panic!("Description cannot be longer than 500 bytes");
+ }
+ if status != "To-Do" && status != "In Progress" && status != "Done" {
+ panic!("Only `To-Do`, `In Progress`, and `Done` statuses are allowed");
+ }
+
+ Ticket {
+ title,
+ description,
+ status,
+ }
+ }
+
+ pub fn title(&self) -> &String {
+ &self.title
+ }
+
+ pub fn description(&self) -> &String {
+ &self.description
+ }
+
+ pub fn status(&self) -> &String {
+ &self.status
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use common::{valid_description, valid_title};
+ use std::any::{Any, TypeId};
+
+ #[test]
+ fn test_type() {
+ let ticket = Ticket::new(valid_title(), valid_description(), "To-Do".to_string());
+ // Some dark magic to verify that you used the expected return types
+ assert_eq!(TypeId::of::<str>(), ticket.title().type_id());
+ assert_eq!(TypeId::of::<str>(), ticket.description().type_id());
+ assert_eq!(TypeId::of::<str>(), ticket.status().type_id());
+ }
+}
--- /dev/null
+[package]
+name = "deref"
+version = "0.1.0"
+edition = "2021"
\ No newline at end of file
--- /dev/null
+// TODO: whenever `title` and `description` are returned via their accessor methods, they
+// should be normalized—i.e. leading and trailing whitespace should be removed.
+// There is a method in Rust's standard library that can help with this, but you won't
+// find it in the documentation for `String`.
+// Can you figure out where it is defined and how to use it?
+
+pub struct Ticket {
+ title: String,
+ description: String,
+ status: String,
+}
+
+impl Ticket {
+ pub fn title(&self) -> &str {
+ todo!()
+ }
+
+ pub fn description(&self) -> &str {
+ todo!()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_normalization() {
+ let ticket = Ticket {
+ title: " A title ".to_string(),
+ description: " A description ".to_string(),
+ status: "To-Do".to_string(),
+ };
+
+ assert_eq!("A title", ticket.title());
+ assert_eq!("A description", ticket.description());
+ }
+}
+++ /dev/null
-[package]
-name = "sized"
-version = "0.1.0"
-edition = "2021"
\ No newline at end of file
+++ /dev/null
-pub fn example() {
- // Trying to get the size of a str (or any other DST)
- // via `std::mem::size_of` will result in a compile-time error.
- //
- // TODO: Comment out the following line and move on to the next exercise.
- std::mem::size_of::<str>();
-}
+++ /dev/null
-[package]
-name = "from"
-version = "0.1.0"
-edition = "2021"
\ No newline at end of file
+++ /dev/null
-// TODO: Implement the `From` trait for the `WrappingU32` type to make `example` compile.
-
-pub struct WrappingU32 {
- value: u32,
-}
-
-fn example() {
- let wrapping: WrappingU32 = 42.into();
- let wrapping = WrappingU32::from(42);
-}
--- /dev/null
+[package]
+name = "sized"
+version = "0.1.0"
+edition = "2021"
\ No newline at end of file
--- /dev/null
+pub fn example() {
+ // Trying to get the size of a str (or any other DST)
+ // via `std::mem::size_of` will result in a compile-time error.
+ //
+ // TODO: Comment out the following line and move on to the next exercise.
+ std::mem::size_of::<str>();
+}
+++ /dev/null
-[package]
-name = "assoc_vs_generic"
-version = "0.1.0"
-edition = "2021"
\ No newline at end of file
+++ /dev/null
-// TODO: Define a new trait, `Power`, that has a method `power` that raises `self`
-// to the power of `n`.
-// The trait definition and its implementations should be enough to get
-// the tests to compile and pass.
-//
-// Recommendation: you may be tempted to write a generic implementation to handle
-// all cases at once. However, this is fairly complicated and requires the use of
-// additional crates (i.e. `num-traits`).
-// Even then, it might be preferable to use a simple macro instead to avoid
-// the complexity of a highly generic implementation. Check out the
-// "Little book of Rust macros" (https://veykril.github.io/tlborm/) if you're
-// interested in learning more about it.
-// You don't have to though: it's perfectly okay to write three separate
-// implementations manually. Venture further only if you're curious.
-
-#[cfg(test)]
-mod tests {
- use super::Power;
-
- #[test]
- fn test_power_u16() {
- let x: u32 = 2_u32.power(3u16);
- assert_eq!(x, 8);
- }
-
- #[test]
- fn test_power_u32() {
- let x: u32 = 2_u32.power(3u32);
- assert_eq!(x, 8);
- }
-
- #[test]
- fn test_power_ref_u32() {
- let x: u32 = 2_u32.power(&3u32);
- assert_eq!(x, 8);
- }
-}
--- /dev/null
+[package]
+name = "from"
+version = "0.1.0"
+edition = "2021"
\ No newline at end of file
--- /dev/null
+// TODO: Implement the `From` trait for the `WrappingU32` type to make `example` compile.
+
+pub struct WrappingU32 {
+ value: u32,
+}
+
+fn example() {
+ let wrapping: WrappingU32 = 42.into();
+ let wrapping = WrappingU32::from(42);
+}
--- /dev/null
+[package]
+name = "assoc_vs_generic"
+version = "0.1.0"
+edition = "2021"
\ No newline at end of file
--- /dev/null
+// TODO: Define a new trait, `Power`, that has a method `power` that raises `self`
+// to the power of `n`.
+// The trait definition and its implementations should be enough to get
+// the tests to compile and pass.
+//
+// Recommendation: you may be tempted to write a generic implementation to handle
+// all cases at once. However, this is fairly complicated and requires the use of
+// additional crates (i.e. `num-traits`).
+// Even then, it might be preferable to use a simple macro instead to avoid
+// the complexity of a highly generic implementation. Check out the
+// "Little book of Rust macros" (https://veykril.github.io/tlborm/) if you're
+// interested in learning more about it.
+// You don't have to though: it's perfectly okay to write three separate
+// implementations manually. Venture further only if you're curious.
+
+#[cfg(test)]
+mod tests {
+ use super::Power;
+
+ #[test]
+ fn test_power_u16() {
+ let x: u32 = 2_u32.power(3u16);
+ assert_eq!(x, 8);
+ }
+
+ #[test]
+ fn test_power_u32() {
+ let x: u32 = 2_u32.power(3u32);
+ assert_eq!(x, 8);
+ }
+
+ #[test]
+ fn test_power_ref_u32() {
+ let x: u32 = 2_u32.power(&3u32);
+ assert_eq!(x, 8);
+ }
+}
+++ /dev/null
-[package]
-name = "clone"
-version = "0.1.0"
-edition = "2021"
\ No newline at end of file
+++ /dev/null
-// TODO: add the necessary `Clone` implementations (and invocations)
-// to get the code to compile.
-
-pub fn summary(ticket: Ticket) -> (Ticket, Summary) {
- (ticket, ticket.summary())
-}
-
-pub struct Ticket {
- pub title: String,
- pub description: String,
- pub status: String,
-}
-
-impl Ticket {
- pub fn summary(self) -> Summary {
- Summary {
- title: self.title,
- status: self.status,
- }
- }
-}
-
-pub struct Summary {
- pub title: String,
- pub status: String,
-}
--- /dev/null
+[package]
+name = "clone"
+version = "0.1.0"
+edition = "2021"
\ No newline at end of file
--- /dev/null
+// TODO: add the necessary `Clone` implementations (and invocations)
+// to get the code to compile.
+
+pub fn summary(ticket: Ticket) -> (Ticket, Summary) {
+ (ticket, ticket.summary())
+}
+
+pub struct Ticket {
+ pub title: String,
+ pub description: String,
+ pub status: String,
+}
+
+impl Ticket {
+ pub fn summary(self) -> Summary {
+ Summary {
+ title: self.title,
+ status: self.status,
+ }
+ }
+}
+
+pub struct Summary {
+ pub title: String,
+ pub status: String,
+}
+++ /dev/null
-[package]
-name = "copy"
-version = "0.1.0"
-edition = "2021"
\ No newline at end of file
+++ /dev/null
-// TODO: implement the necessary traits to make the test compile and pass.
-// You *can't* modify the test.
-
-pub struct WrappingU32 {
- value: u32,
-}
-
-impl WrappingU32 {
- pub fn new(value: u32) -> Self {
- Self { value }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_ops() {
- let x = WrappingU32::new(42);
- let y = WrappingU32::new(31);
- let z = WrappingU32::new(u32::MAX);
- assert_eq!(x + y + y + z, WrappingU32::new(103));
- }
-}
--- /dev/null
+[package]
+name = "copy"
+version = "0.1.0"
+edition = "2021"
\ No newline at end of file
--- /dev/null
+// TODO: implement the necessary traits to make the test compile and pass.
+// You *can't* modify the test.
+
+pub struct WrappingU32 {
+ value: u32,
+}
+
+impl WrappingU32 {
+ pub fn new(value: u32) -> Self {
+ Self { value }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_ops() {
+ let x = WrappingU32::new(42);
+ let y = WrappingU32::new(31);
+ let z = WrappingU32::new(u32::MAX);
+ assert_eq!(x + y + y + z, WrappingU32::new(103));
+ }
+}
+++ /dev/null
-[package]
-name = "drop"
-version = "0.1.0"
-edition = "2021"
\ No newline at end of file
+++ /dev/null
-// TODO: implement a so-called "Drop bomb": a type that panics when dropped
-// unless a certain operation has been performed on it.
-// You can see the expected API in the tests below.
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- #[should_panic]
- fn test_drop_bomb() {
- let bomb = DropBomb::new();
- // The bomb should panic when dropped
- }
-
- #[test]
- fn test_defused_drop_bomb() {
- let mut bomb = DropBomb::new();
- bomb.defuse();
- // The bomb should not panic when dropped
- // since it has been defused
- }
-}
--- /dev/null
+[package]
+name = "drop"
+version = "0.1.0"
+edition = "2021"
\ No newline at end of file
--- /dev/null
+// TODO: implement a so-called "Drop bomb": a type that panics when dropped
+// unless a certain operation has been performed on it.
+// You can see the expected API in the tests below.
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ #[should_panic]
+ fn test_drop_bomb() {
+ let bomb = DropBomb::new();
+ // The bomb should panic when dropped
+ }
+
+ #[test]
+ fn test_defused_drop_bomb() {
+ let mut bomb = DropBomb::new();
+ bomb.defuse();
+ // The bomb should not panic when dropped
+ // since it has been defused
+ }
+}
+++ /dev/null
-[package]
-name = "outro_03"
-version = "0.1.0"
-edition = "2021"
\ No newline at end of file
+++ /dev/null
-// TODO: Define a new `SaturatingU16` type.
-// It should hold a `u16` value.
-// It should provide conversions from `u16`, `u8`, `&u16` and `&u8`.
-// It should support addition with a right-hand side of type
-// SaturatingU16, u16, &u16, and &SaturatingU16. Addition should saturate at the
-// maximum value for `u16`.
-// It should be possible to compare it with another `SaturatingU16` or a `u16`.
-// It should be possible to print its debug representation.
-//
-// Tests are located in the `tests` folder—pay attention to the visibility of your types and methods.
+++ /dev/null
-use outro_03::SaturatingU16;
-
-#[test]
-fn test_saturating_u16() {
- let a: SaturatingU16 = (&10u8).into();
- let b: SaturatingU16 = 5u8.into();
- let c: SaturatingU16 = u16::MAX.into();
- let d: SaturatingU16 = (&1u16).into();
-
- assert_eq!(a + b, SaturatingU16::from(15u16));
- assert_eq!(a + c, SaturatingU16::from(u16::MAX));
- assert_eq!(a + d, SaturatingU16::from(11u16));
- assert_eq!(a + a, 20u16);
- assert_eq!(a + 5u16, 15u16);
- assert_eq!(a + &u16::MAX, SaturatingU16::from(u16::MAX));
-}
--- /dev/null
+[package]
+name = "outro_03"
+version = "0.1.0"
+edition = "2021"
\ No newline at end of file
--- /dev/null
+// TODO: Define a new `SaturatingU16` type.
+// It should hold a `u16` value.
+// It should provide conversions from `u16`, `u8`, `&u16` and `&u8`.
+// It should support addition with a right-hand side of type
+// SaturatingU16, u16, &u16, and &SaturatingU16. Addition should saturate at the
+// maximum value for `u16`.
+// It should be possible to compare it with another `SaturatingU16` or a `u16`.
+// It should be possible to print its debug representation.
+//
+// Tests are located in the `tests` folder—pay attention to the visibility of your types and methods.
--- /dev/null
+use outro_03::SaturatingU16;
+
+#[test]
+fn test_saturating_u16() {
+ let a: SaturatingU16 = (&10u8).into();
+ let b: SaturatingU16 = 5u8.into();
+ let c: SaturatingU16 = u16::MAX.into();
+ let d: SaturatingU16 = (&1u16).into();
+
+ assert_eq!(a + b, SaturatingU16::from(15u16));
+ assert_eq!(a + c, SaturatingU16::from(u16::MAX));
+ assert_eq!(a + d, SaturatingU16::from(11u16));
+ assert_eq!(a + a, 20u16);
+ assert_eq!(a + 5u16, 15u16);
+ assert_eq!(a + &u16::MAX, SaturatingU16::from(u16::MAX));
+}