ushell 0.4.0

Embedded shell over serial connection
Documentation
#![no_std]
#![deny(unsafe_code)]

extern crate heapless;
extern crate nb;
extern crate uluru;

pub mod serial;
pub mod autocomplete;
pub mod control;
pub mod history;

mod shell;

use core::{fmt, marker::PhantomData, str::Utf8Error};
pub use shell::*;
pub use serial::*;


pub enum ShellError<S>
where
    S: Read<u8> + Write<u8>,
{
    ReadError(<S as Read<u8>>::Error),
    WriteError(<S as Write<u8>>::Error),
    FormatError(fmt::Error),
    BadInputError(Utf8Error),
    WouldBlock,
    HistoryError,
}

impl<S> From<fmt::Error> for ShellError<S>
where
    S: Read<u8> + Write<u8>,
{
    fn from(err: fmt::Error) -> Self {
        ShellError::FormatError(err)
    }
}

impl<S> From<Utf8Error> for ShellError<S>
where
    S: Read<u8> + Write<u8>,
{
    fn from(err: Utf8Error) -> Self {
        ShellError::BadInputError(err)
    }
}

pub enum SpinError<S, E>
where
    S: Read<u8> + Write<u8>,
{
    ShellError(ShellError<S>),
    EnvironmentError(E),
}

impl<S, E> From<ShellError<S>> for SpinError<S, E>
where
    S: Read<u8> + Write<u8>,
{
    fn from(err: ShellError<S>) -> Self {
        SpinError::ShellError(err)
    }
}

impl<S, E> From<fmt::Error> for SpinError<S, E>
where
    S: Read<u8> + Write<u8>,
{
    fn from(err: fmt::Error) -> Self {
        SpinError::ShellError(err.into())
    }
}

impl<S, E> From<Utf8Error> for SpinError<S, E>
where
    S: Read<u8> + Write<u8>,
{
    fn from(err: Utf8Error) -> Self {
        SpinError::ShellError(err.into())
    }
}

pub enum Input<'a> {
    Control(u8),
    Command((&'a str, &'a str)),
}

pub trait Environment<S, A, H, E, const CMD_LEN: usize>
where
    S: Read<u8> + Write<u8>,
    A: autocomplete::Autocomplete<CMD_LEN>,
    H: history::History<CMD_LEN>,
{
    fn command(
        &mut self,
        shell: &mut UShell<S, A, H, CMD_LEN>,
        cmd: &str,
        args: &str,
    ) -> SpinResult<S, E>;

    fn control(&mut self, shell: &mut UShell<S, A, H, CMD_LEN>, code: u8) -> SpinResult<S, E>;
}

pub struct Serial<W, TX: Write<W>, RX: Read<W>> {
    w: PhantomData<W>,
    tx: TX,
    rx: RX,
}

impl<W, TX: Write<W>, RX: Read<W>> Serial<W, TX, RX> {
    pub fn from_parts(tx: TX, rx: RX) -> Self {
        Self {
            tx,
            rx,
            w: PhantomData,
        }
    }

    pub fn tx(&mut self) -> &mut TX {
        &mut self.tx
    }

    pub fn rx(&mut self) -> &mut RX {
        &mut self.rx
    }

    pub fn split(self) -> (TX, RX) {
        (self.tx, self.rx)
    }
}

impl<W, TX: Write<W>, RX: Read<W>> Write<W> for Serial<W, TX, RX> {
    type Error = TX::Error;

    fn write(&mut self, word: W) -> nb::Result<(), Self::Error> {
        self.tx.write(word)
    }

    fn flush(&mut self) -> nb::Result<(), Self::Error> {
        self.tx.flush()
    }
}

impl<W, TX: Write<W>, RX: Read<W>> Read<W> for Serial<W, TX, RX> {
    type Error = RX::Error;

    fn read(&mut self) -> nb::Result<W, Self::Error> {
        self.rx.read()
    }
}