Your infinite loop is because:
<Rule as Deserialize<'de>>::deserialize
- calls
string_or_rule
- which calls
Deserializer::deserialize_any::<RuleVisitor>
- which calls
<RuleVisitor as Visitor<'de>>::visit_map
- which calls
<Rule as Deserialize<'de>>::deserialize
You can break the loop by calling anything other than Rule::deserialize
on the last step. One way would be to deserialize a helper type in the last step, then convert it to Rule.
fn visit_map<M>(self, map: M) -> Result<Rule, M::Error>
where
M: MapAccess<'de>,
{
#[derive(Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
enum RuleHelper {
Course(course::Rule),
Requirement(requirement::Rule),
}
let map = de::value::MapAccessDeserializer::new(map);
let helper = RuleHelper::deserialize(map)?;
match helper {
RuleHelper::Course(course) => Ok(Rule::Course(course)),
RuleHelper::Requirement(req) => Ok(Rule::Requirement(req)),
}
}
A more concise way would be to treat RuleHelper
as a remote derive for Rule
so that no conversion is needed.
fn visit_map<M>(self, map: M) -> Result<Rule, M::Error>
where
M: MapAccess<'de>,
{
#[derive(Deserialize)]
#[serde(remote = "Rule")]
#[serde(tag = "type", rename_all = "lowercase")]
enum RuleHelper {
Course(course::Rule),
Requirement(requirement::Rule),
}
RuleHelper::deserialize(de::value::MapAccessDeserializer::new(map))
}
Another more concise way would be to skip RuleHelper
altogether and treat Rule
as a remote derive for itself. In general remote derives are a way to generate de/serialization logic without generating a De/Serialize impl.
#[derive(Deserialize, Debug)]
#[serde(remote = "Self")]
#[serde(tag = "type", rename_all = "lowercase")]
enum Rule {
Course(course::Rule),
Requirement(requirement::Rule),
}
/* ... */
fn visit_map<M>(self, map: M) -> Result<Rule, M::Error>
where
M: MapAccess<'de>,
{
Rule::deserialize(de::value::MapAccessDeserializer::new(map))
}