use core::fmt::{Arguments, Debug};
use std::io;
use crate::{Flush, IntoWriteFn, WriteBytes, WriteStr};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct IoWriter<F1, F2>(F1, F2);
pub trait ExpectIoWriteResult {
fn expect_io_write_result(self, buf: &[u8]) -> io::Result<usize>;
}
pub trait ExpectIoFlushResult {
fn expect_io_flush_result(self) -> io::Result<()>;
}
impl<F1, F2> IoWriter<F1, F2>
where
F1: WriteStr,
F2: Flush,
{
pub fn new(write: F1, flush: F2) -> Self {
Self(write, flush)
}
}
impl<F1> IoWriter<F1, ()>
where
F1: WriteStr,
{
pub fn from_closure<F, Ts>(closure: F) -> Self
where
F: IntoWriteFn<Ts, WriteFn = F1>,
{
Self(closure.into_write_fn(), ())
}
}
impl<F1> IoWriter<F1, ()>
where
Self: io::Write,
{
pub fn write_fmt(&mut self, args: Arguments<'_>) -> io::Result<()> {
io::Write::write_fmt(self, args)
}
}
impl<F1, F2> io::Write for IoWriter<F1, F2>
where
Self: WriteBytes<Output = io::Result<usize>> + Flush<Output = io::Result<()>>,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
WriteBytes::write_bytes(self, buf)
}
fn flush(&mut self) -> io::Result<()> {
Flush::flush(self)
}
}
impl<F1, F2> WriteBytes for IoWriter<F1, F2>
where
F1: WriteBytes,
F1::Output: ExpectIoWriteResult,
{
type Output = io::Result<usize>;
fn write_bytes(&mut self, buf: &[u8]) -> Self::Output {
self.0.write_bytes(buf).expect_io_write_result(buf)
}
}
impl<F1, F2> Flush for IoWriter<F1, F2>
where
F2: Flush,
F2::Output: ExpectIoFlushResult,
{
type Output = io::Result<()>;
fn flush(&mut self) -> Self::Output {
self.1.flush().expect_io_flush_result()
}
}
impl ExpectIoWriteResult for () {
fn expect_io_write_result(self, buf: &[u8]) -> io::Result<usize> {
Ok(buf.len())
}
}
impl ExpectIoWriteResult for usize {
fn expect_io_write_result(self, buf: &[u8]) -> io::Result<usize> {
let _ = buf;
Ok(self)
}
}
impl<E: Debug> ExpectIoWriteResult for Result<(), E> {
fn expect_io_write_result(self, buf: &[u8]) -> io::Result<usize> {
self.expect("failed writing");
Ok(buf.len())
}
}
impl<E: Debug> ExpectIoWriteResult for Result<usize, E> {
fn expect_io_write_result(self, buf: &[u8]) -> io::Result<usize> {
let _ = buf;
Ok(self.expect("failed writing"))
}
}
impl ExpectIoFlushResult for () {
fn expect_io_flush_result(self) -> io::Result<()> {
Ok(())
}
}
impl<E: Debug> ExpectIoFlushResult for Result<(), E> {
fn expect_io_flush_result(self) -> io::Result<()> {
self.expect("failed flushing");
Ok(())
}
}