use std::fs::{self, OpenOptions};
use std::io::{self, BufReader, BufWriter, Read, Write};
use std::path::PathBuf;
use super::{InputProvider, OutputTarget};
#[derive(Debug, Clone)]
pub struct StdinInput {
id: String,
}
impl StdinInput {
pub fn new() -> Self {
Self { id: "-".into() }
}
}
impl Default for StdinInput {
fn default() -> Self {
Self::new()
}
}
impl InputProvider for StdinInput {
fn id(&self) -> &str {
&self.id
}
fn open(&self) -> io::Result<Box<dyn Read + Send>> {
let stdin = io::stdin();
Ok(Box::new(BufReader::new(stdin)))
}
}
#[derive(Debug, Clone)]
pub struct FileInput {
id: String,
path: PathBuf,
}
impl FileInput {
pub fn new(path: PathBuf) -> Self {
let id = path.to_string_lossy().into_owned();
Self { id, path }
}
pub fn path(&self) -> &PathBuf {
&self.path
}
}
impl InputProvider for FileInput {
fn id(&self) -> &str {
&self.id
}
fn open(&self) -> io::Result<Box<dyn Read + Send>> {
let file = std::fs::File::open(&self.path)?;
Ok(Box::new(BufReader::new(file)))
}
}
#[derive(Debug, Clone)]
pub struct StdoutOutput {
id: String,
}
impl StdoutOutput {
pub fn new() -> Self {
Self { id: "-".into() }
}
}
impl Default for StdoutOutput {
fn default() -> Self {
Self::new()
}
}
impl OutputTarget for StdoutOutput {
fn id(&self) -> &str {
&self.id
}
fn open_overwrite(&self) -> io::Result<Box<dyn Write + Send>> {
let stdout = io::stdout();
Ok(Box::new(BufWriter::new(stdout)))
}
fn open_append(&self) -> io::Result<Box<dyn Write + Send>> {
let stdout = io::stdout();
Ok(Box::new(BufWriter::new(stdout)))
}
}
#[derive(Debug, Clone)]
pub struct StderrOutput {
id: String,
}
impl StderrOutput {
pub fn new() -> Self {
Self {
id: "stderr".into(),
}
}
}
impl Default for StderrOutput {
fn default() -> Self {
Self::new()
}
}
impl OutputTarget for StderrOutput {
fn id(&self) -> &str {
&self.id
}
fn open_overwrite(&self) -> io::Result<Box<dyn Write + Send>> {
let stderr = io::stderr();
Ok(Box::new(BufWriter::new(stderr)))
}
fn open_append(&self) -> io::Result<Box<dyn Write + Send>> {
let stderr = io::stderr();
Ok(Box::new(BufWriter::new(stderr)))
}
}
#[derive(Debug, Clone)]
pub struct FileOutput {
id: String,
path: PathBuf,
}
impl FileOutput {
pub fn new(path: PathBuf) -> Self {
let id = path.to_string_lossy().into_owned();
Self { id, path }
}
pub fn path(&self) -> &PathBuf {
&self.path
}
}
impl OutputTarget for FileOutput {
fn id(&self) -> &str {
&self.id
}
fn open_overwrite(&self) -> io::Result<Box<dyn Write + Send>> {
if let Some(parent) = self.path.parent() {
if !parent.as_os_str().is_empty() {
fs::create_dir_all(parent)?;
}
}
let file = OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(&self.path)?;
Ok(Box::new(BufWriter::new(file)))
}
fn open_append(&self) -> io::Result<Box<dyn Write + Send>> {
if let Some(parent) = self.path.parent() {
if !parent.as_os_str().is_empty() {
fs::create_dir_all(parent)?;
}
}
let file = OpenOptions::new()
.create(true)
.append(true)
.open(&self.path)?;
Ok(Box::new(BufWriter::new(file)))
}
}