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
use ratatui::buffer::{Buffer, Cell};
use ratatui::layout::{Position, Rect};
use crate::CellFilter;

pub struct CellIterator<'a> {
    current: u16,
    area: Rect,
    buf: &'a mut Buffer,
    filter: Option<CellFilter>,
}

impl<'a> CellIterator<'a> {
    pub fn new(
        buf: &'a mut Buffer,
        area: Rect,
        filter: Option<CellFilter>,
    ) -> Self {
        Self { current: 0, area, buf, filter }
    }
    
    fn cell_mut(&mut self) -> (Position, &mut Cell) {
        let x = self.current % self.area.width;
        let y = self.current / self.area.width;

        let pos = Position::new(self.area.x + x, self.area.y + y);
        let cell = self.buf.get_mut(pos.x, pos.y);
        (pos, cell)
    }
}

impl<'a> Iterator for CellIterator<'a> {
    type Item = (Position, &'a mut Cell);

    fn next(&mut self) -> Option<Self::Item> {
        let selector = self.filter.as_ref().map(|f| f.selector(self.area));
        while self.current < self.area.area() {
            let (pos, cell) = self.cell_mut();
            // enforce cell's lifetime. this is safe because `buf` is guaranteed to outlive `'a`
            let cell: &'a mut Cell = unsafe { std::mem::transmute(cell) };
            self.current += 1;

            if let Some(filter) = &selector {
                if filter.is_valid(pos, cell) {
                    return Some((pos, cell));
                }
            } else {
                return Some((pos, cell));
            }
        }

        None
    }
}