xee_interpreter/sequence/
iter.rs

1use xot::Xot;
2
3use crate::{atomic, error, function};
4
5use super::item::Item;
6
7/// An iterator over the nodes in a sequence.
8pub struct NodeIter<I>
9where
10    I: Iterator<Item = Item>,
11{
12    iter: I,
13}
14
15impl<I> NodeIter<I>
16where
17    I: Iterator<Item = Item>,
18{
19    pub(crate) fn new(iter: I) -> Self {
20        Self { iter }
21    }
22}
23
24impl<I> Iterator for NodeIter<I>
25where
26    I: Iterator<Item = Item>,
27{
28    type Item = error::Result<xot::Node>;
29
30    fn next(&mut self) -> Option<Self::Item> {
31        let next = self.iter.next();
32        next.map(|v| v.to_node())
33    }
34
35    fn size_hint(&self) -> (usize, Option<usize>) {
36        self.iter.size_hint()
37    }
38}
39
40/// An iterator atomizing a sequence.
41pub struct AtomizedIter<'a, I>
42where
43    I: Iterator<Item = Item> + 'a,
44{
45    xot: &'a Xot,
46    iter: I,
47    item_iter: Option<AtomizedItemIter<'a>>,
48}
49
50impl<'a, I> AtomizedIter<'a, I>
51where
52    I: Iterator<Item = Item>,
53{
54    pub(crate) fn new(xot: &'a Xot, iter: I) -> AtomizedIter<'a, I> {
55        AtomizedIter {
56            xot,
57            iter,
58            item_iter: None,
59        }
60    }
61}
62
63impl<'a, I> Iterator for AtomizedIter<'a, I>
64where
65    I: Iterator<Item = Item> + 'a,
66{
67    type Item = error::Result<atomic::Atomic>;
68
69    fn next(&mut self) -> Option<error::Result<atomic::Atomic>> {
70        loop {
71            // if there there are any more atoms in this node,
72            // supply those
73            if let Some(item_iter) = &mut self.item_iter {
74                if let Some(item) = item_iter.next() {
75                    return Some(item);
76                } else {
77                    self.item_iter = None;
78                }
79            }
80            // if not, move on to the next item
81            let item = self.iter.next();
82            if let Some(item) = item {
83                self.item_iter = Some(AtomizedItemIter::new(item, self.xot));
84                continue;
85            } else {
86                // no more items, we're done
87                return None;
88            }
89        }
90    }
91
92    fn size_hint(&self) -> (usize, Option<usize>) {
93        // using iter as the lower bound is safe, as we will
94        // go through each item at least once. it's harder to determine an upper
95        // bound however
96        let (lower, _) = self.iter.size_hint();
97        (lower, None)
98    }
99}
100
101/// Atomizing an individual item in a sequence.
102pub enum AtomizedItemIter<'a> {
103    Atomic(std::iter::Once<atomic::Atomic>),
104    Node(AtomizedNodeIter),
105    Array(AtomizedArrayIter<'a>),
106    // TODO: properly handle functions; for now they error
107    Erroring(std::iter::Once<error::Result<atomic::Atomic>>),
108}
109
110impl<'a> AtomizedItemIter<'a> {
111    pub(crate) fn new(item: Item, xot: &'a Xot) -> Self {
112        match item {
113            Item::Atomic(a) => Self::Atomic(std::iter::once(a)),
114            Item::Node(n) => Self::Node(AtomizedNodeIter::new(n, xot)),
115            Item::Function(function) => match function {
116                function::Function::Array(a) => Self::Array(AtomizedArrayIter::new(a, xot)),
117                _ => Self::Erroring(std::iter::once(Err(error::Error::FOTY0013))),
118            },
119        }
120    }
121}
122
123impl Iterator for AtomizedItemIter<'_> {
124    type Item = error::Result<atomic::Atomic>;
125
126    fn next(&mut self) -> Option<Self::Item> {
127        match self {
128            Self::Atomic(iter) => iter.next().map(Ok),
129            Self::Node(iter) => iter.next().map(Ok),
130            Self::Array(iter) => iter.next(),
131            Self::Erroring(iter) => iter.next(),
132        }
133    }
134
135    fn size_hint(&self) -> (usize, Option<usize>) {
136        match self {
137            Self::Atomic(iter) => iter.size_hint(),
138            Self::Node(iter) => iter.size_hint(),
139            Self::Array(iter) => iter.size_hint(),
140            Self::Erroring(iter) => iter.size_hint(),
141        }
142    }
143}
144
145/// Atomizing a node
146pub struct AtomizedNodeIter {
147    typed_value: Vec<atomic::Atomic>,
148    typed_value_index: usize,
149}
150
151impl AtomizedNodeIter {
152    fn new(node: xot::Node, xot: &Xot) -> Self {
153        let s = xot.string_value(node);
154        let typed_value = vec![atomic::Atomic::Untyped(s.into())];
155        Self {
156            typed_value,
157            typed_value_index: 0,
158        }
159    }
160}
161
162impl Iterator for AtomizedNodeIter {
163    type Item = atomic::Atomic;
164
165    fn next(&mut self) -> Option<Self::Item> {
166        if self.typed_value_index < self.typed_value.len() {
167            let item = self.typed_value[self.typed_value_index].clone();
168            self.typed_value_index += 1;
169            Some(item)
170        } else {
171            None
172        }
173    }
174
175    fn size_hint(&self) -> (usize, Option<usize>) {
176        let remaining = self.typed_value.len() - self.typed_value_index;
177        (remaining, Some(remaining))
178    }
179}
180
181/// Atomizing a XPath array
182pub struct AtomizedArrayIter<'a> {
183    xot: &'a Xot,
184    array: function::Array,
185    array_index: usize,
186    iter: Option<std::vec::IntoIter<error::Result<atomic::Atomic>>>,
187}
188
189impl<'a> AtomizedArrayIter<'a> {
190    fn new(array: function::Array, xot: &'a Xot) -> Self {
191        Self {
192            xot,
193            array,
194            array_index: 0,
195            iter: None,
196        }
197    }
198}
199
200impl Iterator for AtomizedArrayIter<'_> {
201    type Item = error::Result<atomic::Atomic>;
202
203    fn next(&mut self) -> Option<Self::Item> {
204        loop {
205            // if there there are any more atoms in this array entry,
206            // supply those
207            if let Some(iter) = &mut self.iter {
208                if let Some(item) = iter.next() {
209                    return Some(item);
210                } else {
211                    self.iter = None;
212                }
213            }
214            let array = &self.array.0;
215            // if we're at the end of the array, we're done
216            if self.array_index >= array.len() {
217                return None;
218            }
219            let sequence = &array[self.array_index];
220            self.array_index += 1;
221            // TODO: we have lifetime whackamole issues here, because
222            // an array reference cannot live long enough, but an owned
223            // array also cannot live long enough. So we collect things
224            // into a vector...
225            let v = sequence.atomized(self.xot).collect::<Vec<_>>();
226            self.iter = Some(v.into_iter());
227        }
228    }
229
230    fn size_hint(&self) -> (usize, Option<usize>) {
231        // we will have at least as many entries as in the array, but
232        // we don't really know the upper bound
233        let remaining = self.array.0.len() - self.array_index;
234        (remaining, None)
235    }
236}
237
238pub(crate) fn one<'a, T>(mut iter: impl Iterator<Item = T> + 'a) -> error::Result<T> {
239    if let Some(one) = iter.next() {
240        if iter.next().is_none() {
241            Ok(one)
242        } else {
243            Err(error::Error::XPTY0004)
244        }
245    } else {
246        Err(error::Error::XPTY0004)
247    }
248}
249
250pub(crate) fn option<'a, T>(mut iter: impl Iterator<Item = T> + 'a) -> error::Result<Option<T>> {
251    if let Some(one) = iter.next() {
252        if iter.next().is_none() {
253            Ok(Some(one))
254        } else {
255            Err(error::Error::XPTY0004)
256        }
257    } else {
258        Ok(None)
259    }
260}