1use std::borrow::ToOwned;
6use std::collections::HashSet;
7use std::mem;
8
9use crate::Node;
10
11#[derive(Debug)]
13pub enum Value<N: Node> {
14 Boolean(bool),
15 Number(f64),
17 String(String),
18 NodeSet(NodeSet<N>),
19}
20
21#[derive(Debug)]
22pub struct NodeSet<N: Node> {
23 nodes: Vec<N>,
24 is_sorted: bool,
25}
26
27impl<N: Node> Default for NodeSet<N> {
28 fn default() -> Self {
29 Self {
30 nodes: Default::default(),
31 is_sorted: false,
32 }
33 }
34}
35
36impl<N: Node> NodeSet<N> {
37 pub(crate) fn len(&self) -> usize {
38 self.nodes.len()
39 }
40
41 fn is_empty(&self) -> bool {
42 self.nodes.is_empty()
43 }
44
45 pub(crate) fn push(&mut self, node: N) {
46 self.is_sorted = false;
47 self.nodes.push(node);
48 }
49
50 pub(crate) fn extend<I>(&mut self, iter: I)
51 where
52 I: IntoIterator<Item = N>,
53 {
54 self.nodes.extend(iter);
55 }
56
57 pub(crate) fn is_sorted(&self) -> bool {
62 self.is_sorted || self.nodes.len() < 2
63 }
64
65 pub(crate) fn assume_sorted(&mut self, cx: &mut N::Context) {
67 debug_assert!(
68 self.nodes
69 .is_sorted_by(|a, b| a.compare_tree_order(cx, b).is_le())
70 );
71 self.is_sorted = true;
72 }
73
74 pub(crate) fn sort(&mut self, cx: &mut N::Context) {
75 if self.is_sorted() {
76 return;
77 }
78
79 self.nodes
82 .sort_unstable_by(|a, b| a.compare_tree_order(cx, b));
83 }
84
85 pub(crate) fn iter(&self) -> impl Iterator<Item = &N> {
86 self.nodes.iter()
87 }
88
89 pub(crate) fn first(&self, cx: &mut N::Context) -> Option<N> {
93 if self.is_sorted() {
94 return self.nodes.first().cloned();
95 }
96
97 self.iter()
98 .min_by(|a, b| a.compare_tree_order(cx, b))
99 .cloned()
100 }
101
102 pub(crate) fn deduplicate(&mut self) {
103 let mut seen = HashSet::new();
104 self.nodes = mem::take(&mut self.nodes)
105 .into_iter()
106 .filter_map(|node| {
107 let opaque = node.to_opaque();
108 seen.insert(opaque).then_some(node)
109 })
110 .collect();
111 }
112
113 pub(crate) fn retain<F>(&mut self, f: F)
119 where
120 F: FnMut(&N) -> bool,
121 {
122 self.nodes.retain(f)
123 }
124
125 pub(crate) fn reverse(&mut self) {
126 self.nodes = mem::take(&mut self.nodes).into_iter().rev().collect();
127 }
128}
129
130impl<N: Node> IntoIterator for NodeSet<N> {
131 type IntoIter = <Vec<N> as IntoIterator>::IntoIter;
132 type Item = <Vec<N> as IntoIterator>::Item;
133
134 fn into_iter(self) -> Self::IntoIter {
135 self.nodes.into_iter()
136 }
137}
138
139impl<N: Node> FromIterator<N> for NodeSet<N> {
140 fn from_iter<T: IntoIterator<Item = N>>(iter: T) -> Self {
141 Self {
142 nodes: iter.into_iter().collect(),
143 is_sorted: false,
144 }
145 }
146}
147
148pub(crate) fn parse_number_from_string(string: &str) -> f64 {
149 string.trim_ascii().parse().unwrap_or(f64::NAN)
158}
159
160fn num_vals<N: Node>(nodes: &NodeSet<N>) -> Vec<f64> {
162 nodes
163 .iter()
164 .map(|node| parse_number_from_string(&node.text_content()))
165 .collect()
166}
167
168impl<N: Node> Value<N> {
169 pub(crate) fn partial_eq(&self, cx: &mut N::Context, other: &Self) -> bool {
170 match (self, other) {
171 (Value::NodeSet(left_nodes), Value::NodeSet(right_nodes)) => {
172 let left_strings: HashSet<String> =
173 left_nodes.iter().map(|node| node.text_content()).collect();
174 let right_strings: HashSet<String> =
175 right_nodes.iter().map(|node| node.text_content()).collect();
176 !left_strings.is_disjoint(&right_strings)
177 },
178 (&Value::NodeSet(ref nodes), &Value::Number(val)) |
179 (&Value::Number(val), &Value::NodeSet(ref nodes)) => {
180 let numbers = num_vals(nodes);
181 numbers.contains(&val)
182 },
183 (&Value::NodeSet(ref nodes), &Value::String(ref string)) |
184 (&Value::String(ref string), &Value::NodeSet(ref nodes)) => nodes
185 .iter()
186 .map(|node| node.text_content())
187 .any(|text_content| &text_content == string),
188 (&Value::Boolean(_), _) | (_, &Value::Boolean(_)) => {
189 self.convert_to_boolean() == other.convert_to_boolean()
190 },
191 (&Value::Number(_), _) | (_, &Value::Number(_)) => {
192 self.convert_to_number(cx) == other.convert_to_number(cx)
193 },
194 _ => self.convert_to_string(cx) == other.convert_to_string(cx),
195 }
196 }
197
198 pub fn convert_to_boolean(&self) -> bool {
200 match self {
201 Value::Boolean(boolean) => *boolean,
202 Value::Number(number) => *number != 0.0 && !number.is_nan(),
203 Value::String(string) => !string.is_empty(),
204 Value::NodeSet(nodeset) => !nodeset.is_empty(),
205 }
206 }
207
208 pub fn convert_to_number(&self, cx: &mut N::Context) -> f64 {
210 match self {
211 Value::Boolean(boolean) => {
212 if *boolean {
213 1.0
214 } else {
215 0.0
216 }
217 },
218 Value::Number(number) => *number,
219 Value::String(string) => parse_number_from_string(string),
220 Value::NodeSet(_) => parse_number_from_string(&self.convert_to_string(cx)),
221 }
222 }
223
224 pub fn convert_to_string(&self, cx: &mut N::Context) -> String {
226 match self {
227 Value::Boolean(value) => value.to_string(),
228 Value::Number(number) => {
229 if number.is_infinite() {
230 if number.is_sign_negative() {
231 "-Infinity".to_owned()
232 } else {
233 "Infinity".to_owned()
234 }
235 } else if *number == 0.0 {
236 "0".into()
238 } else {
239 number.to_string()
240 }
241 },
242 Value::String(string) => string.to_owned(),
243 Value::NodeSet(nodes) => nodes
244 .first(cx)
245 .as_ref()
246 .map(Node::text_content)
247 .unwrap_or_default(),
248 }
249 }
250}
251
252macro_rules! from_impl {
253 ($raw:ty, $variant:expr) => {
254 impl<N: Node> From<$raw> for Value<N> {
255 fn from(other: $raw) -> Self {
256 $variant(other)
257 }
258 }
259 };
260}
261
262from_impl!(bool, Value::Boolean);
263from_impl!(f64, Value::Number);
264from_impl!(String, Value::String);
265impl<'a, N: Node> From<&'a str> for Value<N> {
266 fn from(other: &'a str) -> Self {
267 Value::String(other.into())
268 }
269}
270
271macro_rules! partial_eq_impl {
272 ($raw:ty, $variant:pat => $b:expr) => {
273 impl<N: Node> PartialEq<$raw> for Value<N> {
274 fn eq(&self, other: &$raw) -> bool {
275 match *self {
276 $variant => $b == other,
277 _ => false,
278 }
279 }
280 }
281
282 impl<N: Node> PartialEq<Value<N>> for $raw {
283 fn eq(&self, other: &Value<N>) -> bool {
284 match *other {
285 $variant => $b == self,
286 _ => false,
287 }
288 }
289 }
290 };
291}
292
293partial_eq_impl!(bool, Value::Boolean(ref v) => v);
294partial_eq_impl!(f64, Value::Number(ref v) => v);
295partial_eq_impl!(String, Value::String(ref v) => v);
296partial_eq_impl!(&str, Value::String(ref v) => v);
297
298#[cfg(test)]
299mod tests {
300 use std::f64;
301
302 use crate::dummy_implementation;
303
304 type Value = super::Value<dummy_implementation::DummyNode>;
305
306 #[test]
307 fn string_value_to_number() {
308 let cx = &mut ();
309 assert_eq!(Value::String("42.123".into()).convert_to_number(cx), 42.123);
310 assert_eq!(Value::String(" 42\n".into()).convert_to_number(cx), 42.);
311 assert!(
312 Value::String("totally-invalid".into())
313 .convert_to_number(cx)
314 .is_nan()
315 );
316
317 assert!(
319 Value::String("\u{2004}42".into())
320 .convert_to_number(cx)
321 .is_nan()
322 );
323 }
324
325 #[test]
326 fn number_value_to_string() {
327 let cx = &mut ();
328 assert_eq!(Value::Number(f64::NAN).convert_to_string(cx), "NaN");
329 assert_eq!(Value::Number(0.).convert_to_string(cx), "0");
330 assert_eq!(Value::Number(-0.).convert_to_string(cx), "0");
331 assert_eq!(
332 Value::Number(f64::INFINITY).convert_to_string(cx),
333 "Infinity"
334 );
335 assert_eq!(
336 Value::Number(f64::NEG_INFINITY).convert_to_string(cx),
337 "-Infinity"
338 );
339 assert_eq!(Value::Number(42.0).convert_to_string(cx), "42");
340 assert_eq!(Value::Number(-42.0).convert_to_string(cx), "-42");
341 assert_eq!(Value::Number(0.75).convert_to_string(cx), "0.75");
342 assert_eq!(Value::Number(-0.75).convert_to_string(cx), "-0.75");
343 }
344
345 #[test]
346 fn boolean_value_to_string() {
347 let cx = &mut ();
348 assert_eq!(Value::Boolean(false).convert_to_string(cx), "false");
349 assert_eq!(Value::Boolean(true).convert_to_string(cx), "true");
350 }
351}