I have a set of structs that can form a schema. In actuality, there's a lot of these and they have additional behavior attached to them, but the basic idea is that you can statically assemble these using generics, and there is also this Dynamic version which can be changed at runtime.
#[derive(Debug, PartialEq)]
struct Atom {
param: u32,
state: u32,
}
#[derive(Debug, PartialEq)]
struct Compound<A, B>(A, B);
#[derive(Debug, PartialEq)]
enum Dynamic {
Atom(Atom),
Compound(Box<Compound<Dynamic, Dynamic>>),
}
My goal is to serialize the state, but not the parameters, of these. For Atom, that means state
but not param
. For Dynamic, it means the state of the variant but not the variant itself. It would be simple if I could do something like this:
trait Stateful {
type State: serde::Serialize + serde::de::DeserializeOwned;
fn state(&self) -> Self::State;
fn set_state(&mut self, state: Self::State);
}
This isn't a good choice, because it isn't possible to make statically-known State
type for Dynamic
. The obvious route would be to make an enum like this:
enum DynamicState {
Atom(<Atom as Stateful>::State),
Compound(Box<<Compound<Dynamic, Dynamic> as Stateful>::State>),
}
However, I this approach means that DynamicState is serialized as a tagged enum, which I don't want.
Current approach
Basically, Dynamic
needs to be available when deserializing to know how to deserialize the state. This sounds like a job for DeserializeSeed.
pub trait Stateful: for<'de> DeserializeSeed<'de, Value = Self> {
type State<'a>: Debug + Serialize
where
Self: 'a;
fn state(&self) -> Self::State<'_>;
}
This works (code in playground), but it sucks to code. I have to manually implement DeserializeSeed
for each type, which is extremely verbose.
Is there some way I can accomplish what I'm trying to do here without having to manually write Serialize and Deserialize impls for all of my types?