skyscraper/xpath/
xpath_item_set.rs1use std::{fmt::Display, ops::Index};
4
5use indexmap::{self, IndexSet};
6
7use super::grammar::data_model::{AnyAtomicType, XpathItem};
8
9#[derive(Debug)]
11pub struct XpathItemSet<'tree> {
12 index_set: IndexSet<XpathItem<'tree>>,
13}
14
15impl Display for XpathItemSet<'_> {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 write!(f, "[")?;
18 let values: Vec<String> = self.iter().map(|item| item.to_string()).collect();
19 let values_str = values.join(", ");
20 write!(f, "{}", values_str)?;
21 write!(f, "]")
22 }
23}
24
25impl PartialEq for XpathItemSet<'_> {
26 fn eq(&self, other: &Self) -> bool {
27 self.index_set == other.index_set
28 }
29}
30
31impl PartialOrd for XpathItemSet<'_> {
32 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
33 self.index_set.iter().partial_cmp(&other.index_set)
34 }
35}
36
37impl<'a, 'tree> IntoIterator for &'a XpathItemSet<'tree> {
38 type Item = &'a XpathItem<'tree>;
39
40 type IntoIter = indexmap::set::Iter<'a, XpathItem<'tree>>;
41
42 fn into_iter(self) -> Self::IntoIter {
43 self.index_set.iter()
44 }
45}
46
47impl<'tree> IntoIterator for XpathItemSet<'tree> {
48 type Item = XpathItem<'tree>;
49
50 type IntoIter = indexmap::set::IntoIter<XpathItem<'tree>>;
51
52 fn into_iter(self) -> Self::IntoIter {
53 self.index_set.into_iter()
54 }
55}
56
57impl<'tree> FromIterator<XpathItem<'tree>> for XpathItemSet<'tree> {
58 fn from_iter<T: IntoIterator<Item = XpathItem<'tree>>>(iter: T) -> Self {
59 let index_set = IndexSet::from_iter(iter);
60 XpathItemSet { index_set }
61 }
62}
63
64impl<'tree> Extend<XpathItem<'tree>> for XpathItemSet<'tree> {
65 fn extend<T: IntoIterator<Item = XpathItem<'tree>>>(&mut self, iter: T) {
66 self.index_set.extend(iter)
67 }
68}
69
70impl<'tree> XpathItemSet<'tree> {
71 pub fn new() -> Self {
73 XpathItemSet {
74 index_set: IndexSet::new(),
75 }
76 }
77
78 pub fn is_empty(&self) -> bool {
80 self.index_set.is_empty()
81 }
82
83 pub fn len(&self) -> usize {
85 self.index_set.len()
86 }
87
88 pub fn insertb(&mut self, item: XpathItem<'tree>) -> bool {
92 self.index_set.insert(item)
93 }
94
95 pub fn insert(&mut self, item: XpathItem<'tree>) {
100 self.insertb(item);
101 }
102
103 pub fn iter(&self) -> indexmap::set::Iter<'_, XpathItem<'tree>> {
105 self.index_set.iter()
106 }
107
108 pub fn boolean(&self) -> bool {
112 if self.index_set.len() == 1 {
114 match &self.index_set[0] {
115 XpathItem::Node(_) => true,
116 XpathItem::Function(_) => true,
117 XpathItem::AnyAtomicType(atomic_type) => match atomic_type {
118 AnyAtomicType::Boolean(b) => *b,
119 AnyAtomicType::Integer(n) => *n != 0,
120 AnyAtomicType::Float(n) => *n != 0.0,
121 AnyAtomicType::Double(n) => *n != 0.0,
122 AnyAtomicType::String(s) => !s.is_empty(),
123 },
124 }
125 }
126 else {
128 !self.index_set.is_empty()
129 }
130 }
131
132 pub(crate) fn sort(&mut self) {
133 self.index_set.sort();
134 }
135}
136
137impl<'tree> From<IndexSet<XpathItem<'tree>>> for XpathItemSet<'tree> {
138 fn from(value: IndexSet<XpathItem<'tree>>) -> Self {
139 XpathItemSet { index_set: value }
140 }
141}
142
143impl<'tree> Index<usize> for XpathItemSet<'tree> {
144 type Output = XpathItem<'tree>;
145
146 fn index(&self, index: usize) -> &Self::Output {
147 self.index_set.index(index)
148 }
149}
150
151#[macro_export]
153macro_rules! xpath_item_set {
154 ($($value:expr,)+) => { $crate::xpath::xpath_item_set::xpath_item_set!($($value),+) };
155 ($($value:expr),*) => {
156 {
157 let set = indexmap::indexset![$($value,)*];
158
159 crate::xpath::XpathItemSet::from(set)
160 }
161 };
162}
163
164#[cfg(test)]
165mod tests {
166 use crate::xpath::grammar::data_model::AnyAtomicType;
167
168 use super::*;
169
170 #[test]
171 fn macro_works_with_one() {
172 let node1 = XpathItem::AnyAtomicType(AnyAtomicType::String(String::from("1")));
174
175 let item_set = xpath_item_set![node1.clone()];
177
178 let mut expected = XpathItemSet::new();
180 expected.insert(node1);
181
182 assert_eq!(item_set, expected);
183 }
184
185 #[test]
186 fn macro_works_with_multiple() {
187 let node1 = XpathItem::AnyAtomicType(AnyAtomicType::String(String::from("1")));
189 let node2 = XpathItem::AnyAtomicType(AnyAtomicType::String(String::from("2")));
190 let node3 = XpathItem::AnyAtomicType(AnyAtomicType::String(String::from("3")));
191
192 let item_set = xpath_item_set![node1.clone(), node2.clone(), node3.clone()];
194
195 let mut expected = XpathItemSet::new();
197 expected.insert(node1);
198 expected.insert(node2);
199 expected.insert(node3);
200
201 assert_eq!(item_set, expected);
202 }
203}