error_stack/
iter.rs

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