Skip to content

Commit df8e2e8

Browse files
committed
Static Guarantees becomes Typestate Programming, as per @japaric 's suggestion
1 parent f0084e0 commit df8e2e8

File tree

7 files changed

+74
-8
lines changed

7 files changed

+74
-8
lines changed

src/SUMMARY.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ more information and coordination
2424
- [The Borrow Checker](./peripherals/borrowck.md)
2525
- [Singletons](./peripherals/singletons.md)
2626
- [Peripherals in Rust](./peripherals/rusty.md)
27-
- [Static Guarantees](./static-guarantees/static-guarantees.md)
28-
- [Strong Types](./static-guarantees/strong-types.md)
29-
- [Design Contracts](./static-guarantees/design-contracts.md)
30-
- [Zero Cost Abstractions](./static-guarantees/zero-cost-abstractions.md)
27+
- [Typestate Programming](./typestate-programming/typestate-programming.md)
28+
- [Peripherals as State Machines](./typestate-programming/state-machines.md)
29+
- [Design Contracts](./typestate-programming/design-contracts.md)
30+
- [Zero Cost Abstractions](./typestate-programming/zero-cost-abstractions.md)
3131
- [Portability](./portability/portability.md)
3232
- [The Trait System](./portability/traits.md)
3333
<!-- TODO: Define more sections -->

src/static-guarantees/static-guarantees.md

-3
This file was deleted.

src/static-guarantees/strong-types.md

-1
This file was deleted.

src/static-guarantees/design-contracts.md renamed to src/typestate-programming/design-contracts.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Design Contracts
22

3+
In
4+
35
```rust
46
struct GpioPin; struct InputGpio; struct OutputGpio;
57

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Peripherals as State Machines
2+
3+
The peripherals of a microcontroller can be thought of as set of state machines. For example, a simplified [GPIO pin]
4+
5+
[GPIO pin]: https://en.wikipedia.org/wiki/General-purpose_input/output
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Typestate Programming
2+
3+
The concept of [typestates] describes the encoding of information about the current state of an object into the type of that object. Although this can sound a little arcane, if you have used the [Builder Pattern] in Rust, you have already started using Typestate Programming!
4+
5+
[typestates]: https://en.wikipedia.org/wiki/Typestate_analysis
6+
[Builder Pattern]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html
7+
8+
```rust
9+
#[derive(Debug)]
10+
struct Foo {
11+
inner: u32,
12+
}
13+
14+
struct FooBuilder {
15+
a: u32,
16+
b: u32,
17+
}
18+
19+
impl FooBuilder {
20+
pub fn new(starter: u32) -> Self {
21+
Self {
22+
a: starter,
23+
b: starter,
24+
}
25+
}
26+
27+
pub fn double_a(self) -> Self {
28+
Self {
29+
a: self.a * 2,
30+
b: self.b,
31+
}
32+
}
33+
34+
pub fn into_foo(self) -> Foo {
35+
Foo {
36+
inner: self.a + self.b,
37+
}
38+
}
39+
}
40+
41+
fn main() {
42+
let x = FooBuilder::new(10)
43+
.double_a()
44+
.into_foo();
45+
46+
println!("{:#?}", x);
47+
}
48+
```
49+
50+
In this example, there is no direct way to create a `Foo` object. We must create a `FooBuilder`, and properly initialize it before we can obtain the `Foo` object we want.
51+
52+
This minimal example encodes two states:
53+
54+
* `FooBuilder`, which represents an "unconfigured", or "configuration in process" state
55+
* `Foo`, which represents a "configured", or "ready to use" state.
56+
57+
## Strong Types
58+
59+
Because Rust has a [Strong Type System], there is no easy way to magically create an instance of `Foo`, or to turn a `FooBuilder` into a `Foo` without calling the `into_foo()` method. Additionally, calling the `into_foo()` method consumes the original `FooBuilder` structure, meaning it can not be reused without the creation of a new instance.
60+
61+
[Strong Type System]: https://en.wikipedia.org/wiki/Strong_and_weak_typing
62+
63+
This allows us to represent the states of our system as types, and to include the necessary actions for state transitions into the methods that exchange one type for another. By creating a `FooBuilder`, and exchanging it for a `Foo` object, we have walked through the steps of a basic state machine.

0 commit comments

Comments
 (0)