error_stack/
iter.rs

1//! Iterators over [`Frame`]s.
2
3use alloc::{vec, vec::Vec};
4#[cfg(nightly)]
5use core::marker::PhantomData;
6use core::{
7    fmt,
8    iter::FusedIterator,
9    slice::{Iter, IterMut},
10};
11
12use crate::Frame;
13
14/// Helper function, which is used in both [`Frames`] and [`FramesMut`].
15///
16/// To traverse the frames, the following algorithm is used:
17/// Given a list of iterators, take the last iterator, and use items from it until the iterator has
18/// been exhausted. If that is the case (it returned `None`), remove the iterator from the list,
19/// and continue with the next iterator until all iterators are exhausted.
20///
21/// # Example
22///
23/// ```text
24/// 1) Out: - Stack: [A, G]
25/// 2) Out: A Stack: [G] [B, C]
26/// 3) Out: B Stack: [G] [E] [C, D]
27/// 4) Out: C Stack: [G] [E] [D]
28/// 4) Out: D Stack: [G] [E]
29/// 5) Out: E Stack: [G] [F]
30/// 6) Out: F Stack: [G]
31/// 7) Out: G Stack: [H]
32/// 8) Out: H Stack: -
33/// ```
34fn next<I: Iterator<Item = T>, T>(iter: &mut Vec<I>) -> Option<T> {
35    let out;
36    loop {
37        let last = iter.last_mut()?;
38
39        if let Some(next) = last.next() {
40            out = next;
41            break;
42        }
43
44        // exhausted, therefore cannot be used anymore.
45        iter.pop();
46    }
47
48    Some(out)
49}
50
51/// Iterator over the [`Frame`] stack of a [`Report`].
52///
53/// This uses an implementation of the Pre-Order, NLR Depth-First Search algorithm to resolve the
54/// tree.
55///
56/// Use [`Report::frames()`] to create this iterator.
57///
58/// # Example
59///
60/// This shows in numbers the index of the different depths, using this it's possible to linearize
61/// all frames and sort topologically, meaning that this ensures no child ever is before its parent.
62///
63/// Iterating the following report will return the frames in alphabetical order:
64///
65/// ```text
66/// A
67/// ╰┬▶ B
68///  │  ╰┬▶ C
69///  │   ╰▶ D
70///  ╰▶ E
71///     ╰─▶ F
72/// G
73/// ╰─▶ H
74/// ```
75///
76/// [`Report`]: crate::Report
77/// [`Report::frames()`]: crate::Report::frames
78#[must_use]
79#[derive(Clone)]
80pub struct Frames<'r> {
81    stack: Vec<Iter<'r, Frame>>,
82}
83
84impl<'r> Frames<'r> {
85    pub(crate) fn new(frames: &'r [Frame]) -> Self {
86        Self {
87            stack: vec![frames.iter()],
88        }
89    }
90}
91
92impl<'r> Iterator for Frames<'r> {
93    type Item = &'r Frame;
94
95    fn next(&mut self) -> Option<Self::Item> {
96        let frame = next(&mut self.stack)?;
97
98        self.stack.push(frame.sources().iter());
99        Some(frame)
100    }
101}
102
103impl FusedIterator for Frames<'_> {}
104
105impl fmt::Debug for Frames<'_> {
106    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
107        fmt.debug_list().entries(self.clone()).finish()
108    }
109}
110
111/// Iterator over the mutable [`Frame`] stack of a [`Report`].
112///
113/// Use [`Report::frames_mut()`] to create this iterator.
114///
115/// [`Report`]: crate::Report
116/// [`Report::frames_mut()`]: crate::Report::frames_mut
117#[must_use]
118pub struct FramesMut<'r> {
119    stack: Vec<IterMut<'r, Frame>>,
120}
121
122impl<'r> FramesMut<'r> {
123    pub(crate) fn new(frames: &'r mut [Frame]) -> Self {
124        Self {
125            stack: vec![frames.iter_mut()],
126        }
127    }
128}
129
130impl<'r> Iterator for FramesMut<'r> {
131    type Item = &'r mut Frame;
132
133    fn next(&mut self) -> Option<Self::Item> {
134        let frame = next(&mut self.stack)?;
135        let frame: *mut Frame = frame;
136
137        // SAFETY:
138        // We require both mutable access to the frame for all sources (as a mutable iterator) and
139        // we need to return the mutable frame itself. We will never access the same value twice,
140        // and only store their mutable iterator until the next `next()` call. This function acts
141        // like a dynamic chain of multiple `IterMut`. The borrow checker is unable to prove that
142        // subsequent calls to `next()` won't access the same data.
143        // NB: It's almost never possible to implement a mutable iterator without `unsafe`.
144        unsafe {
145            self.stack.push((*frame).sources_mut().iter_mut());
146
147            Some(&mut *frame)
148        }
149    }
150}
151
152impl FusedIterator for FramesMut<'_> {}
153
154/// Iterator over requested references in the [`Frame`] stack of a [`Report`].
155///
156/// Use [`Report::request_ref()`] to create this iterator.
157///
158/// [`Report`]: crate::Report
159/// [`Report::request_ref()`]: crate::Report::request_ref
160#[must_use]
161#[cfg(nightly)]
162pub struct RequestRef<'r, T: ?Sized> {
163    frames: Frames<'r>,
164    _marker: PhantomData<&'r T>,
165}
166
167#[cfg(nightly)]
168impl<'r, T: ?Sized> RequestRef<'r, T> {
169    pub(super) fn new(frames: &'r [Frame]) -> Self {
170        Self {
171            frames: Frames::new(frames),
172            _marker: PhantomData,
173        }
174    }
175}
176
177#[cfg(nightly)]
178impl<'r, T> Iterator for RequestRef<'r, T>
179where
180    T: ?Sized + 'static,
181{
182    type Item = &'r T;
183
184    fn next(&mut self) -> Option<Self::Item> {
185        self.frames.by_ref().find_map(Frame::request_ref)
186    }
187}
188
189#[cfg(nightly)]
190impl<T> FusedIterator for RequestRef<'_, T> where T: ?Sized + 'static {}
191
192#[cfg(nightly)]
193impl<T: ?Sized> Clone for RequestRef<'_, T> {
194    fn clone(&self) -> Self {
195        Self {
196            frames: self.frames.clone(),
197            _marker: PhantomData,
198        }
199    }
200}
201
202#[cfg(nightly)]
203impl<T> fmt::Debug for RequestRef<'_, T>
204where
205    T: ?Sized + fmt::Debug + 'static,
206{
207    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
208        fmt.debug_list().entries(self.clone()).finish()
209    }
210}
211
212/// Iterator over requested values in the [`Frame`] stack of a [`Report`].
213///
214/// Use [`Report::request_value()`] to create this iterator.
215///
216/// [`Report`]: crate::Report
217/// [`Report::request_value()`]: crate::Report::request_value
218#[must_use]
219#[cfg(nightly)]
220pub struct RequestValue<'r, T> {
221    frames: Frames<'r>,
222    _marker: PhantomData<T>,
223}
224
225#[cfg(nightly)]
226impl<'r, T> RequestValue<'r, T> {
227    pub(super) fn new(frames: &'r [Frame]) -> Self {
228        Self {
229            frames: Frames::new(frames),
230            _marker: PhantomData,
231        }
232    }
233}
234
235#[cfg(nightly)]
236impl<T> Iterator for RequestValue<'_, T>
237where
238    T: 'static,
239{
240    type Item = T;
241
242    fn next(&mut self) -> Option<Self::Item> {
243        self.frames.find_map(Frame::request_value)
244    }
245}
246
247#[cfg(nightly)]
248impl<T> FusedIterator for RequestValue<'_, T> where T: 'static {}
249
250#[cfg(nightly)]
251impl<T> Clone for RequestValue<'_, T> {
252    fn clone(&self) -> Self {
253        Self {
254            frames: self.frames.clone(),
255            _marker: PhantomData,
256        }
257    }
258}
259
260#[cfg(nightly)]
261impl<T> fmt::Debug for RequestValue<'_, T>
262where
263    T: fmt::Debug + 'static,
264{
265    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
266        fmt.debug_list().entries(self.clone()).finish()
267    }
268}