Skip to main content

dfir_pipes/pull/
skip_while.rs

1use core::pin::Pin;
2
3use pin_project_lite::pin_project;
4
5use crate::pull::{FusedPull, Pull, PullStep};
6
7pin_project! {
8    /// Pull combinator that skips items while a predicate returns `true`.
9    #[must_use = "`Pull`s do nothing unless polled"]
10    #[derive(Clone, Debug)]
11    pub struct SkipWhile<Prev, Func> {
12        #[pin]
13        prev: Prev,
14        func: Func,
15        skipping: bool,
16    }
17}
18
19impl<Prev, Func> SkipWhile<Prev, Func>
20where
21    Self: Pull,
22{
23    pub(crate) const fn new(prev: Prev, func: Func) -> Self {
24        Self {
25            prev,
26            func,
27            skipping: true,
28        }
29    }
30}
31
32impl<Prev, Func> Pull for SkipWhile<Prev, Func>
33where
34    Prev: Pull,
35    Func: FnMut(&Prev::Item) -> bool,
36{
37    type Ctx<'ctx> = Prev::Ctx<'ctx>;
38
39    type Item = Prev::Item;
40    type Meta = Prev::Meta;
41    type CanPend = Prev::CanPend;
42    type CanEnd = Prev::CanEnd;
43
44    fn pull(
45        self: Pin<&mut Self>,
46        ctx: &mut Self::Ctx<'_>,
47    ) -> PullStep<Self::Item, Self::Meta, Self::CanPend, Self::CanEnd> {
48        let mut this = self.project();
49
50        loop {
51            return match this.prev.as_mut().pull(ctx) {
52                PullStep::Ready(item, meta) => {
53                    if *this.skipping && (this.func)(&item) {
54                        continue;
55                    }
56                    *this.skipping = false;
57                    PullStep::Ready(item, meta)
58                }
59                PullStep::Pending(can_pend) => PullStep::Pending(can_pend),
60                PullStep::Ended(can_end) => PullStep::Ended(can_end),
61            };
62        }
63    }
64
65    fn size_hint(&self) -> (usize, Option<usize>) {
66        let (_, upper) = self.prev.size_hint();
67        if self.skipping {
68            // Still skipping, so lower bound is 0
69            (0, upper)
70        } else {
71            // Done skipping, pass through
72            self.prev.size_hint()
73        }
74    }
75}
76
77impl<Prev, Func> FusedPull for SkipWhile<Prev, Func>
78where
79    Prev: FusedPull,
80    Func: FnMut(&Prev::Item) -> bool,
81{
82}