Skip to main content

xsd_schema/xpath/
iter_adapters.rs

1//! Iterator adapters for XPath evaluation.
2//!
3//! This module provides iterator adapters for common XPath operations.
4//! These are building blocks for the full XPath iterator infrastructure.
5
6use crate::types::value::XmlValue;
7
8/// An iterator that yields codepoints from a string.
9///
10/// Implements fn:string-to-codepoints.
11pub struct CodepointIterator {
12    chars: std::vec::IntoIter<char>,
13}
14
15impl CodepointIterator {
16    /// Create a new codepoint iterator from a string.
17    pub fn new(s: &str) -> Self {
18        Self {
19            chars: s.chars().collect::<Vec<_>>().into_iter(),
20        }
21    }
22}
23
24impl Iterator for CodepointIterator {
25    type Item = XmlValue;
26
27    fn next(&mut self) -> Option<Self::Item> {
28        self.chars
29            .next()
30            .map(|c| XmlValue::integer(num_bigint::BigInt::from(c as u32)))
31    }
32
33    fn size_hint(&self) -> (usize, Option<usize>) {
34        self.chars.size_hint()
35    }
36}
37
38impl ExactSizeIterator for CodepointIterator {}
39
40/// An iterator that filters items based on a predicate.
41pub struct FilterIterator<I, F> {
42    inner: I,
43    predicate: F,
44}
45
46impl<I, F> FilterIterator<I, F>
47where
48    I: Iterator,
49    F: FnMut(&I::Item) -> bool,
50{
51    /// Create a new filter iterator.
52    pub fn new(inner: I, predicate: F) -> Self {
53        Self { inner, predicate }
54    }
55}
56
57impl<I, F> Iterator for FilterIterator<I, F>
58where
59    I: Iterator,
60    F: FnMut(&I::Item) -> bool,
61{
62    type Item = I::Item;
63
64    fn next(&mut self) -> Option<Self::Item> {
65        self.inner.by_ref().find(&mut self.predicate)
66    }
67}
68
69/// An iterator that maps items through a transformation function.
70pub struct MapIterator<I, F> {
71    inner: I,
72    transform: F,
73}
74
75impl<I, F, T> MapIterator<I, F>
76where
77    I: Iterator,
78    F: FnMut(I::Item) -> T,
79{
80    /// Create a new map iterator.
81    pub fn new(inner: I, transform: F) -> Self {
82        Self { inner, transform }
83    }
84}
85
86impl<I, F, T> Iterator for MapIterator<I, F>
87where
88    I: Iterator,
89    F: FnMut(I::Item) -> T,
90{
91    type Item = T;
92
93    fn next(&mut self) -> Option<Self::Item> {
94        self.inner.next().map(&mut self.transform)
95    }
96
97    fn size_hint(&self) -> (usize, Option<usize>) {
98        self.inner.size_hint()
99    }
100}
101
102/// An iterator that yields items from a slice with position tracking.
103pub struct PositionalIterator<'a, T> {
104    items: std::slice::Iter<'a, T>,
105    position: usize,
106    count: usize,
107}
108
109impl<'a, T> PositionalIterator<'a, T> {
110    /// Create a new positional iterator.
111    pub fn new(items: &'a [T]) -> Self {
112        Self {
113            items: items.iter(),
114            position: 0,
115            count: items.len(),
116        }
117    }
118
119    /// Get the current position (1-based, XPath style).
120    pub fn position(&self) -> usize {
121        self.position
122    }
123
124    /// Get the total count of items.
125    pub fn count(&self) -> usize {
126        self.count
127    }
128
129    /// Check if this is the last item.
130    pub fn is_last(&self) -> bool {
131        self.position == self.count
132    }
133}
134
135impl<'a, T> Iterator for PositionalIterator<'a, T> {
136    type Item = (usize, &'a T);
137
138    fn next(&mut self) -> Option<Self::Item> {
139        self.items.next().map(|item| {
140            self.position += 1;
141            (self.position, item)
142        })
143    }
144
145    fn size_hint(&self) -> (usize, Option<usize>) {
146        self.items.size_hint()
147    }
148}
149
150impl<'a, T> ExactSizeIterator for PositionalIterator<'a, T> {}
151
152/// An iterator that reverses another iterator.
153pub struct ReverseIterator<I: DoubleEndedIterator> {
154    inner: std::iter::Rev<I>,
155}
156
157impl<I: DoubleEndedIterator> ReverseIterator<I> {
158    /// Create a new reverse iterator.
159    pub fn new(inner: I) -> Self {
160        Self { inner: inner.rev() }
161    }
162}
163
164impl<I: DoubleEndedIterator> Iterator for ReverseIterator<I> {
165    type Item = I::Item;
166
167    fn next(&mut self) -> Option<Self::Item> {
168        self.inner.next()
169    }
170
171    fn size_hint(&self) -> (usize, Option<usize>) {
172        self.inner.size_hint()
173    }
174}
175
176/// An iterator that takes at most N items.
177pub struct TakeIterator<I> {
178    inner: I,
179    remaining: usize,
180}
181
182impl<I: Iterator> TakeIterator<I> {
183    /// Create a new take iterator.
184    pub fn new(inner: I, count: usize) -> Self {
185        Self {
186            inner,
187            remaining: count,
188        }
189    }
190}
191
192impl<I: Iterator> Iterator for TakeIterator<I> {
193    type Item = I::Item;
194
195    fn next(&mut self) -> Option<Self::Item> {
196        if self.remaining == 0 {
197            None
198        } else {
199            self.remaining -= 1;
200            self.inner.next()
201        }
202    }
203
204    fn size_hint(&self) -> (usize, Option<usize>) {
205        let (lower, upper) = self.inner.size_hint();
206        (
207            lower.min(self.remaining),
208            upper.map(|u| u.min(self.remaining)),
209        )
210    }
211}
212
213/// An iterator that skips the first N items.
214pub struct SkipIterator<I> {
215    inner: I,
216    to_skip: usize,
217}
218
219impl<I: Iterator> SkipIterator<I> {
220    /// Create a new skip iterator.
221    pub fn new(inner: I, count: usize) -> Self {
222        Self {
223            inner,
224            to_skip: count,
225        }
226    }
227}
228
229impl<I: Iterator> Iterator for SkipIterator<I> {
230    type Item = I::Item;
231
232    fn next(&mut self) -> Option<Self::Item> {
233        while self.to_skip > 0 {
234            self.to_skip -= 1;
235            self.inner.next()?;
236        }
237        self.inner.next()
238    }
239}
240
241/// An iterator that chains two iterators together.
242pub struct ChainIterator<I1, I2>
243where
244    I1: Iterator,
245    I2: Iterator<Item = I1::Item>,
246{
247    first: Option<I1>,
248    second: I2,
249}
250
251impl<I1, I2> ChainIterator<I1, I2>
252where
253    I1: Iterator,
254    I2: Iterator<Item = I1::Item>,
255{
256    /// Create a new chain iterator.
257    pub fn new(first: I1, second: I2) -> Self {
258        Self {
259            first: Some(first),
260            second,
261        }
262    }
263}
264
265impl<I1, I2> Iterator for ChainIterator<I1, I2>
266where
267    I1: Iterator,
268    I2: Iterator<Item = I1::Item>,
269{
270    type Item = I1::Item;
271
272    fn next(&mut self) -> Option<Self::Item> {
273        if let Some(ref mut first) = self.first {
274            if let Some(item) = first.next() {
275                return Some(item);
276            }
277            self.first = None;
278        }
279        self.second.next()
280    }
281}
282
283#[cfg(test)]
284mod tests {
285    use super::*;
286
287    #[test]
288    fn test_codepoint_iterator() {
289        let iter = CodepointIterator::new("ABC");
290        let codepoints: Vec<_> = iter.collect();
291        assert_eq!(codepoints.len(), 3);
292        assert_eq!(codepoints[0].to_string_value(), "65");
293        assert_eq!(codepoints[1].to_string_value(), "66");
294        assert_eq!(codepoints[2].to_string_value(), "67");
295    }
296
297    #[test]
298    fn test_positional_iterator() {
299        let items = vec![1, 2, 3];
300        let mut iter = PositionalIterator::new(&items);
301
302        let (pos, val) = iter.next().unwrap();
303        assert_eq!(pos, 1);
304        assert_eq!(*val, 1);
305
306        let (pos, val) = iter.next().unwrap();
307        assert_eq!(pos, 2);
308        assert_eq!(*val, 2);
309    }
310
311    #[test]
312    fn test_take_iterator() {
313        let items = vec![1, 2, 3, 4, 5];
314        let iter = TakeIterator::new(items.into_iter(), 3);
315        let result: Vec<_> = iter.collect();
316        assert_eq!(result, vec![1, 2, 3]);
317    }
318
319    #[test]
320    fn test_skip_iterator() {
321        let items = vec![1, 2, 3, 4, 5];
322        let iter = SkipIterator::new(items.into_iter(), 2);
323        let result: Vec<_> = iter.collect();
324        assert_eq!(result, vec![3, 4, 5]);
325    }
326
327    #[test]
328    fn test_filter_iterator() {
329        let items = vec![1, 2, 3, 4, 5];
330        let iter = FilterIterator::new(items.into_iter(), |&x| x % 2 == 0);
331        let result: Vec<_> = iter.collect();
332        assert_eq!(result, vec![2, 4]);
333    }
334
335    #[test]
336    fn test_map_iterator() {
337        let items = vec![1, 2, 3];
338        let iter = MapIterator::new(items.into_iter(), |x| x * 2);
339        let result: Vec<_> = iter.collect();
340        assert_eq!(result, vec![2, 4, 6]);
341    }
342
343    #[test]
344    fn test_chain_iterator() {
345        let first = vec![1, 2];
346        let second = vec![3, 4];
347        let iter = ChainIterator::new(first.into_iter(), second.into_iter());
348        let result: Vec<_> = iter.collect();
349        assert_eq!(result, vec![1, 2, 3, 4]);
350    }
351}