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. system.
In the next slide, we will apply the **typestate pattern** to enforce correct 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> </details>

View File

@ -60,9 +60,6 @@ impl SerializeList {
- However, this introduces both **duplication** and **structural complexity**. - 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 - Even more critically, we now hit a **type system limitation**: we cannot
cleanly express what `finish()` should return without duplicating variants for cleanly express what `finish()` should return without duplicating variants for
every nesting context (e.g. root, struct, list). every nesting context (e.g. root, struct, list).

View File

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

View File

@ -176,7 +176,7 @@ fn main() {
<details> <details>
- The full code for this example is available - 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 - By using generics to track the parent context, we can construct arbitrarily
nested serializers that enforce valid transitions between struct, list, and 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: - Of course, this pattern isn't a silver bullet. It still allows issues like:
- Empty or invalid property names (which can be fixed using - Empty or invalid property names (which can be fixed using
[the newtype pattern](../newtype-pattern.md)) [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`) via `Result`)
- If validation failures occur, we can also change method signatures to return a - If validation failures occur, we can also change method signatures to return a