irid-std 0.1.0

A replacement for std when running without a filesystem on the irid kernel
Documentation
mod error;
mod stdio;

use core::{fmt::Arguments, marker::PhantomData};

use alloc::{string::{String, ToString}, vec::Vec};
pub use error::IOError as Error;
use heapless::format;
pub(crate) use error::WithPath;

pub type Stdin = stdio::StdInput<0>;
pub type Stdout = stdio::StdOutput<1>;
pub type Stderr = stdio::StdOutput<2>;

pub fn stdin() -> Stdin {
    Stdin {
        _hidden: PhantomData
    }
}

pub fn stdout() -> Stdout {
    Stdout {
        _hidden: PhantomData
    }
}

pub fn stderr() -> Stderr {
    Stderr {
        _hidden: PhantomData
    }
}

pub trait Read {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error>;

    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize, Error> { 
        let mut read = 0;

        let mut loops = 0;

        loop {
            if loops > 16 {
                panic!("IO Timeout");
            }
            let mut buffer = [0; 0x1000 * 16];

            let bytes = self.read(&mut buffer)?;

            read += bytes;
            buf.extend_from_slice(&buffer[0..bytes]);

            if bytes < buffer.len() {
                break;
            }

            loops += 1;
        }

        Ok(read)
    }

    fn read_to_string(&mut self, buf: &mut String) -> Result<usize, Error> {
        self.read_to_end(unsafe { buf.as_mut_vec() })
    }

    fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Error> {
        let bytes = self.read(buf)?;

        if bytes < buf.len() {
            Err(Error::EndOfFile)
        } else {
            Ok(())
        }
    }

    fn read_array<const N: usize>(&mut self) -> Result<[u8; N], Error> where Self: Sized {
        let mut array = [0; N];

        self.read_exact(&mut array)?;

        Ok(array)
    }
}

pub trait Write {
    fn write(&mut self, buf: &[u8]) -> Result<usize, Error>;
    fn flush(&mut self) -> Result<(), Error>;

    fn write_all(&mut self, mut buf: &[u8]) -> Result<(), Error> {
        while !buf.is_empty() {
            let written = self.write(buf)?;

            buf = &buf[written..];
        }

        Ok(())
    }

    fn write_fmt(&mut self, args: Arguments<'_>) -> Result<(), Error> {
        let string: Result<heapless::String<4096>, _> = format!("{args}");

        if let Ok(string) = string {
            self.write_all(string.as_bytes())
        } else {
            self.write_all(args.to_string().as_bytes())
        }
    }
}

pub trait Seek {
    fn seek(&mut self, pos: SeekFrom) -> Result<u64, Error>;

    fn rewind(&mut self) -> Result<(), Error> {
        self.seek(SeekFrom::Start(0)).map(|_| ())
    }

    fn stream_position(&mut self) -> Result<u64, Error> {
        self.seek(SeekFrom::Current(0))
    }

    fn seek_relative(&mut self, offset: i64) -> Result<(), Error> {
        self.seek(SeekFrom::Current(offset)).map(|_| ())
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SeekFrom {
    Start(u64),
    End(i64),
    Current(i64),
}