rta_for_fps_lib/iterators/peek.rs
1//! Module for the `Peeker` and `PeekRef` implementation and definition
2
3use core::marker::PhantomData;
4use core::ops::{Deref, DerefMut};
5use core::ptr::NonNull;
6
7/// Smart Pointer to a Peek Element
8/// allows viewing, modifying and taking the Peek Element
9#[derive(Debug)]
10pub struct PeekRef<'a, I> {
11 /// The reference to the nested options containing the Peek Element
12 #[allow(clippy::option_option)]
13 container: NonNull<Option<Option<I>>>,
14 /// The reference to the element contained in the above options
15 inner: NonNull<I>,
16 /// make sure we have the correct variance and
17 /// the only one with access to the original reference
18 /// while we are alive
19 mut_ref: PhantomData<&'a mut I>,
20}
21
22impl<'a, I> Deref for PeekRef<'a, I> {
23 type Target = I;
24
25 fn deref(&self) -> &Self::Target {
26 self.as_ref()
27 }
28}
29
30impl<'a, I> DerefMut for PeekRef<'a, I> {
31 fn deref_mut(&mut self) -> &mut Self::Target {
32 self.as_mut()
33 }
34}
35
36impl<'a, I> PeekRef<'a, I> {
37 /// Create a new `PeekRef` for the nested Options
38 #[allow(clippy::option_option)]
39 pub fn new(option: &'a mut Option<Option<I>>) -> Option<PeekRef<'a, I>> {
40 let option_ref = NonNull::from(&*option);
41 option
42 .as_mut()
43 .and_then(core::option::Option::as_mut)
44 .map(|inner| PeekRef {
45 container: option_ref,
46 inner: NonNull::from(inner),
47 mut_ref: PhantomData::<&'a mut I>,
48 })
49 }
50
51 /// Consume the `PeekRef` and get the peek element
52 #[allow(clippy::must_use_candidate)]
53 pub fn take(mut self) -> I {
54 unsafe {
55 // Safety:
56 // This type is constructed from mutable references to Options that contain the Some variant
57 // This types interface makes sure that the inner pointer stays valid until this value is
58 // dropped or take is called
59 //
60 // As we consume self it is safe to invalidate inner as we don't use it here
61 // and drop our self at the end of the function
62 self.container.as_mut()
63 }
64 .take()
65 .flatten()
66 .expect("Constructed only for Some variant containing Some variant")
67 }
68
69 /// Get a mutable reference to the peek element
70 fn as_mut(&mut self) -> &mut I {
71 unsafe {
72 // Safety:
73 // This type is constructed from mutable references to Options that contain the Some variant
74 // This types interface makes sure that the inner pointer stays valid until this value is
75 // dropped or take is called
76 //
77 // As we have a mutable reference to self we can't have given out another reference
78 // currently
79 self.inner.as_mut()
80 }
81 }
82 /// Get an immutable reference to the peek element
83 fn as_ref(&self) -> &I {
84 unsafe {
85 // Safety:
86 // This type is constructed from mutable references to Options that contain the Some variant
87 // This types interface makes sure that the inner pointer stays valid until this value is
88 // dropped or take is called
89 //
90 // As we have a reference to self we can't have given out a mutable reference
91 // currently
92 self.inner.as_ref()
93 }
94 }
95}
96
97/// A version of the standard libraries [`Peekable`](core::iter::Peekable) that lets one restore/replace/clear the peek element
98#[derive(Debug, Clone)]
99pub struct Peeker<I, IT> {
100 /// The iterator we are peeking into
101 iter: I,
102 /// If Some contains the peeked at value
103 /// which may be a None
104 /// Otherwise we have not peeked since the last next call
105 /// or the value was taken via a PeekRef
106 #[allow(clippy::option_option)]
107 peek_window: Option<Option<IT>>,
108}
109
110impl<I, IT> Peeker<I, IT>
111where
112 I: Iterator<Item = IT>,
113{
114 /// Create a new `Peeker`
115 pub fn new(inner: I) -> Self {
116 Self {
117 iter: inner,
118 peek_window: None,
119 }
120 }
121
122 /// Take a peek at the element that will be returned from the next next call
123 pub fn peek(&mut self) -> Option<&IT> {
124 self.peek_ref_mut().as_ref()
125 }
126
127 /// Take a mutable peek at the element that will be returned from the next next call
128 /// Changing the value behind the reference will change the next element
129 pub fn peek_mut(&mut self) -> Option<&mut IT> {
130 self.peek_ref_mut().as_mut()
131 }
132
133 /// Peek into the iterator if not done already and get a `PeekRef`
134 /// to the peeked value if it was Some
135 pub fn peek_ref(&mut self) -> Option<PeekRef<'_, IT>> {
136 self.peek_ref_mut();
137 PeekRef::new(&mut self.peek_window)
138 }
139
140 /// Make sure the peek slot is filled and return a mutable reference to the inner option
141 fn peek_ref_mut(&mut self) -> &mut Option<IT> {
142 let iter = &mut self.iter;
143 self.peek_window.get_or_insert_with(|| iter.next())
144 }
145
146 /// Set a peek window if there currently is none
147 ///
148 /// # Panics
149 /// If there is a window held as peek
150 pub fn restore_peek(&mut self, window: IT) {
151 if self.peek_window.take().flatten().is_none() {
152 self.peek_window = Some(Some(window))
153 } else {
154 panic!("Restoring over existing peek window!")
155 }
156 }
157}
158
159impl<I, IT> Iterator for Peeker<I, IT>
160where
161 I: Iterator<Item = IT>,
162{
163 type Item = IT;
164
165 fn next(&mut self) -> Option<Self::Item> {
166 self.peek_window.take().unwrap_or_else(|| self.iter.next())
167 }
168}