list_fn/
flat_scan.rs

1use super::*;
2
3pub trait FlatScanFn {
4    type InputItem;
5    type InputResult;
6    type OutputList: ListFn<End = Self>;
7    type EndList: ListFn<Item = <Self::OutputList as ListFn>::Item>;
8    /// Map the given `input` item into a list.
9    fn map_item(self, item: Self::InputItem) -> Self::OutputList;
10    /// Map the given `result` into an end list.
11    fn map_result(self, result: Self::InputResult) -> Self::EndList;
12}
13
14pub enum FlatScanState<I, F>
15where
16    I: ListFn,
17    F: FlatScanFn<InputItem = I::Item>,
18    I::End: ResultFn<Result = F::InputResult>,
19{
20    Begin {
21        flat_scan: F,
22        input_list: I,
23    },
24    OutputList {
25        output_list: F::OutputList,
26        input_list: I,
27    },
28    EndList(F::EndList),
29}
30
31impl<I, F> ListFn for FlatScanState<I, F>
32where
33    I: ListFn,
34    F: FlatScanFn<InputItem = I::Item>,
35    I::End: ResultFn<Result = F::InputResult>,
36{
37    type Item = <F::OutputList as ListFn>::Item;
38    type End = <F::EndList as ListFn>::End;
39    fn next(mut self) -> ListState<Self> {
40        loop {
41            self = match self {
42                FlatScanState::Begin {
43                    input_list,
44                    flat_scan,
45                } => match input_list.next() {
46                    ListState::Some(some) => FlatScanState::OutputList {
47                        output_list: flat_scan.map_item(some.first),
48                        input_list: some.next,
49                    },
50                    ListState::End(end) => {
51                        FlatScanState::EndList(flat_scan.map_result(end.result()))
52                    }
53                },
54                FlatScanState::OutputList {
55                    output_list,
56                    input_list,
57                } => match output_list.next() {
58                    ListState::Some(some) => {
59                        return ListState::some(
60                            some.first,
61                            FlatScanState::OutputList {
62                                output_list: some.next,
63                                input_list,
64                            },
65                        )
66                    }
67                    ListState::End(flat_scan) => FlatScanState::Begin {
68                        input_list,
69                        flat_scan,
70                    },
71                },
72                FlatScanState::EndList(end_list) => {
73                    return match end_list.next() {
74                        ListState::Some(some) => {
75                            ListState::some(some.first, FlatScanState::EndList(some.next))
76                        }
77                        ListState::End(end) => ListState::End(end),
78                    }
79                }
80            }
81        }
82    }
83}
84
85pub trait FlatScan: ListFn {
86    fn flat_scan<F>(self, flat_scan: F) -> FlatScanState<Self, F>
87    where
88        F: FlatScanFn<InputItem = Self::Item>,
89        Self::End: ResultFn<Result = F::InputResult>,
90    {
91        FlatScanState::Begin {
92            input_list: self,
93            flat_scan,
94        }
95    }
96}
97
98impl<S: ListFn> FlatScan for S {}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103
104    struct TestFlatScan();
105
106    impl ResultFn for TestFlatScan {
107        type Result = ();
108        fn result(self) {}
109    }
110
111    impl FlatScanFn for TestFlatScan {
112        type InputItem = ();
113        type InputResult = ();
114        type OutputList = Empty<(), Self>;
115        type EndList = Empty<(), Self>;
116        fn map_item(self, _: ()) -> Self::OutputList {
117            Empty::new(self)
118        }
119        fn map_result(self, _: ()) -> Self::EndList {
120            Empty::new(self)
121        }
122    }
123
124    #[test]
125    fn flat_scan_end() {
126        let x = Empty::<(), ()>::new(());
127        let f = TestFlatScan();
128        let list = x.flat_scan(f);
129        let _list1 = list.next();
130    }
131}