shelly-shell 0.5.4

A Rust based Unix style shell with a typed and structured language syntax.

use std::{
    io,
    pin::Pin,
    sync::Arc,
    task::{Context, Poll},
};

use tokio::{
    io::{AsyncRead, ReadBuf},
    sync::mpsc::{Receiver, Sender, channel},
};

use crate::{
    language::data::io::handles::{Control, Reader},
    runtime::tasks::ScriptFault,
};

pub enum Chunk
{
    Bytes(Arc<[u8]>),
    Failed(u64),
}

struct QueueReader
{
    receiver: Receiver<Chunk>,
    current: Arc<[u8]>,
    offset: usize,
}

impl AsyncRead for QueueReader
{
    fn poll_read(
        mut self: Pin<&mut Self>,
        context: &mut Context<'_>,
        output: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>>
    {
        loop
        {
            if self.offset < self.current.len()
            {
                let count = output.remaining().min(self.current.len() - self.offset);
                output.put_slice(&self.current[self.offset..self.offset + count]);
                self.offset += count;
                return Poll::Ready(Ok(()));
            }
            match self.receiver.poll_recv(context)
            {
                Poll::Ready(Some(Chunk::Bytes(bytes))) =>
                {
                    self.current = bytes;
                    self.offset = 0;
                }
                Poll::Ready(Some(Chunk::Failed(id))) =>
                {
                    return Poll::Ready(Err(io::Error::other(ScriptFault(id))));
                }
                Poll::Ready(None) => return Poll::Ready(Ok(())),
                Poll::Pending => return Poll::Pending,
            }
        }
    }
}

pub fn reader() -> (Reader, Sender<Chunk>)
{
    let (sender, receiver) = channel(1);
    let reader = Reader::new(
        QueueReader {
            receiver,
            current: Arc::from([]),
            offset: 0,
        },
        Control::new(),
    );
    (reader, sender)
}