|
| 1 | +//! This example demonstrates how to deserialize enum nodes using an intermediate |
| 2 | +//! custom deserializer. |
| 3 | +//! The `elem` node can either be a `Foo` or a `Bar` node, depending on the `type`. |
| 4 | +//! The `type` attribute is used to determine which variant to deserialize. |
| 5 | +//! This is a workaround for [serde's issue](https://github.com/serde-rs/serde/issues/1905) |
| 6 | +//! |
| 7 | +//! note: to use serde, the feature needs to be enabled |
| 8 | +//! run example with: |
| 9 | +//! cargo run --example flattened_enum --features="serialize" |
| 10 | +
|
| 11 | +use std::fmt; |
| 12 | + |
| 13 | +use quick_xml::de::from_str; |
| 14 | +use serde::de::value::MapAccessDeserializer; |
| 15 | +use serde::de::{Error, MapAccess, Visitor}; |
| 16 | +use serde::Deserialize; |
| 17 | + |
| 18 | +#[derive(Debug, Deserialize, PartialEq)] |
| 19 | +struct Model { |
| 20 | + elem: Vec<Elem>, |
| 21 | +} |
| 22 | + |
| 23 | +#[derive(Debug, PartialEq)] |
| 24 | +enum Elem { |
| 25 | + Foo(Foo), |
| 26 | + Bar(Bar), |
| 27 | +} |
| 28 | + |
| 29 | +impl<'de> Deserialize<'de> for Elem { |
| 30 | + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
| 31 | + where |
| 32 | + D: serde::Deserializer<'de>, |
| 33 | + { |
| 34 | + struct ElemVisitor; |
| 35 | + |
| 36 | + impl<'de> Visitor<'de> for ElemVisitor { |
| 37 | + type Value = Elem; |
| 38 | + |
| 39 | + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
| 40 | + formatter.write_str("an object with a `type` field") |
| 41 | + } |
| 42 | + |
| 43 | + fn visit_map<A>(self, mut map: A) -> Result<Elem, A::Error> |
| 44 | + where |
| 45 | + A: MapAccess<'de>, |
| 46 | + { |
| 47 | + if let Some((key, value)) = map.next_entry::<String, String>()? { |
| 48 | + return match key.as_str() { |
| 49 | + "@type" => match value.as_str() { |
| 50 | + "foo" => { |
| 51 | + let f = Foo::deserialize(MapAccessDeserializer::new(map))?; |
| 52 | + Ok(Elem::Foo(f)) |
| 53 | + } |
| 54 | + "bar" => { |
| 55 | + let f = Bar::deserialize(MapAccessDeserializer::new(map))?; |
| 56 | + Ok(Elem::Bar(f)) |
| 57 | + } |
| 58 | + t => Err(Error::custom(format!("unknown type attribute `{t}`"))), |
| 59 | + }, |
| 60 | + a => Err(Error::custom(format!( |
| 61 | + "expected attribute `type`, but found `{a}`" |
| 62 | + ))), |
| 63 | + }; |
| 64 | + } |
| 65 | + Err(Error::custom("expected `type` attribute")) |
| 66 | + } |
| 67 | + } |
| 68 | + deserializer.deserialize_map(ElemVisitor) |
| 69 | + } |
| 70 | +} |
| 71 | + |
| 72 | +#[derive(Debug, Deserialize, PartialEq)] |
| 73 | +struct Foo { |
| 74 | + a: String, |
| 75 | + subfoo: SubFoo, |
| 76 | +} |
| 77 | + |
| 78 | +#[derive(Debug, Deserialize, PartialEq)] |
| 79 | +struct SubFoo { |
| 80 | + a1: String, |
| 81 | + a2: String, |
| 82 | + a3: String, |
| 83 | +} |
| 84 | + |
| 85 | +#[derive(Debug, Deserialize, PartialEq)] |
| 86 | +struct Bar { |
| 87 | + b: String, |
| 88 | +} |
| 89 | + |
| 90 | +fn main() { |
| 91 | + let x = r#" |
| 92 | +<model> |
| 93 | + <elem type="foo"> |
| 94 | + <a>1</a> |
| 95 | + <subfoo> |
| 96 | + <a1>2</a1> |
| 97 | + <a2>42</a2> |
| 98 | + <a3>1337</a3> |
| 99 | + </subfoo> |
| 100 | + </elem> |
| 101 | + <elem type="bar"> |
| 102 | + <b>22</b> |
| 103 | + </elem> |
| 104 | +</model> |
| 105 | +"#; |
| 106 | + |
| 107 | + let model: Model = from_str(&x).unwrap(); |
| 108 | + println!("{:?}", model); |
| 109 | +} |
0 commit comments