miniconf/
iter.rs

1use core::marker::PhantomData;
2
3use crate::{DescendError, IntoKeys, KeyError, Keys, Schema, Short, Track, Transcode};
4
5/// Counting wrapper for iterators with known exact size
6#[derive(Clone, Debug, PartialEq, Eq)]
7pub struct ExactSize<T> {
8    iter: T,
9    count: usize,
10}
11
12impl<T: Iterator> Iterator for ExactSize<T> {
13    type Item = T::Item;
14
15    fn next(&mut self) -> Option<Self::Item> {
16        if let Some(v) = self.iter.next() {
17            self.count -= 1; // checks for overflow in debug
18            Some(v)
19        } else {
20            debug_assert!(self.count == 0);
21            None
22        }
23    }
24
25    fn size_hint(&self) -> (usize, Option<usize>) {
26        (self.count, Some(self.count))
27    }
28}
29
30// Even though general TreeSchema iterations may well be longer than usize::MAX
31// we are sure that the aren't in this case since self.count <= usize::MAX
32impl<T: Iterator> ExactSizeIterator for ExactSize<T> {}
33
34// `Iterator` is sufficient to fuse
35impl<T: Iterator> core::iter::FusedIterator for ExactSize<T> {}
36
37// https://github.com/rust-lang/rust/issues/37572
38// unsafe impl<T: Iterator> core::iter::TrustedLen for ExactSize<T> {}
39
40/// Node iterator
41///
42/// A managed indices state for iteration of nodes `N` in a `TreeSchema`.
43///
44/// `D` is the depth limit. Internal nodes will be returned on iteration where
45/// the depth limit is exceeded.
46///
47/// The `Err(usize)` variant of the `Iterator::Item` indicates that `N` does
48/// not have sufficient capacity and failed to encode the key at the given depth.
49#[derive(Clone, Debug, PartialEq)]
50pub struct NodeIter<N, const D: usize> {
51    // We can't use Packed as state since we need to be able to modify the
52    // indices directly. Packed erases knowledge of the bit widths of the individual
53    // indices.
54    schema: &'static Schema,
55    state: [usize; D],
56    root: usize,
57    depth: usize,
58    _n: PhantomData<N>,
59}
60
61impl<N, const D: usize> NodeIter<N, D> {
62    /// Create a new iterator.
63    ///
64    /// # Panic
65    /// If the root depth exceeds the state length.
66    pub const fn with(schema: &'static Schema, state: [usize; D], root: usize) -> Self {
67        assert!(root <= D);
68        Self {
69            schema,
70            state,
71            root,
72            // Marker to prevent initial index increment in `next()`
73            depth: D + 1,
74            _n: PhantomData,
75        }
76    }
77
78    /// Create a new iterator with default root and initial state.
79    pub const fn new(schema: &'static Schema) -> Self {
80        Self::with(schema, [0; D], 0)
81    }
82
83    /// Limit and start iteration to at and below the provided root key.
84    ///
85    /// This requires moving `self` to ensure `FusedIterator`.
86    pub fn with_root(
87        schema: &'static Schema,
88        root: impl IntoKeys,
89    ) -> Result<Self, DescendError<()>> {
90        let mut state = [0; D];
91        let mut root = root.into_keys().track();
92        let mut tr = Short::new(state.as_mut());
93        tr.transcode(schema, &mut root)?;
94        Ok(Self::with(schema, state, root.depth()))
95    }
96
97    /// Wrap the iterator in an exact size counting iterator that is
98    /// `FusedIterator` and `ExactSizeIterator`.
99    ///
100    /// Note(panic): Panics, if the iterator had `next()` called or
101    /// if the iteration depth has been limited or if the iteration root
102    /// is not the tree root.
103    ///
104    pub const fn exact_size(schema: &'static Schema) -> ExactSize<Self> {
105        let shape = schema.shape();
106        if D < shape.max_depth {
107            panic!("insufficient depth for exact size iteration");
108        }
109        ExactSize {
110            iter: Self::new(schema),
111            count: shape.count.get(),
112        }
113    }
114
115    /// Return the underlying schema
116    pub const fn schema(&self) -> &'static Schema {
117        self.schema
118    }
119
120    /// Return the current state
121    pub fn state(&self) -> Option<&[usize]> {
122        self.state.get(..self.depth)
123    }
124
125    /// Return the root depth
126    pub const fn root(&self) -> usize {
127        self.root
128    }
129}
130
131impl<N: Transcode + Default, const D: usize> Iterator for NodeIter<N, D> {
132    type Item = Result<N, N::Error>;
133
134    fn next(&mut self) -> Option<Self::Item> {
135        loop {
136            debug_assert!(self.depth >= self.root);
137            debug_assert!(self.depth <= D + 1);
138            if self.depth == self.root {
139                // Iteration done
140                return None;
141            }
142            if self.depth <= D {
143                // Not initial state: increment
144                self.state[self.depth - 1] += 1;
145            }
146            let mut item = Track::new(N::default());
147            let ret = item.transcode(self.schema, &self.state[..]);
148            // Track<N> counts is the number of successful Keys::next()
149            let (item, depth) = item.into_inner();
150            match ret {
151                Err(DescendError::Key(KeyError::NotFound)) => {
152                    // Reset index at NotFound depth, then retry with incremented earlier index or terminate
153                    self.state[depth] = 0;
154                    self.depth = depth.max(self.root);
155                }
156                Err(DescendError::Key(KeyError::TooLong)) | Ok(()) => {
157                    // Leaf node found, save depth for increment at next iteration
158                    self.depth = depth;
159                    return Some(Ok(item));
160                }
161                Err(DescendError::Key(KeyError::TooShort)) => {
162                    // Use Short<N> to suppress this branch and also get internal short nodes
163                    self.depth = depth;
164                }
165                Err(DescendError::Inner(e)) => {
166                    // Target type can not hold keys
167                    return Some(Err(e));
168                }
169            }
170        }
171    }
172}
173
174// Contract: Do not allow manipulation of `depth` other than through iteration.
175impl<N: Transcode + Default, const D: usize> core::iter::FusedIterator for NodeIter<N, D> {}