1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// use std::mem::replace;

// use super::*;

pub trait FlatScan {
    type YieldInput;
    type ReturnInput;
    type YieldOutputIterator: Iterator;
    type ReturnOutput;
    fn map_yield(&mut self, yield_input: Self::YieldInput) -> Self::YieldOutputIterator;
    fn map_return(&mut self, return_input: Self::ReturnInput) -> Self::ReturnOutput;
}

/*
pub trait FlatScan {
    type YieldInput;
    type ReturnInput;
    type OutputGenerator: Generator;
    fn map_yield(
        self,
        prior: Option<<Self::OutputGenerator as Generator>::Return>,
        input: Self::YieldInput,
    ) -> Self::OutputGenerator;
    fn map_return(
        self,
        prior: Option<<Self::OutputGenerator as Generator>::Return>,
        input: Self::ReturnInput,
    ) -> Self::OutputGenerator;
}

//

pub struct FlatScanGenerator<I, F: FlatScan> {
    input: I,
    flat_scan: F,
    ret: Option<<F::OutputGenerator as Generator>::Return>,
    list: Option<F::OutputGenerator>,
}

impl<I: Generator, F: FlatScan<Input = I::Yield> + Copy> Generator for FlatScanGenerator<I, F> {
    type Yield = <F::OutputGenerator as Generator>::Yield;
    type Return = (Option<<F::OutputGenerator as Generator>::Return>, I::Return);
    fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {
        loop {
            match &mut self.list {
                Some(list) => match list.resume() {
                    GeneratorState::Yielded(y) => return GeneratorState::Yielded(y),
                    GeneratorState::Completed(c) => {
                        self.list = None;
                        self.ret = Some(c);
                    }
                },
                None => {
                    let ret = replace(&mut self.ret, None);
                    match self.input.resume() {
                        GeneratorState::Yielded(y) => self.list = Some(self.flat_scan.map_input(ret, y)),
                        GeneratorState::Completed(c) => return GeneratorState::Completed((ret, c)),
                    }
                }
            }
        }
    }
}

pub trait FlatScanSugar: Generator + Sized {
    fn flat_scan<F: FlatScan<Input = Self::Yield>>(
        self,
        flat_scan: F,
        ret: Option<<F::OutputGenerator as Generator>::Return>,
    ) -> FlatScanGenerator<Self, F>;
}

impl<G: Generator> FlatScanSugar for G {
    fn flat_scan<F: FlatScan<Input = Self::Yield>>(
        self,
        flat_scan: F,
        ret: Option<<F::OutputGenerator as Generator>::Return>,
    ) -> FlatScanGenerator<Self, F> {
        FlatScanGenerator {
            input: self,
            flat_scan,
            ret,
            list: None,
        }
    }
}
*/