use super::*;
pub trait FlatMapFn {
    type Input;
    type OutputList: ListFn;
    fn map(&self, input: Self::Input) -> Self::OutputList;
}
pub struct FlatMapList<I: ListFn, F: FlatMapFn<Input = I::Item>> {
    flat_map: F,
    input_list: I,
    output_list: Option<F::OutputList>,
}
impl<I: ListFn, F: FlatMapFn<Input = I::Item>> ListFn for FlatMapList<I, F> {
    type Item = <F::OutputList as ListFn>::Item;
    type End = I::End;
    fn next(mut self) -> ListState<Self> {
        loop {
            match self.output_list {
                Some(item_list) => match item_list.next() {
                    ListState::Some(some) => {
                        return ListState::some(
                            some.first,
                            FlatMapList {
                                flat_map: self.flat_map,
                                input_list: self.input_list,
                                output_list: Some(some.next),
                            },
                        )
                    }
                    ListState::End(..) => self.output_list = None,
                },
                None => match self.input_list.next() {
                    ListState::Some(some) => {
                        self.input_list = some.next;
                        self.output_list = Some(self.flat_map.map(some.first));
                    }
                    ListState::End(end) => return ListState::End(end),
                },
            }
        }
    }
}
pub trait FlatMap: ListFn {
    fn flat_map<F: FlatMapFn<Input = Self::Item>>(self, flat_map: F) -> FlatMapList<Self, F> {
        FlatMapList {
            input_list: self,
            flat_map,
            output_list: None,
        }
    }
}
impl<S: ListFn> FlatMap for S {}