operator based command spawning and direction in rust (wip)
Diffstat (limited to 'src/processor.rs')
-rw-r--r--src/processor.rs112
1 files changed, 112 insertions, 0 deletions
diff --git a/src/processor.rs b/src/processor.rs
new file mode 100644
index 0000000..1d8b129
--- /dev/null
+++ b/src/processor.rs
@@ -0,0 +1,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(())
+ }
+}