use crate::{PatternBuffer, ToStderr};
use std::{io::stdin, path::PathBuf};
use sysexits::Result;
pub trait Reader {
fn behaviour(
&self,
show_error_messages: bool,
) -> Result<Box<dyn PatternBuffer>>;
fn read(&self) -> Result<Box<dyn PatternBuffer>> {
self.behaviour(true)
}
fn read_silently(&self) -> Result<Box<dyn PatternBuffer>> {
self.behaviour(false)
}
}
impl Reader for Option<PathBuf> {
fn behaviour(
&self,
show_error_messages: bool,
) -> Result<Box<dyn PatternBuffer>> {
self.as_ref().map_or_else(
|| stdin().behaviour(show_error_messages),
|path| Reader::behaviour(path, show_error_messages),
)
}
}
impl Reader for &Option<PathBuf> {
fn behaviour(
&self,
show_error_messages: bool,
) -> Result<Box<dyn PatternBuffer>> {
(*self).behaviour(show_error_messages)
}
}
impl Reader for PathBuf {
fn behaviour(
&self,
show_error_messages: bool,
) -> Result<Box<dyn PatternBuffer>> {
match std::fs::read_to_string(self) {
Ok(string) => Ok(Box::new(string)),
Err(error) => error.to_stderr(show_error_messages),
}
}
}
impl Reader for std::io::Stdin {
fn behaviour(
&self,
show_error_messages: bool,
) -> Result<Box<dyn PatternBuffer>> {
let mut result = String::new();
for line in stdin().lines() {
match line {
Ok(string) => result.push_str(&string),
Err(error) => return error.to_stderr(show_error_messages),
}
}
Ok(Box::new(result))
}
}
impl Reader for &Vec<PathBuf> {
fn behaviour(
&self,
show_error_messages: bool,
) -> Result<Box<dyn PatternBuffer>> {
if self.is_empty() {
stdin().behaviour(show_error_messages)
} else {
let mut result = Vec::<u8>::new();
for file in *self {
let mut bytes = Reader::behaviour(file, show_error_messages)?
.as_ref()
.try_into_bytes()?;
result.append(&mut bytes);
}
Ok(Box::new(result))
}
}
}