use bytes::BytesMut;
use std::cmp::min;
use std::io::{self, Read, Write};
pub mod crypto;
pub mod progress;
mod traits;
pub use progress::{ProgressPipe, ProgressReader, ProgressReporter, ProgressWriter};
pub use traits::{Pipe, PipeLen, PipeRead, PipeWrite, ReadLen, WriteLen};
pub mod prelude {
pub use super::{crypto::prelude::*, Pipe, PipeLen, PipeRead, PipeWrite, ReadLen, WriteLen};
}
const DEFAULT_BUF_SIZE: usize = 8 * 1024;
pub struct PipeReader<P>
where
P: Pipe,
{
pipe: P,
inner: Box<dyn Read>,
buf: BytesMut,
}
pub struct PipeWriter<P>
where
P: Pipe,
{
pipe: P,
inner: Box<dyn Write>,
}
impl<P> PipeRead<P> for PipeReader<P>
where
P: Pipe,
{
fn new(pipe: P, inner: Box<dyn Read>) -> Self {
Self {
pipe,
inner,
buf: BytesMut::with_capacity(DEFAULT_BUF_SIZE),
}
}
}
impl<P> PipeWrite<P> for PipeWriter<P>
where
P: Pipe,
{
fn new(pipe: P, inner: Box<dyn Write>) -> Self {
Self { pipe, inner }
}
}
impl<P> Read for PipeReader<P>
where
P: Pipe,
{
fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
let capacity = min(DEFAULT_BUF_SIZE, buf.len()) - self.buf.len();
if capacity > 0 {
let mut inner_buf = vec![0u8; capacity];
let read = self.inner.read(&mut inner_buf)?;
self.buf.extend_from_slice(&inner_buf[..read]);
if read == 0 {
return Ok(0);
}
}
let (read, out) = self.pipe.pipe(&self.buf);
let _ = self.buf.split_to(read);
let mut total = 0;
if let Some(out) = out {
let write = min(out.len(), buf.len());
total += write;
buf[..write].copy_from_slice(&out[..write]);
assert_eq!(
write,
out.len(),
"failed to write all pipe output bytes to output buffer"
);
if write == buf.len() {
return Ok(total);
}
buf = &mut buf[write..];
}
self.read(buf).map(|n| n + total)
}
}
impl<P> Write for PipeWriter<P>
where
P: Pipe,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let (read, data) = self.pipe.pipe(buf);
if let Some(data) = data {
self.inner.write_all(&data)?;
}
Ok(read)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}