quick-xml icon indicating copy to clipboard operation
quick-xml copied to clipboard

Deserialization of enum variant which recursively refers to itself failed with stackoverflow

Open Mingun opened this issue 1 year ago • 0 comments

Found in https://stackoverflow.com/questions/67932584/deserializing-recursive-xml-using-serde-in-rust

Currently recursively defined enums using newtype variants for recursion lead to stack overflow error:

#[test]
fn recursive() {
    #[derive(Debug, Deserialize, PartialEq)]
    #[serde(rename_all = "camelCase")]
    enum MathNode {
        Apply(Vec<MathNode>),
        Ci(Vec<MathNode>),
        #[serde(rename = "$text")]
        Text(String),
        #[serde(rename = "math")]
        Root(Vec<MathNode>),
    }

    let test = r#"
    <math>
        <apply>
            <ci type="integer">5</ci>
        </apply>
    </math>"#;
    assert_eq!(
        from_str::<MathNode>(test).unwrap(),
        MathNode::Root(vec![MathNode::Apply(vec![MathNode::Ci(vec![
            MathNode::Text("5".into())
        ])])])
    );
}

However, if change newtype variant to the struct variant with one $value field, everything works:

#[test]
fn recursive() {
    #[derive(Debug, Deserialize, PartialEq)]
    #[serde(rename_all = "camelCase")]
    enum MathNode {
        Apply {
            #[serde(rename = "$value")]
            value: Vec<MathNode>,
        },
        Ci {
            #[serde(rename = "$value")]
            value: Vec<MathNode>,
        },
        #[serde(rename = "$text")]
        Text(String),
        #[serde(rename = "math")]
        Root {
            #[serde(rename = "$value")]
            value: Vec<MathNode>,
        },
    }

    let test = r#"
    <math>
        <apply>
            <ci type="integer">5</ci>
        </apply>
    </math>"#;
    assert_eq!(
        from_str::<MathNode>(test).unwrap(),
        MathNode::Root {
            value: vec![MathNode::Apply {
                value: vec![MathNode::Ci {
                    value: vec![MathNode::Text("5".into())]
                }],
            }],
        }
    );
}

It seems worth to implement newtype variant deserialization like such structs

Mingun avatar Oct 09 '24 14:10 Mingun