1
0
mirror of https://github.com/google/comprehensive-rust.git synced 2025-08-08 00:12:51 +02:00

improve typestate pattern slides

This commit is contained in:
Glen De Cauwsemaecker
2025-08-03 20:32:50 +02:00
parent 11481c74e4
commit 6b04193735
4 changed files with 10 additions and 11 deletions

View File

@ -83,6 +83,7 @@ serialize struct start
system.
In the next slide, we will apply the **typestate pattern** to enforce correct
usage at compile time and make invalid states unrepresentable.
usage at compile time and make it impossible to call incompatible methods or
forget to do a required action.
</details>

View File

@ -60,9 +60,6 @@ impl SerializeList {
- However, this introduces both **duplication** and **structural complexity**.
`SerializeStructProperty` and `SerializeList` now share similar logic (e.g.
adding strings, nested structs, or nested lists).
- Even more critically, we now hit a **type system limitation**: we cannot
cleanly express what `finish()` should return without duplicating variants for
every nesting context (e.g. root, struct, list).

View File

@ -17,7 +17,7 @@ struct SerializeStruct {
impl Serializer {
fn serialize_struct(mut self, name: &str) -> SerializeStruct {
let _ = writeln!(&mut self.output, "{name} {{");
writeln!(&mut self.output, "{name} {{").unwrap();
SerializeStruct { serializer: self }
}
@ -28,7 +28,7 @@ impl Serializer {
impl SerializeStruct {
fn serialize_field(mut self, key: &str, value: &str) -> Self {
let _ = writeln!(&mut self.serializer.output, " {key}={value};");
writeln!(&mut self.serializer.output, " {key}={value};").unwrap();
self
}
@ -62,8 +62,9 @@ fn main() {
```bob
+------------+ serialize struct +-----------------+
| Serializer +-------------------->| SerializeStruct |<-------+
+--+---------+ +-+-----+---------+ |
| Serializer | ------------------> | SerializeStruct | <------+
+------------+ +-----------------+ |
|
| ^ | | |
| | finish struct | | serialize field |
| +-----------------------------+ +------------------+
@ -81,7 +82,7 @@ fn main() {
related to serializing struct fields.
- The original `Serializer` is no longer accessible — preventing us from
mixing modes (like writing a tuple or primitive mid-struct) or calling
mixing modes (such as starting another _struct_ mid-struct) or calling
`finish()` too early.
- Only after calling `.finish_struct()` do we receive the `Serializer` back.

View File

@ -176,7 +176,7 @@ fn main() {
<details>
- The full code for this example is available
[in the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=48b106089ca600453f3ed00a0a31af26)
[in the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=48b106089ca600453f3ed00a0a31af26).
- By using generics to track the parent context, we can construct arbitrarily
nested serializers that enforce valid transitions between struct, list, and
@ -234,7 +234,7 @@ finish | | +-------------------------------+ struct
- Of course, this pattern isn't a silver bullet. It still allows issues like:
- Empty or invalid property names (which can be fixed using
[the newtype pattern](../newtype-pattern.md))
- Duplicate property names (which could be tracked in `Struct<S>` or handled
- Duplicate property names (which could be tracked in `Struct<S>` and handled
via `Result`)
- If validation failures occur, we can also change method signatures to return a