use crate::demo::DemoGenerator;
use crate::error::Result;
use std::fs::File;
use std::io::{self, BufRead, BufReader, Read};
use std::path::Path;
use crossterm::terminal::size;
pub struct InputReader {
source: Box<dyn BufRead>,
}
impl InputReader {
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
let file = File::open(path)?;
Ok(Self {
source: Box::new(BufReader::new(file)),
})
}
pub fn from_stdin() -> Result<Self> {
Ok(Self {
source: Box::new(BufReader::new(io::stdin())),
})
}
pub fn from_demo(_is_animated: bool) -> Result<Self> {
let (width, height) = size()?;
let generator = DemoGenerator::new(width, height.saturating_sub(2)); Ok(Self {
source: Box::new(DemoInput::new(generator)),
})
}
pub fn reader(&mut self) -> &mut dyn BufRead {
&mut *self.source
}
pub fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
self.source.read_to_string(buf).map_err(Into::into)
}
pub fn lines(self) -> impl Iterator<Item = Result<String>> {
self.source.lines().map(|line| line.map_err(Into::into))
}
}
struct DemoInput {
buffer: Vec<u8>,
position: usize,
}
impl DemoInput {
fn new(mut generator: DemoGenerator) -> Self {
log::info!("Initializing demo mode content");
let content = generator.generate();
let buffer = content.into_bytes();
log::debug!("Demo content size: {} bytes", buffer.len());
Self {
buffer,
position: 0,
}
}
}
impl Read for DemoInput {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if self.position >= self.buffer.len() {
return Ok(0);
}
let available = self.buffer.len() - self.position;
let to_copy = available.min(buf.len());
buf[..to_copy].copy_from_slice(&self.buffer[self.position..self.position + to_copy]);
self.position += to_copy;
Ok(to_copy)
}
}
impl BufRead for DemoInput {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
Ok(&self.buffer[self.position..])
}
fn consume(&mut self, amt: usize) {
self.position = (self.position + amt).min(self.buffer.len());
}
}