Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into amanjeev/some-notes
Browse files Browse the repository at this point in the history
  • Loading branch information
amanjeev committed Aug 21, 2023
2 parents 3474b1b + 05cc19b commit 6e6ce84
Show file tree
Hide file tree
Showing 20 changed files with 330 additions and 562 deletions.
10 changes: 8 additions & 2 deletions training-slides/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,10 @@
- [Drop, Panic and Abort](./drop-panic-abort.md)
- [Dynamic Dispatch](./dynamic-dispatch.md)
- [Foreign Function Interface](./ffi.md)
- [libcore and libstd](./libcore-and-libstd.md)
- [Macros](./macros.md)
- [Property Testing](./property-testing.md)
- [Send and Sync](./send-and-sync.md)
- [Serde](./serde.md)
- [Standard Types](./standard-types.md)
- [Strings](./strings.md)
- [Testing](./testing.md)
- [The stdlib](./std-lib-tour.md)
Expand All @@ -55,3 +53,11 @@
- [Using Cargo](./using-cargo.md)
- [Dependency Management with Cargo](./dependency-management.md)
- [Rust Projects Build Time](./rust-build-time.md)
- [Using Types to encode State (TBC)](./type-state.md)
- [Overview of Embedded Rust (TBC)](./rust-embedded.md)
- [Working with no-std (TBC)](./no-std.md)
- [Booting a Cortex-M Microcontroller (TBC)](./cortex-m.md)
- [PACs and svd2rust (TBC)](./pac-svd2rust.md)
- [The Embedded HAL and its implementations (TBC)](./embedded-hals.md)
- [Using RTIC v1 (TBC)](./rtic-v1.md)
- [Writing a new target (TBC)](./custom-target.md)
2 changes: 1 addition & 1 deletion training-slides/src/compound-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ fn check_shape(shape: &Shape) {

Note:

Why is there a `*` in front of `radius` in `match`?
You might ask "Why is there a `*` in front of `radius` in `match`?" - It's because you only have an `&Shape` and so if you pattern match on a value of that type, you can only get a `&` reference to its contents. Unfortunately, the Rust operator `>` (or rather, the trait `std::cmp::PartialOrd` is implemented to compare two `i32` values, but not to compare an `i32` with an `&i32`.

## Combining patterns

Expand Down
1 change: 1 addition & 0 deletions training-slides/src/cortex-m.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Booting a Cortex-M Microcontroller
1 change: 1 addition & 0 deletions training-slides/src/custom-target.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Writing a new target
1 change: 1 addition & 0 deletions training-slides/src/embedded-hals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# The Embedded HAL and its implementations
152 changes: 86 additions & 66 deletions training-slides/src/generics.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ fn print_stuff<X>(value: X) {

Note:

Default bounds are `Sized`, finding size is one thing that you can do.
Default bounds are `Sized`, so finding the size of the type is one thing that you can do. You can also take a reference or a pointer to the value.

## Generic Implementations

Expand Down Expand Up @@ -115,60 +115,54 @@ error[E0599]: no method named `magnitude` found for struct `Vector<{integer}>` i
For more information about this error, try `rustc --explain E0599`.
```

## Generic Traits
## Adding Bounds

* Generics aren't much use without bounds.
* A bound says which traits must be implemented on any type used for that type parameter
* You can apply the bounds on the type, or a function/method, or both.

Traits can have type parameters.
## Adding Bounds - Example

```rust []
trait HasArea<T> {
fn area(&self) -> T;
trait HasArea {
fn area(&self) -> f32;
}

// Here we only accept a shape where the `T` in `HasArea<T>` is `f64`
fn print_area(shape: &dyn HasArea<f64>) {

fn print_area<T>(shape: &T) where T: HasArea {
let area = shape.area();
println!("Area = {area:0.6}");
println!("Area = {area:?}");
}

struct UnitSquare;

impl HasArea<f64> for UnitSquare {
fn area(&self) -> f64 {
impl HasArea for UnitSquare {
fn area(&self) -> f32 {
1.0
}
}

impl HasArea<u32> for UnitSquare {
fn area(&self) -> u32 {
1
}
}

fn main() {
let u = UnitSquare;
print_area(&u);
}
```

## Adding Bounds

* Generics aren't much use without bounds.
* You can apply the bounds on the type, or a function, or both.
## Adding Bounds - Alt. Example

```rust []
trait HasArea<T> {
fn area(&self) -> T;
trait HasArea {
fn area(&self) -> f32;
}

fn print_area<T>(shape: &dyn HasArea<T>) where T: std::fmt::Debug {
fn print_area<T: HasArea>(shape: &T) {
let area = shape.area();
println!("Area = {area:?}");
}

struct UnitSquare;

impl HasArea<f64> for UnitSquare {
fn area(&self) -> f64 {
impl HasArea for UnitSquare {
fn area(&self) -> f32 {
1.0
}
}
Expand All @@ -179,24 +173,11 @@ fn main() {
}
```

## Adding Bounds

The bounds can also go here:

```rust []
trait HasArea<T> {
fn area(&self) -> T;
}

fn print_area<T: std::fmt::Debug>(shape: &dyn HasArea<T>) {
let area = shape.area();
println!("Area = {area:?}");
}
```

Note:

This is exactly equivalent to the previous example, but shorter.
This is exactly equivalent to the previous example, but shorter. However, if you
end up with a large set of bounds, they are easier to format when at the end of
the line.

## General Rule

Expand All @@ -208,42 +189,27 @@ This is exactly equivalent to the previous example, but shorter.
You can specify multiple bounds.

```rust []
trait HasArea<T> {
fn area(&self) -> T;
trait HasArea {
fn area(&self) -> f32;
}

fn print_areas<T: std::fmt::Debug + std::cmp::PartialEq>(
shape1: &dyn HasArea<T>,
shape2: &dyn HasArea<T>,
) {
let area1 = shape1.area();
let area2 = shape2.area();
if area1 == area2 {
println!("Both areas are {area1:?}");
} else {
println!("{area1:?}, {area2:?}");
}
fn print_area<T: std::fmt::Debug + HasArea>(shape: &T) {
println!("Shape {:?} has area {}", shape, shape.area());
}

#[derive(Debug)]
struct UnitSquare;

impl HasArea<f64> for UnitSquare {
fn area(&self) -> f64 {
1.0
}
impl HasArea for UnitSquare {
fn area(&self) -> f32 { 1.0 }
}

fn main() {
let u1 = UnitSquare;
let u2 = UnitSquare;
print_areas(&u1, &u2);
let u = UnitSquare;
print_area(&u);
}
```

Note:

Try removing the `std::cmp::PartialEq` bound and see what it says about using the `==` operator on type `T`.

## impl Trait

* The `impl Trait` syntax in argument position was just *syntactic sugar*.
Expand Down Expand Up @@ -276,6 +242,60 @@ Some types that cannot be written out, like the closure, can be expressed as ret
* Don't reach for it in the first instance...
* Try and just use concrete types?

## Generic over Constants

In Rust 1.51, we gained the ability to be generic over *constant values* too.

```rust []
struct Polygon<const SIDES: u8> {
colour: u32
}

impl<const SIDES: u8> Polygon<SIDES> {
fn new(colour: u32) -> Polygon<SIDES> { Polygon { colour } }
fn print(&self) { println!("{} sides, colour=0x{:06x}", SIDES, self.colour); }
}

fn main() {
let triangle: Polygon<3> = Polygon::new(0x00FF00);
triangle.print();
}
```

Note:

`SIDES` is a property of the type, and doesn't occupy any memory within any
values of that type at run-time - the constant is pasted in wherever it is used.

## Generic Traits

Traits themselves can have type parameters too!

```rust []
trait HasArea<T> {
fn area(&self) -> T;
}

// Here we only accept a shape where the `U` in `HasArea<Y>` is printable
fn print_area<T, U>(shape: &T) where T: HasArea<U>, U: std::fmt::Debug {
let area = shape.area();
println!("Area = {area:?}");
}

struct UnitSquare;

impl HasArea<f64> for UnitSquare {
fn area(&self) -> f64 {
1.0
}
}

fn main() {
let u = UnitSquare;
print_area(&u);
}
```

## Special Bounds

* Some bounds apply automatically
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion training-slides/src/imports-modules-and-visibility.md

This file was deleted.

1 change: 0 additions & 1 deletion training-slides/src/libcore-and-libstd.md

This file was deleted.

27 changes: 24 additions & 3 deletions training-slides/src/methods-traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,12 @@ impl Square {

```rust []
trait HasArea {
const M2_PER_ACRE: f64 = 4046.86;

/// Get the area, in m².
fn area_m2(&self) -> f64;

/// Get the area, in acres.
fn area_acres(&self) -> f64 {
self.area_m2() * Self::M2_PER_ACRE
self.area_m2() / 4046.86
}
}
```
Expand All @@ -150,6 +148,29 @@ fn main() {
}
```

## Associated Types

A trait can also have some *associated types*, which are type aliases chosen when
the trait is *implemented*.

```rust
trait Iterator {
type Item;

fn next(&mut self) -> Option<Self::Item>;
}

struct MyRange { start: u32, len: u32 }

impl Iterator for MyRange {
type Item = u32;

fn next(&mut self) -> Option<Self::Item> {
todo!();
}
}
```

## Rules for Implementing

You can only *implement* a *Trait* for a *Type* if:
Expand Down
1 change: 1 addition & 0 deletions training-slides/src/no-std.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Working with no-std
2 changes: 1 addition & 1 deletion training-slides/src/ownership.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ Try adding more excitement by calling `add_excitement` multiple times.

Note:

Why are there two types of Borrowed string types (`&String` and `&str`)?
Why are there two types of Borrowed string types (`&String` and `&str`)? The first is a reference to a `struct` (`std::string::String`, specifically), and the latter is a built-in slice type which points at some bytes in memory which are valid UTF-8 encoded characters.

## An aside: Method Calls

Expand Down
1 change: 1 addition & 0 deletions training-slides/src/pac-svd2rust.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# PACs and svd2rust
1 change: 1 addition & 0 deletions training-slides/src/rtic-v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Using RTIC v1
1 change: 1 addition & 0 deletions training-slides/src/rust-embedded.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Overview of Embedded Rust
Loading

0 comments on commit 6e6ce84

Please sign in to comment.