You've already forked comprehensive-rust
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:
@ -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>
|
||||
|
@ -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).
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user