Is there a more ergonomic pattern for types that "build up?"
A few times, I've found myself needing a type with "stages" that add upon eachother, usually when dealing with some kind of graph structure. One way of doing this is:
enum Thing {
Stage1 { a: u8 },
Stage2 { a: u8, b: u8 },
Stage3 { a: u8, b: u8, c: u8, d: u8 },
}
But that requires some ugly pattern matching when trying to write code that works for multiple stages:
match thing {
Stage1 { .. } => panic!("stage 2 or 3 required"),
Stage2 { a, b } | Stage3 { a, b, .. } => todo!(),
}
It also doesn't work well when switching stages because fields need to be moved into the other variant rather than just staying in place. This isn't a problem for this example, but it is in a real usecase where some fields are not Copy.
The other way I have found is:
struct Stage3 {
c: u8,
d: u8,
}
struct Stage2 {
b: u8,
stage_3: Option<Stage3>,
}
struct Thing {
a: u8,
stage_2: Option<Stage2>,
}
This avoids some of the problems of the other way, but it's also pretty ugly to work with, and it requires defining a lot of extra structs, probably in a dedicated module, depending on how many stages you need.
Is there a nicer way of doing this?
Edit: To clarify, there is a constraint that Thing has the same type regardless of what stage it's in. It needs to be able to be stored generically over its stage. This is why the builder/typestate pattern doesn't work here.