bitpill 0.3.5

A personal medication management TUI application built in Rust.
Documentation
use std::time::Duration;

use crate::presentation::tui::input::Key;

pub trait EventSource {
    fn poll(&self, duration: Duration) -> Result<bool, std::io::Error>;
    fn read_key(&self) -> Result<Key, std::io::Error>;
}

pub struct RealEventSource;

impl EventSource for RealEventSource {
    fn poll(&self, duration: Duration) -> Result<bool, std::io::Error> {
        crossterm::event::poll(duration)
    }

    fn read_key(&self) -> Result<Key, std::io::Error> {
        match crossterm::event::read()? {
            crossterm::event::Event::Key(k) => Ok(Key::from(k)),
            _ => Err(std::io::Error::other("RealEventSource: non-key event")),
        }
    }
}

#[derive(Clone, Default)]
pub struct FakeEventSource {
    poll_result: Option<bool>,
    read_result: Option<Key>,
}

impl FakeEventSource {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn with_poll_result(mut self, result: bool) -> Self {
        self.poll_result = Some(result);
        self
    }

    pub fn with_event(mut self, event: Key) -> Self {
        self.read_result = Some(event);
        self
    }

    pub fn with_key(mut self, key: Key) -> Self {
        self.read_result = Some(key);
        self
    }

    pub fn no_event(self) -> Self {
        self.with_poll_result(false)
    }

    pub fn with_quit_event(self) -> Self {
        self.with_poll_result(true).with_key(Key::Esc)
    }

    pub fn with_char_event(self, c: char) -> Self {
        self.with_poll_result(true).with_key(Key::Char(c))
    }
}

impl EventSource for FakeEventSource {
    fn poll(&self, _: Duration) -> Result<bool, std::io::Error> {
        Ok(self.poll_result.unwrap_or(false))
    }

    fn read_key(&self) -> Result<Key, std::io::Error> {
        self.read_result
            .clone()
            .ok_or_else(|| std::io::Error::other("FakeEventSource: no event configured"))
    }
}