lb 0.6.0

A TUI library with ASCII/Unicode graphics.
Documentation
use std::io;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Key {
    Up,
    Down,
    Left,
    Right,
    Esc,
    Char(u8),
}

#[derive(Debug)]
pub struct Keys<'a> {
    buffer: &'a [u8],
    offset: usize,
}

impl<'a> Keys<'a> {
    #[inline]
    pub fn new<R>(reader: &mut R, buffer: &'a mut [u8]) -> io::Result<Self>
    where
        R: io::Read,
    {
        reader.read_keys(buffer)
    }

    #[inline]
    pub fn with_filled_buffer(buffer: &'a [u8]) -> Self {
        Self { buffer, offset: 0 }
    }

    #[inline]
    pub fn bytes(&self) -> &[u8] {
        self.buffer
    }

    #[inline]
    fn consume(&mut self, advance: usize, key: Key) -> Option<Key> {
        self.offset += advance;
        Some(key)
    }
}

impl<'a> Iterator for Keys<'a> {
    type Item = Key;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        match &self.buffer[self.offset..] {
            [] => None,
            [b'\x1b', rest @ ..] => match rest {
                [b'[', b'A', ..] => self.consume(3, Key::Up),
                [b'[', b'B', ..] => self.consume(3, Key::Down),
                [b'[', b'C', ..] => self.consume(3, Key::Right),
                [b'[', b'D', ..] => self.consume(3, Key::Left),
                _ => self.consume(1, Key::Esc),
            },
            [ch, ..] => self.consume(1, Key::Char(*ch)),
        }
    }
}

pub trait ReadKeys {
    fn read_keys<'a>(&mut self, buffer: &'a mut [u8]) -> io::Result<Keys<'a>>;
}

impl<R> ReadKeys for R
where
    R: io::Read,
{
    #[inline]
    fn read_keys<'a>(&mut self, buffer: &'a mut [u8]) -> io::Result<Keys<'a>> {
        let count = self.read(buffer)?;

        Ok(Keys::with_filled_buffer(&buffer[..count]))
    }
}