Skip to main content

dfir_pipes/pull/
filter_map.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 both filters and maps items.
9    #[must_use = "`Pull`s do nothing unless polled"]
10    #[derive(Clone, Debug)]
11    pub struct FilterMap<Prev, Func> {
12        #[pin]
13        prev: Prev,
14        func: Func,
15    }
16}
17
18impl<Prev, Func> FilterMap<Prev, Func>
19where
20    Self: Pull,
21{
22    pub(crate) const fn new(prev: Prev, func: Func) -> Self {
23        Self { prev, func }
24    }
25}
26
27impl<Prev, Func, Item> Pull for FilterMap<Prev, Func>
28where
29    Prev: Pull,
30    Func: FnMut(Prev::Item) -> Option<Item>,
31{
32    type Ctx<'ctx> = Prev::Ctx<'ctx>;
33
34    type Item = Item;
35    type Meta = Prev::Meta;
36    type CanPend = Prev::CanPend;
37    type CanEnd = Prev::CanEnd;
38
39    fn pull(
40        self: Pin<&mut Self>,
41        ctx: &mut Self::Ctx<'_>,
42    ) -> PullStep<Self::Item, Self::Meta, Self::CanPend, Self::CanEnd> {
43        let mut this = self.project();
44        loop {
45            return match this.prev.as_mut().pull(ctx) {
46                PullStep::Ready(item, meta) => {
47                    if let Some(mapped) = (this.func)(item) {
48                        PullStep::Ready(mapped, meta)
49                    } else {
50                        continue;
51                    }
52                }
53                PullStep::Pending(can_pend) => PullStep::Pending(can_pend),
54                PullStep::Ended(can_end) => PullStep::Ended(can_end),
55            };
56        }
57    }
58
59    fn size_hint(&self) -> (usize, Option<usize>) {
60        let (_, upper) = self.prev.size_hint();
61        (0, upper)
62    }
63}
64
65impl<Prev, Func, Item> FusedPull for FilterMap<Prev, Func>
66where
67    Prev: FusedPull,
68    Func: FnMut(Prev::Item) -> Option<Item>,
69{
70}