1use alloc::boxed::Box;
2use core::{fmt, ops::ControlFlow};
3
4use crate::{
5 try_trait_v2::{FromResidual, Try},
6 DoubleEndedLender, ExactSizeLender, FusedLender, Lend, Lender, Lending,
7};
8
9#[must_use = "lenders are lazy and do nothing unless consumed"]
10pub struct Peekable<'this, L>
11where
12 L: Lender,
13{
14 lender: Box<L>,
15 peeked: Option<Option<Lend<'this, L>>>,
16}
17impl<'this, L> Peekable<'this, L>
18where
19 L: Lender,
20{
21 pub(crate) fn new(lender: L) -> Peekable<'this, L> {
22 Peekable { lender: Box::new(lender), peeked: None }
23 }
24 pub fn into_inner(self) -> L {
25 *self.lender
26 }
27 pub fn peek(&mut self) -> Option<&'_ Lend<'this, L>> {
28 let lender = &mut self.lender;
29 self.peeked
30 .get_or_insert_with(|| {
31 unsafe { core::mem::transmute::<Option<Lend<'_, L>>, Option<Lend<'this, L>>>(lender.next()) }
33 })
34 .as_ref()
35 }
36 pub fn peek_mut(&mut self) -> Option<&'_ mut Lend<'this, L>> {
37 let lender = &mut self.lender;
38 self.peeked
39 .get_or_insert_with(|| {
40 unsafe { core::mem::transmute::<Option<Lend<'_, L>>, Option<Lend<'this, L>>>(lender.next()) }
42 })
43 .as_mut()
44 }
45 pub fn next_if<F>(&mut self, f: F) -> Option<Lend<'_, L>>
46 where
47 F: FnOnce(&Lend<'_, L>) -> bool,
48 {
49 let peeked = unsafe { &mut *(&mut self.peeked as *mut _) };
50 match self.next() {
51 Some(v) if f(&v) => Some(v),
52 v => {
53 *peeked = Some(unsafe { core::mem::transmute::<Option<Lend<'_, L>>, Option<Lend<'this, L>>>(v) });
55 None
56 }
57 }
58 }
59 pub fn next_if_eq<'a, T>(&'a mut self, t: &T) -> Option<Lend<'a, L>>
60 where
61 T: for<'all> PartialEq<Lend<'all, L>>,
62 {
63 self.next_if(|v| t == v)
64 }
65}
66impl<L> Clone for Peekable<'_, L>
67where
68 L: Lender + Clone,
69{
70 fn clone(&self) -> Self {
71 Peekable { lender: self.lender.clone(), peeked: None }
72 }
73}
74impl<'this, L: fmt::Debug> fmt::Debug for Peekable<'this, L>
75where
76 L: Lender + fmt::Debug,
77 Lend<'this, L>: fmt::Debug,
78{
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 f.debug_struct("Peekable").field("lender", &self.lender).field("peeked", &self.peeked).finish()
81 }
82}
83impl<'lend, L> Lending<'lend> for Peekable<'_, L>
84where
85 L: Lender,
86{
87 type Lend = Lend<'lend, L>;
88}
89impl<'this, L> Lender for Peekable<'this, L>
90where
91 L: Lender,
92{
93 fn next(&mut self) -> Option<Lend<'_, Self>> {
94 match self.peeked.take() {
95 Some(peeked) => unsafe { core::mem::transmute::<Option<Lend<'this, Self>>, Option<Lend<'_, Self>>>(peeked) },
97 None => self.lender.next(),
98 }
99 }
100 #[inline]
101 fn count(mut self) -> usize {
102 match self.peeked.take() {
103 Some(None) => 0,
104 Some(Some(_)) => 1 + self.lender.count(),
105 None => self.lender.count(),
106 }
107 }
108 #[inline]
109 fn nth(&mut self, n: usize) -> Option<Lend<'_, Self>> {
110 match self.peeked.take() {
111 Some(None) => None,
112 Some(v @ Some(_)) if n == 0 => unsafe {
114 core::mem::transmute::<Option<Lend<'this, Self>>, Option<Lend<'_, Self>>>(v)
115 },
116 Some(Some(_)) => self.lender.nth(n - 1),
117 None => self.lender.nth(n),
118 }
119 }
120 #[inline]
121 fn last<'a>(&'a mut self) -> Option<Lend<'a, Self>>
122 where
123 Self: Sized,
124 {
125 let peek_opt = match self.peeked.take() {
126 Some(None) => return None,
127 Some(v) => unsafe { core::mem::transmute::<Option<Lend<'this, Self>>, Option<Lend<'a, Self>>>(v) },
129 None => None,
130 };
131 self.lender.last().or(peek_opt)
132 }
133 #[inline]
134 fn size_hint(&self) -> (usize, Option<usize>) {
135 let peek_len = match self.peeked {
136 Some(None) => return (0, Some(0)),
137 Some(Some(_)) => 1,
138 None => 0,
139 };
140 let (l, r) = self.lender.size_hint();
141 (l.saturating_add(peek_len), r.and_then(|r| r.checked_add(peek_len)))
142 }
143 #[inline]
144 fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
145 where
146 Self: Sized,
147 F: FnMut(B, Lend<'_, Self>) -> R,
148 R: Try<Output = B>,
149 {
150 let acc = match self.peeked.take() {
151 Some(None) => return Try::from_output(init),
152 Some(Some(v)) => match f(init, v).branch() {
153 ControlFlow::Break(b) => return FromResidual::from_residual(b),
154 ControlFlow::Continue(a) => a,
155 },
156 None => init,
157 };
158 self.lender.try_fold(acc, f)
159 }
160 #[inline]
161 fn fold<B, F>(mut self, init: B, mut f: F) -> B
162 where
163 Self: Sized,
164 F: FnMut(B, Lend<'_, Self>) -> B,
165 {
166 let acc = match self.peeked.take() {
167 Some(None) => return init,
168 Some(Some(v)) => f(init, v),
169 None => init,
170 };
171 self.lender.fold(acc, f)
172 }
173}
174impl<'this, L: DoubleEndedLender> DoubleEndedLender for Peekable<'this, L> {
175 #[inline]
176 fn next_back(&mut self) -> Option<Lend<'_, Self>> {
177 match self.peeked.as_mut() {
178 Some(v @ Some(_)) => self
180 .lender
181 .next_back()
182 .or_else(|| unsafe { core::mem::transmute::<Option<Lend<'this, Self>>, Option<Lend<'_, Self>>>(v.take()) }),
183 Some(None) => None,
184 None => self.lender.next_back(),
185 }
186 }
187 #[inline]
188 fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
189 where
190 Self: Sized,
191 F: FnMut(B, Lend<'_, Self>) -> R,
192 R: Try<Output = B>,
193 {
194 match self.peeked.take() {
195 None => self.lender.try_rfold(init, f),
196 Some(None) => Try::from_output(init),
197 Some(Some(v)) => match self.lender.try_rfold(init, &mut f).branch() {
198 ControlFlow::Continue(acc) => f(acc, v),
199 ControlFlow::Break(r) => {
200 self.peeked = Some(Some(v));
201 FromResidual::from_residual(r)
202 }
203 },
204 }
205 }
206 #[inline]
207 fn rfold<B, F>(mut self, init: B, mut f: F) -> B
208 where
209 Self: Sized,
210 F: FnMut(B, Lend<'_, Self>) -> B,
211 {
212 match self.peeked.take() {
213 None => self.lender.rfold(init, f),
214 Some(None) => init,
215 Some(Some(v)) => {
216 let acc = self.lender.rfold(init, &mut f);
217 f(acc, v)
218 }
219 }
220 }
221}
222impl<L: ExactSizeLender> ExactSizeLender for Peekable<'_, L> {}
223
224impl<L: FusedLender> FusedLender for Peekable<'_, L> {}
225
226#[cfg(test)]
227mod test {
228 use super::*;
229
230 struct ArrayLender {
231 array: [i32; 4],
232 }
233
234 impl<'lend> Lending<'lend> for ArrayLender {
235 type Lend = &'lend i32;
236 }
237
238 impl Lender for ArrayLender {
239 fn next(&mut self) -> Option<Lend<'_, Self>> {
240 Some(&self.array[0])
241 }
242 }
243
244 #[test]
249 fn test_peekable() {
250 let lender = ArrayLender { array: [-1, 1, 2, 3] };
251 let mut peekable = lender.peekable();
252 assert_eq!(**peekable.peek().unwrap(), -1);
253 assert_eq!(peekable.peeked.unwrap().unwrap() as *const _, &peekable.lender.array[0] as *const _);
254 moved_peekable(peekable);
255 }
256
257 fn moved_peekable(peekable: Peekable<ArrayLender>) {
258 let peeked = peekable.peeked.unwrap().unwrap() as *const _;
259 let array = &peekable.lender.array[0] as *const _;
260 assert_eq!(peeked, array, "Peeked element pointer should point to the first element of the array");
261 }
262}