namespace_set.rs

  1use std::collections::BTreeMap;
  2use std::cell::RefCell;
  3use std::fmt;
  4use std::rc::Rc;
  5
  6
  7#[derive(Clone, PartialEq, Eq)]
  8pub struct NamespaceSet {
  9    parent: RefCell<Option<Rc<NamespaceSet>>>,
 10    namespaces: BTreeMap<Option<String>, String>,
 11}
 12
 13impl Default for NamespaceSet {
 14    fn default() -> Self {
 15        NamespaceSet {
 16            parent: RefCell::new(None),
 17            namespaces: BTreeMap::new(),
 18        }
 19    }
 20}
 21
 22impl fmt::Debug for NamespaceSet {
 23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 24        write!(f, "NamespaceSet(")?;
 25        for (prefix, namespace) in &self.namespaces {
 26            write!(f, "xmlns{}={:?}, ", match prefix {
 27                None => String::new(),
 28                Some(prefix) => format!(":{}", prefix),
 29            }, namespace)?;
 30        }
 31        write!(f, "parent: {:?})", *self.parent.borrow())
 32    }
 33}
 34
 35impl NamespaceSet {
 36    pub fn declared_ns(&self) -> &BTreeMap<Option<String>, String> {
 37        &self.namespaces
 38    }
 39
 40    pub fn get(&self, prefix: &Option<String>) -> Option<String> {
 41        match self.namespaces.get(prefix) {
 42            Some(ns) => Some(ns.clone()),
 43            None => match *self.parent.borrow() {
 44                None => None,
 45                Some(ref parent) => parent.get(prefix)
 46            },
 47        }
 48    }
 49
 50    pub fn has<NS: AsRef<str>>(&self, prefix: &Option<String>, wanted_ns: NS) -> bool {
 51        match self.namespaces.get(prefix) {
 52            Some(ns) =>
 53                ns == wanted_ns.as_ref(),
 54            None => match *self.parent.borrow() {
 55                None =>
 56                    false,
 57                Some(ref parent) =>
 58                    parent.has(prefix, wanted_ns),
 59            },
 60        }
 61    }
 62
 63    pub fn set_parent(&self, parent: Rc<NamespaceSet>) {
 64        let mut parent_ns = self.parent.borrow_mut();
 65        let new_set = parent;
 66        *parent_ns = Some(new_set);
 67    }
 68
 69}
 70
 71impl From<BTreeMap<Option<String>, String>> for NamespaceSet {
 72    fn from(namespaces: BTreeMap<Option<String>, String>) -> Self {
 73        NamespaceSet {
 74            parent: RefCell::new(None),
 75            namespaces,
 76        }
 77    }
 78}
 79
 80impl From<Option<String>> for NamespaceSet {
 81    fn from(namespace: Option<String>) -> Self {
 82        match namespace {
 83            None => Self::default(),
 84            Some(namespace) => Self::from(namespace),
 85        }
 86    }
 87}
 88
 89impl From<String> for NamespaceSet {
 90    fn from(namespace: String) -> Self {
 91        let mut namespaces = BTreeMap::new();
 92        namespaces.insert(None, namespace);
 93
 94        NamespaceSet {
 95            parent: RefCell::new(None),
 96            namespaces,
 97        }
 98    }
 99}
100
101impl From<(Option<String>, String)> for NamespaceSet {
102    fn from(prefix_namespace: (Option<String>, String)) -> Self {
103        let (prefix, namespace) = prefix_namespace;
104        let mut namespaces = BTreeMap::new();
105        namespaces.insert(prefix, namespace);
106
107        NamespaceSet {
108            parent: RefCell::new(None),
109            namespaces,
110        }
111    }
112}
113
114impl From<(String, String)> for NamespaceSet {
115    fn from(prefix_namespace: (String, String)) -> Self {
116        let (prefix, namespace) = prefix_namespace;
117        Self::from((Some(prefix), namespace))
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124
125    #[test]
126    fn get_has() {
127        let namespaces = NamespaceSet::from("foo".to_owned());
128        assert_eq!(namespaces.get(&None), Some("foo".to_owned()));
129        assert!(namespaces.has(&None, "foo"));
130    }
131
132    #[test]
133    fn get_has_prefixed() {
134        let namespaces = NamespaceSet::from(("x".to_owned(), "bar".to_owned()));
135        assert_eq!(namespaces.get(&Some("x".to_owned())), Some("bar".to_owned()));
136        assert!(namespaces.has(&Some("x".to_owned()), "bar"));
137    }
138
139    #[test]
140    fn get_has_recursive() {
141        let mut parent = NamespaceSet::from("foo".to_owned());
142        for _ in 0..1000 {
143            let namespaces = NamespaceSet::default();
144            namespaces.set_parent(Rc::new(parent));
145            assert_eq!(namespaces.get(&None), Some("foo".to_owned()));
146            assert!(namespaces.has(&None, "foo"));
147            parent = namespaces;
148        }
149    }
150
151    #[test]
152    fn get_has_prefixed_recursive() {
153        let mut parent = NamespaceSet::from(("x".to_owned(), "bar".to_owned()));
154        for _ in 0..1000 {
155            let namespaces = NamespaceSet::default();
156            namespaces.set_parent(Rc::new(parent));
157            assert_eq!(namespaces.get(&Some("x".to_owned())), Some("bar".to_owned()));
158            assert!(namespaces.has(&Some("x".to_owned()), "bar"));
159            parent = namespaces;
160        }
161    }
162
163    #[test]
164    fn debug_looks_correct() {
165        let parent = NamespaceSet::from("http://www.w3.org/2000/svg".to_owned());
166        let namespaces = NamespaceSet::from(("xhtml".to_owned(), "http://www.w3.org/1999/xhtml".to_owned()));
167        namespaces.set_parent(Rc::new(parent));
168        assert_eq!(format!("{:?}", namespaces), "NamespaceSet(xmlns:xhtml=\"http://www.w3.org/1999/xhtml\", parent: Some(NamespaceSet(xmlns=\"http://www.w3.org/2000/svg\", parent: None)))");
169    }
170}