use crate::{PatternBuffer, ToStderr};
use std::{fs::File, io::Write, path::PathBuf};
use sysexits::{ExitCode, Result};
pub trait Writer {
fn append(&self, buffer: Box<dyn PatternBuffer>) -> Result<()> {
self.behaviour(buffer, true, true, false)
}
fn append_silently(&self, buffer: Box<dyn PatternBuffer>) -> Result<()> {
self.behaviour(buffer, true, false, false)
}
fn behaviour(
&self,
buffer: Box<dyn PatternBuffer>,
append: bool,
show_error_messages: bool,
truncate: bool,
) -> Result<()>;
#[deprecated(since = "3.7.6", note = "use `aeruginous_io` instead")]
fn truncate(&self, buffer: Box<dyn PatternBuffer>) -> Result<()> {
self.behaviour(buffer, false, true, true)
}
#[deprecated(since = "3.7.6", note = "use `aeruginous_io` instead")]
fn truncate_silently(&self, buffer: Box<dyn PatternBuffer>) -> Result<()> {
self.behaviour(buffer, false, false, true)
}
fn write(&self, buffer: Box<dyn PatternBuffer>) -> Result<()> {
self.behaviour(buffer, false, true, false)
}
fn write_silently(&self, buffer: Box<dyn PatternBuffer>) -> Result<()> {
self.behaviour(buffer, false, false, false)
}
}
#[macro_export]
macro_rules! impl_pattern_writer_for {
( @all $T:ty ) => {
impl_pattern_writer_for!(@option $T);
impl_pattern_writer_for!(@ref $T);
};
( @option $T:ty ) => {
impl $crate::PatternWriter for $T {
fn behaviour(
&self,
buffer: Box<dyn PatternBuffer>,
append: bool,
show_error_messages: bool,
truncate: bool,
) -> Result<()> {
match self {
Some(thing) => Writer::behaviour(
thing,
buffer,
append,
show_error_messages,
truncate,
),
None => std::io::stdout().behaviour(
buffer,
append,
show_error_messages,
truncate,
),
}
}
}
};
( @ref $T:ty ) => {
impl $crate::PatternWriter for &$T {
fn behaviour(
&self,
buffer: Box<dyn PatternBuffer>,
append: bool,
show_error_messages: bool,
truncate: bool,
) -> Result<()> {
(*self).behaviour(buffer, append, show_error_messages, truncate)
}
}
};
}
impl_pattern_writer_for!(@all Option<PathBuf>);
impl_pattern_writer_for!(@option Option<&PathBuf>);
impl_pattern_writer_for!(@all Option<String>);
impl_pattern_writer_for!(@option Option<&str>);
impl_pattern_writer_for!(@ref PathBuf);
impl Writer for PathBuf {
fn behaviour(
&self,
buffer: Box<dyn PatternBuffer>,
append: bool,
show_error_messages: bool,
truncate: bool,
) -> Result<()> {
match File::options()
.append(append)
.create(true)
.write(true)
.truncate(truncate)
.open(self)
{
Ok(mut file) => {
let bytes = buffer.as_ref().try_into_bytes()?;
match file.write(&bytes) {
Ok(count) => {
if count == bytes.len() {
Ok(())
} else {
if show_error_messages {
eprintln!(
"Creating an exact copy was not possible."
);
}
Err(ExitCode::IoErr)
}
}
Err(error) => error.to_stderr(show_error_messages),
}
}
Err(error) => error.to_stderr(show_error_messages),
}
}
}
impl Writer for std::io::Stderr {
fn behaviour(
&self,
buffer: Box<dyn PatternBuffer>,
_: bool,
_: bool,
_: bool,
) -> Result<()> {
eprint!("{}", buffer.as_ref().try_into_string()?);
Ok(())
}
}
impl Writer for std::io::Stdout {
fn behaviour(
&self,
buffer: Box<dyn PatternBuffer>,
_: bool,
_: bool,
_: bool,
) -> Result<()> {
print!("{}", buffer.as_ref().try_into_string()?);
Ok(())
}
}
impl Writer for String {
fn behaviour(
&self,
buffer: Box<dyn PatternBuffer>,
append: bool,
show_error_messages: bool,
truncate: bool,
) -> Result<()> {
PathBuf::from(&self).behaviour(
buffer,
append,
show_error_messages,
truncate,
)
}
}
impl Writer for &str {
fn behaviour(
&self,
buffer: Box<dyn PatternBuffer>,
append: bool,
show_error_messages: bool,
truncate: bool,
) -> Result<()> {
PathBuf::from(&self).behaviour(
buffer,
append,
show_error_messages,
truncate,
)
}
}