I have a recursive data structure in my pet-project:
(this is a simplified example)
pub trait Condition {
fn validate(&self, s: &str) -> bool;
}
pub struct Equal {
ref_val: String,
}
impl Condition for Equal {
fn validate(&self, s: &str) -> bool { self.ref_val == s }
}
pub struct And<A, B> where A: Condition + ?Sized, B: Condition + ?Sized {
left: Box<A>,
right: Box<B>,
}
impl<A, B> Condition for And<A, B> where A: Condition + ?Sized, B: Condition + ?Sized {
fn validate(&self, s: &str) -> bool { self.left.validate(s) && self.right.validate(s) }
}
and i want to serialize and de-serialize the condition trait (using serde
) eg.:
fn main() {
let c = And {
left: Box::new(Equal{ ref_val: "goofy".to_string() }),
right: Box::new(Equal{ ref_val: "goofy".to_string() }),
};
let s = serde_json::to_string(&c).unwrap();
let d: Box<dyn Condition> = serde_json::from_string(&s).unwrap();
}
Because serde
cannot deserialize dyn traits out-of-the box, i tagged the serialized markup, eg:
#[derive(PartialEq, Debug, Serialize)]
#[serde(tag="type")]
pub struct Equal {
ref_val: String,
}
and try to implement a Deserializer
and a Vistor
for Box<dyn Condition>
Since i am new to Rust and because the implementation of a Deserializer and a Visitor is not that straightforward with the given documentation, i wonder if someone has an idea how to solve my issue with an easier approach?
I went through the serde documentation and searched for solution on tech sites/forums. i tried out typetag but it does not support generic types
UPDATE:
To be more precise: the serialization works fine, ie. serde can serialize any concrete object of the Condition trait, but in order to deserialize a Condition the concrete type information needs to be provided. But this type info is not available at compile time. I am writing a web service where customers can upload rules for context matching (ie. Conditions) so the controller of the web service does not know the type when the condition needs to be deserialized. eg. a Customer can post:
{"type":"Equal","ref_val":"goofy"}
or
{"type":"Greater","ref_val":"Pluto"}
or more complex with any combinator ('and', 'or', 'not')
{"type":"And","left":{"type":"Greater","ref_val":"Gamma"},"right":{"type":"Equal","ref_val":"Delta"}}
and therefore i need to deserialze to a trait (dyn Condition) using the type tags in the serialized markup...