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
128

use serde::de;
use serde::de::Error;
use std::collections::BTreeMap;

#[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.deserialize_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.deserialize_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_with(Vec::new)
                       .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_with(Vec::new).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)
}