You've already forked comprehensive-rust
mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-08-08 08:22:52 +02:00
improve typestate pattern slides
This commit is contained in:
@ -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>
|
||||||
|
@ -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).
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user