operator based command spawning and direction in rust (wip)
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Process("echo a")[Io::Front] => Process(grep("a"))[Io::Middle] => Process(File)
/// # Safety
///
/// this will return the number of bytes passed to the buffer, and ret < buffer bounds
pub unsafe trait Process: std::fmt::Debug {
    fn run(&mut self, on: Io) -> anyhow::Result<usize>;
    fn done(&mut self, before: Option<bool>) -> anyhow::Result<bool> {
        Ok(before.unwrap_or(false))
    }
}

#[derive(Debug)]
pub struct Processor {
    pub(crate) processes: Vec<Box<dyn Process>>,
    buffer: Vec<u8>,
    buffer_size: u32,
}

pub enum Io<'a> {
    /// echo "a" => next
    First(&'a mut [u8]),
    /// => file
    Last(&'a [u8]),
    /// => this =>
    Middle(&'a [u8], &'a mut [u8]),
}

#[derive(Copy, Clone, Debug)]
enum Buf {
    A,
    B,
}

impl Processor {
    pub fn new(buffer: u32) -> Self {
        Processor {
            processes: Vec::with_capacity(2),
            buffer: vec![0; buffer as usize * 2],
            buffer_size: buffer,
        }
    }

    pub(crate) fn add(&mut self, p: impl Process + 'static) {
        self.processes.push(Box::new(p));
    }

    pub fn complete(&mut self) -> anyhow::Result<()> {
        while !self.done()? {
            self.step()?;
        }
        Ok(())
    }

    pub fn done(&mut self) -> anyhow::Result<bool> {
        let mut done = true;
        let mut last = None;
        for p in &mut self.processes {
            let result = p.done(last)?;
            done &= result;
            last = Some(result);
        }
        Ok(done)
    }

    pub fn step(&mut self) -> anyhow::Result<()> {
        macro_rules! a {
            () => {
                &mut self.buffer[..self.buffer_size as usize]
            };
        }
        macro_rules! b {
            () => {
                &mut self.buffer[self.buffer_size as usize..]
            };
        }
        // [a,b,c,d,e]
        // a (first(a_buf))
        // b (mid(a_buf, b_buf))
        // c (mid(b_buf, a_buf))
        // d (mid(a_buf, b_buf))
        // e (last(b_buf))
        let mut last = Buf::A;
        let mut read = 0;
        let size = self.processes.len();
        for (i, p) in self.processes.iter_mut().enumerate() {
            match i {
                0 => read = p.run(Io::First(a!()))?,
                n if n + 1 == size => {
                    p.run(Io::Last(
                        &match last {
                            Buf::A => a!(),
                            Buf::B => b!(),
                        }[..read],
                    ))?;
                }
                _ => match last {
                    Buf::A => {
                        let (a, b) = self.buffer.split_at_mut(self.buffer_size as usize);
                        read = p.run(Io::Middle(&a[..read], b))?;
                        last = Buf::B;
                    }
                    Buf::B => {
                        let (a, b) = self.buffer.split_at_mut(self.buffer_size as usize);
                        read = p.run(Io::Middle(&b[..read], a))?;
                        last = Buf::A;
                    }
                },
            }
        }
        Ok(())
    }
}