convert.rs

  1//! A module which exports a few traits for converting types to elements and attributes.
  2
  3use element::{Element, ElementBuilder};
  4
  5/// A struct which is used for emitting `Element`s and text nodes into an `Element` without
  6/// exposing more functionality than necessary.
  7pub struct ElementEmitter<'a>(&'a mut Element);
  8
  9impl<'a> ElementEmitter<'a> {
 10    /// Creates a new `ElementEmitter`.
 11    pub fn new(root: &'a mut Element) -> ElementEmitter<'a> {
 12        ElementEmitter(root)
 13    }
 14
 15    /// Appends an `Element` to the target.
 16    pub fn append_child(&mut self, element: Element) {
 17        self.0.append_child(element);
 18    }
 19
 20    /// Appends a text node to the target.
 21    pub fn append_text_node(&mut self, text: String) {
 22        self.0.append_text_node(text);
 23    }
 24}
 25
 26/// A trait for types which can be converted to one or multiple `Element`s.
 27pub trait IntoElements {
 28    /// Emits this as a sequence of text nodes and `Element`s.
 29    fn into_elements(self, emitter: &mut ElementEmitter);
 30}
 31
 32impl<T: IntoElements> IntoElements for Vec<T> {
 33    fn into_elements(self, emitter: &mut ElementEmitter) {
 34        for elem in self {
 35            elem.into_elements(emitter);
 36        }
 37    }
 38}
 39
 40impl<'a, T: IntoElements + Clone> IntoElements for &'a [T] {
 41    fn into_elements(self, emitter: &mut ElementEmitter) {
 42        self.to_vec().into_elements(emitter);
 43    }
 44}
 45
 46impl<T: IntoElements> IntoElements for Option<T> {
 47    fn into_elements(self, emitter: &mut ElementEmitter) {
 48        if let Some(e) = self {
 49            e.into_elements(emitter);
 50        }
 51    }
 52}
 53
 54impl<T> IntoElements for T where T: Into<Element> {
 55    fn into_elements(self, emitter: &mut ElementEmitter) {
 56        emitter.append_child(self.into());
 57    }
 58}
 59
 60impl IntoElements for ElementBuilder {
 61    fn into_elements(self, emitter: &mut ElementEmitter) {
 62        emitter.append_child(self.build());
 63    }
 64}
 65
 66impl IntoElements for String {
 67    fn into_elements(self, emitter: &mut ElementEmitter) {
 68        emitter.append_text_node(self);
 69    }
 70}
 71
 72impl<'a> IntoElements for &'a String {
 73    fn into_elements(self, emitter: &mut ElementEmitter) {
 74        emitter.append_text_node(self.to_owned());
 75    }
 76}
 77
 78impl<'a> IntoElements for &'a str {
 79    fn into_elements(self, emitter: &mut ElementEmitter) {
 80        emitter.append_text_node(self.to_owned());
 81    }
 82}
 83
 84/// A trait for types which can be converted to an attribute value.
 85pub trait IntoAttributeValue {
 86    /// Turns this into an attribute string, or None if it shouldn't be added.
 87    fn into_attribute_value(self) -> Option<String>;
 88}
 89
 90macro_rules! impl_into_attribute_value {
 91    ($t:ty) => {
 92        impl IntoAttributeValue for $t {
 93            fn into_attribute_value(self) -> Option<String> {
 94                Some(format!("{}", self))
 95            }
 96        }
 97    }
 98}
 99
100macro_rules! impl_into_attribute_values {
101    ($($t:ty),*) => {
102        $(impl_into_attribute_value!($t);)*
103    }
104}
105
106impl_into_attribute_values!(usize, u64, u32, u16, u8, isize, i64, i32, i16, i8, ::std::net::IpAddr);
107
108impl IntoAttributeValue for String {
109    fn into_attribute_value(self) -> Option<String> {
110        Some(self)
111    }
112}
113
114impl<'a> IntoAttributeValue for &'a String {
115    fn into_attribute_value(self) -> Option<String> {
116        Some(self.to_owned())
117    }
118}
119
120impl<'a> IntoAttributeValue for &'a str {
121    fn into_attribute_value(self) -> Option<String> {
122        Some(self.to_owned())
123    }
124}
125
126impl<T: IntoAttributeValue> IntoAttributeValue for Option<T> {
127    fn into_attribute_value(self) -> Option<String> {
128        self.and_then(|t| t.into_attribute_value())
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use super::IntoAttributeValue;
135    use std::net::IpAddr;
136    use std::str::FromStr;
137
138    #[test]
139    fn test_into_attribute_value_on_ints() {
140        assert_eq!(16u8.into_attribute_value().unwrap()    , "16");
141        assert_eq!(17u16.into_attribute_value().unwrap()   , "17");
142        assert_eq!(18u32.into_attribute_value().unwrap()   , "18");
143        assert_eq!(19u64.into_attribute_value().unwrap()   , "19");
144        assert_eq!(   16i8.into_attribute_value().unwrap() , "16");
145        assert_eq!((-17i16).into_attribute_value().unwrap(), "-17");
146        assert_eq!(   18i32.into_attribute_value().unwrap(), "18");
147        assert_eq!((-19i64).into_attribute_value().unwrap(), "-19");
148        assert_eq!(IpAddr::from_str("127.000.0.1").unwrap().into_attribute_value().unwrap(), "127.0.0.1");
149    }
150}