1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use std::collections::BTreeMap;
use serde::de;
use serde::de::Error;

#[derive(Clone, PartialEq, Debug)]
pub struct Element {
    pub attributes: BTreeMap<String, Vec<String>>,
    pub members: Content,
}

impl Element {
    pub fn new_text(s: String) -> Element {
        Element {
            attributes: BTreeMap::new(),
            members: Content::Text(s),
        }
    }
    pub fn new_empty() -> Element {
        Element {
            attributes: BTreeMap::new(),
            members: Content::Nothing,
        }
    }
}

#[derive(Clone, PartialEq, Debug)]
pub enum Content {
    Members(BTreeMap<String, Vec<Element>>),
    Text(String),
    Nothing,
}

impl de::Deserialize for Element {
    fn deserialize<D>(deserializer: &mut D) -> Result<Element, D::Error>
        where D: de::Deserializer,
    {
        deserializer.visit_map(ElementVisitor)
    }
}

enum Helper {
    Member(Element),
    Text(String),
}

impl de::Deserialize for Helper {
    fn deserialize<D>(deserializer: &mut D) -> Result<Helper, D::Error>
        where D: de::Deserializer,
    {
        let el = try!(deserializer.visit_map(ElementVisitor));
        Ok(match (el.attributes.is_empty(), el.members) {
            (true, Content::Text(s)) => Helper::Text(s),
            (_, c) => Helper::Member(Element {
                attributes: el.attributes,
                members: c
            }),
        })
    }
}

struct ElementVisitor;

impl de::Visitor for ElementVisitor {
    type Value = Element;

    fn visit_str<E>(&mut self, s: &str) -> Result<Element, E>
        where E: Error,
    {
        Ok(Element::new_text(s.to_string()))
    }

    fn visit_string<E>(&mut self, s: String) -> Result<Element, E>
        where E: Error,
    {
        Ok(Element::new_text(s))
    }

    #[inline]
    fn visit_map<V>(&mut self, mut visitor: V) -> Result<Element, V::Error>
        where V: de::MapVisitor,
    {
        let mut attributes = BTreeMap::new();
        let mut content = Content::Nothing;
        while let Some(key) = try!(visitor.visit_key::<String>()) {
            match content {
                Content::Nothing if key == "$value" => {
                    let v = try!(visitor.visit_value());
                    content = Content::Text(v);
                },
                Content::Text(_)=> unreachable!(),
                Content::Members(mut map) => {
                    map.entry(key)
                       .or_insert(vec![])
                       .push(try!(visitor.visit_value()));
                    content = Content::Members(map); // move back
                },
                Content::Nothing => {
                    // try to push to attributes
                    match try!(visitor.visit_value()) {
                        Helper::Member(el) => {
                            let mut m = BTreeMap::new();
                            m.insert(key, vec![el]);
                            content = Content::Members(m);
                        },
                        Helper::Text(s) => {
                            attributes.entry(key).or_insert(vec![]).push(s);
                            content = Content::Nothing; // move back
                        }
                    }
                },
            }
        }
        try!(visitor.end());
        Ok(Element {
            attributes: attributes,
            members: content,
        })
    }
}

/// Shortcut function to decode a Xml `Element` into a `T`
pub fn from_value<T>(value: Element) -> Result<T, super::error::Error>
    where T: de::Deserialize
{
    let mut de = super::de::value::Deserializer::new(value);
    de::Deserialize::deserialize(&mut de)
}