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}