Skip to main content

rootcause/report_attachments/
iter.rs

1use core::iter::FusedIterator;
2
3use rootcause_internals::RawAttachment;
4
5use crate::{
6    markers::Dynamic,
7    report_attachment::{ReportAttachment, ReportAttachmentMut, ReportAttachmentRef},
8};
9
10/// An iterator over references to report attachments.
11///
12/// This iterator yields [`ReportAttachmentRef`] items and is created by calling
13/// [`ReportAttachments::iter`].
14///
15/// [`ReportAttachmentRef`]: crate::report_attachment::ReportAttachmentRef
16/// [`ReportAttachments::iter`]: crate::report_attachments::ReportAttachments::iter
17///
18/// # Examples
19///
20/// ```
21/// use rootcause::{
22///     report_attachment::ReportAttachment,
23///     report_attachments::{ReportAttachments, ReportAttachmentsIter},
24/// };
25///
26/// let mut attachments = ReportAttachments::new_sendsync();
27/// attachments.push(ReportAttachment::new("debug info").into_dynamic());
28/// attachments.push(ReportAttachment::new(42).into_dynamic());
29///
30/// let iterator: ReportAttachmentsIter<'_> = attachments.iter();
31/// ```
32#[must_use]
33pub struct ReportAttachmentsIter<'a> {
34    raw: core::slice::Iter<'a, RawAttachment>,
35}
36
37impl<'a> ReportAttachmentsIter<'a> {
38    /// Creates a new [`ReportAttachmentsIter`] from an iterator of raw
39    /// attachments
40    pub(crate) fn from_raw(raw: core::slice::Iter<'a, RawAttachment>) -> Self {
41        Self { raw }
42    }
43}
44
45impl<'a> Iterator for ReportAttachmentsIter<'a> {
46    type Item = ReportAttachmentRef<'a, Dynamic>;
47
48    fn next(&mut self) -> Option<Self::Item> {
49        let raw = self.raw.next()?.as_ref();
50
51        // SAFETY:
52        // 1. `A = Dynamic`, so this is trivially satisfied.
53        // 2. `A = Dynamic`, so this is trivially satisfied.
54        let attachment = unsafe {
55            // @add-unsafe-context: Dynamic
56            ReportAttachmentRef::<'a, Dynamic>::from_raw(raw)
57        };
58
59        Some(attachment)
60    }
61
62    fn size_hint(&self) -> (usize, Option<usize>) {
63        self.raw.size_hint()
64    }
65}
66
67impl<'a> DoubleEndedIterator for ReportAttachmentsIter<'a> {
68    fn next_back(&mut self) -> Option<Self::Item> {
69        let raw = self.raw.next_back()?.as_ref();
70
71        // SAFETY:
72        // 1. `A = Dynamic`, so this is trivially satisfied.
73        // 2. `A = Dynamic`, so this is trivially satisfied.
74        let attachment = unsafe {
75            // @add-unsafe-context: Dynamic
76            ReportAttachmentRef::<'a, Dynamic>::from_raw(raw)
77        };
78
79        Some(attachment)
80    }
81}
82
83impl<'a> ExactSizeIterator for ReportAttachmentsIter<'a> {
84    fn len(&self) -> usize {
85        self.raw.len()
86    }
87}
88
89impl<'a> FusedIterator for ReportAttachmentsIter<'a> {}
90
91/// An iterator over mutable references to report attachments.
92///
93/// This iterator yields [`ReportAttachmentMut`] items and is created by calling
94/// [`ReportAttachments::iter_mut`].
95///
96/// [`ReportAttachmentMut`]: crate::report_attachment::ReportAttachmentMut
97/// [`ReportAttachments::iter_mut`]: crate::report_attachments::ReportAttachments::iter_mut
98///
99/// # Examples
100/// ```
101/// use rootcause::{
102///     report_attachment::ReportAttachment,
103///     report_attachments::{ReportAttachments, ReportAttachmentsIterMut},
104/// };
105///
106/// let mut attachments = ReportAttachments::new_sendsync();
107/// attachments.push(ReportAttachment::new(41i32).into_dynamic());
108/// attachments.push(ReportAttachment::new(41i32).into_dynamic());
109///
110/// for mut attachment in attachments.iter_mut() {
111///     if let Some(num) = attachment.downcast_inner_mut::<i32>() {
112///         *num += 1;
113///     }
114/// }
115/// ```
116#[must_use]
117pub struct ReportAttachmentsIterMut<'a> {
118    raw: core::slice::IterMut<'a, RawAttachment>,
119}
120
121impl<'a> ReportAttachmentsIterMut<'a> {
122    /// Creates a new [`ReportAttachmentsIterMut`] from a mutable iterator of
123    /// raw attachments
124    pub(crate) fn from_raw(raw: core::slice::IterMut<'a, RawAttachment>) -> Self {
125        Self { raw }
126    }
127}
128
129impl<'a> Iterator for ReportAttachmentsIterMut<'a> {
130    type Item = ReportAttachmentMut<'a, Dynamic>;
131
132    fn next(&mut self) -> Option<Self::Item> {
133        let raw = self.raw.next()?.as_mut();
134
135        // SAFETY:
136        // 1. `A = Dynamic`, so this is trivially satisfied.
137        // 2. `A = Dynamic`, so this is trivially satisfied.
138        let attachment = unsafe {
139            // @add-unsafe-context: Dynamic
140            ReportAttachmentMut::<'a, Dynamic>::from_raw(raw)
141        };
142
143        Some(attachment)
144    }
145
146    fn size_hint(&self) -> (usize, Option<usize>) {
147        self.raw.size_hint()
148    }
149}
150
151impl<'a> DoubleEndedIterator for ReportAttachmentsIterMut<'a> {
152    fn next_back(&mut self) -> Option<Self::Item> {
153        let raw = self.raw.next_back()?.as_mut();
154
155        // SAFETY:
156        // 1. `A = Dynamic`, so this is trivially satisfied.
157        // 2. `A = Dynamic`, so this is trivially satisfied.
158        let attachment = unsafe {
159            // @add-unsafe-context: Dynamic
160            ReportAttachmentMut::<'a, Dynamic>::from_raw(raw)
161        };
162
163        Some(attachment)
164    }
165}
166
167impl<'a> ExactSizeIterator for ReportAttachmentsIterMut<'a> {
168    fn len(&self) -> usize {
169        self.raw.len()
170    }
171}
172
173impl<'a> FusedIterator for ReportAttachmentsIterMut<'a> {}
174
175/// FIXME: Once rust-lang/rust#132922 gets resolved, we can make the `raw` field
176/// an unsafe field and remove this module.
177mod limit_field_access {
178    use core::marker::PhantomData;
179
180    use rootcause_internals::RawAttachment;
181
182    /// An iterator that consumes report attachments and yields owned values.
183    ///
184    /// This iterator yields [`ReportAttachment`] items and is created by
185    /// calling [`ReportAttachments::into_iter`].
186    ///
187    /// [`ReportAttachment`]: crate::report_attachment::ReportAttachment
188    /// [`ReportAttachments::into_iter`]: crate::report_attachments::ReportAttachments::into_iter
189    ///
190    /// # Examples
191    ///
192    /// ```
193    /// use rootcause::{
194    ///     report_attachment::ReportAttachment,
195    ///     report_attachments::{ReportAttachments, ReportAttachmentsIntoIter},
196    /// };
197    ///
198    /// let mut attachments = ReportAttachments::new_sendsync();
199    /// attachments.push(ReportAttachment::new("debug info").into_dynamic());
200    /// attachments.push(ReportAttachment::new(42).into_dynamic());
201    ///
202    /// let iterator: ReportAttachmentsIntoIter<_> = attachments.into_iter();
203    /// ```
204    #[must_use]
205    pub struct ReportAttachmentsIntoIter<ThreadMarker: 'static> {
206        /// # Safety
207        ///
208        /// The following safety invariants are guaranteed to be upheld as long
209        /// as this struct exists:
210        ///
211        /// 1. Either the collection must be empty or `T` must either be
212        ///    `SendSync` or `Local`.
213        /// 2. If `T = SendSync`: All of the inner attachments must be `Send +
214        ///    Sync`.
215        raw: alloc::vec::IntoIter<RawAttachment>,
216        _thread_safety: PhantomData<ThreadMarker>,
217    }
218
219    impl<T> ReportAttachmentsIntoIter<T> {
220        /// Creates a new [`ReportAttachmentsIntoIter`] from an iterator of raw
221        /// attachments
222        ///
223        /// # Safety
224        ///
225        /// The caller must ensure:
226        ///
227        /// 1. Either the collection must be empty or `T` must either be
228        ///    `SendSync` or `Local`.
229        /// 2. If `T = SendSync`: All of the inner attachments must be `Send +
230        ///    Sync`.
231        pub(crate) unsafe fn from_raw(raw: alloc::vec::IntoIter<RawAttachment>) -> Self {
232            // SAFETY: We must uphold the safety invariants of the raw field:
233            // 1. Guaranteed by the caller
234            // 2. Guaranteed by the caller
235            Self {
236                raw,
237                _thread_safety: PhantomData,
238            }
239        }
240
241        /// Provides access to the inner raw iterator
242        pub(crate) fn as_raw(&self) -> &alloc::vec::IntoIter<RawAttachment> {
243            // SAFETY: We must uphold the safety invariants of the raw field:
244            // 1. Upheld as the type parameters do not change.
245            // 2. No mutation is possible through this reference
246            &self.raw
247        }
248
249        /// Provides mutable access to the inner raw iterator
250        ///
251        /// # Safety
252        ///
253        /// The caller must ensure:
254        ///
255        /// 1. If `T = SendSync`: No mutation is performed that invalidates the
256        ///    invariant that either all inner attachments are `Send + Sync` or
257        ///    the collection is empty.
258        pub(crate) unsafe fn as_raw_mut(&mut self) -> &mut alloc::vec::IntoIter<RawAttachment> {
259            // SAFETY: We must uphold the safety invariants of the raw field:
260            // 1. Upheld as the type parameters do not change.
261            // 2. Guaranteed by the caller
262            &mut self.raw
263        }
264    }
265}
266pub use limit_field_access::ReportAttachmentsIntoIter;
267
268impl<T> Iterator for ReportAttachmentsIntoIter<T> {
269    type Item = ReportAttachment<Dynamic, T>;
270
271    fn next(&mut self) -> Option<Self::Item> {
272        // SAFETY: We only remove items, we don't mutate them.
273        // 1. If the collection is already empty, this is a no-op and it is still empty
274        //    after. On the other hand, if there are items, we are guaranteed by the
275        //    invariants of this type that all inner attachments are `Send + Sync` if `T
276        //    = SendSync`.
277        let raw = unsafe { self.as_raw_mut() };
278
279        let attachment = raw.next()?;
280
281        // SAFETY:
282        // 1. `A=Dynamic`, so this is trivially satisfied.
283        // 2. Guaranteed by the invariants of this type.
284        // 3. `A=Dynamic`, so this is trivially satisfied.
285        // 4. Guaranteed by the invariants of this type.
286        let attachment = unsafe { ReportAttachment::<Dynamic, T>::from_raw(attachment) };
287
288        Some(attachment)
289    }
290
291    fn size_hint(&self) -> (usize, Option<usize>) {
292        self.as_raw().size_hint()
293    }
294}
295
296impl<T> DoubleEndedIterator for ReportAttachmentsIntoIter<T> {
297    fn next_back(&mut self) -> Option<Self::Item> {
298        // SAFETY: We only remove items, we don't mutate them.
299        // 1. If the collection is already empty, this is a no-op and it is still empty
300        //    after. On the other hand, if there are items, we are guaranteed by the
301        //    invariants of this type that all inner attachments are `Send + Sync` if `T
302        //    = SendSync`.
303        let raw = unsafe { self.as_raw_mut() };
304
305        let attachment = raw.next_back()?;
306
307        // SAFETY:
308        // 1. `A=Dynamic`, so this is trivially satisfied.
309        // 2. Guaranteed by the invariants of this type.
310        // 3. `A=Dynamic`, so this is trivially satisfied.
311        // 4. Guaranteed by the invariants of this type.
312        let attachment = unsafe { ReportAttachment::<Dynamic, T>::from_raw(attachment) };
313
314        Some(attachment)
315    }
316}
317
318impl<T> ExactSizeIterator for ReportAttachmentsIntoIter<T> {
319    fn len(&self) -> usize {
320        self.as_raw().len()
321    }
322}
323
324impl<T> FusedIterator for ReportAttachmentsIntoIter<T> {}
325
326impl<T> Unpin for ReportAttachmentsIntoIter<T> {}