use std::{
io::{self, Read, Write},
marker::PhantomData,
};
pub(super) struct Pipe<L, R> {
left: L,
right: R,
buffer_lr: Buffer<L, R>,
buffer_rl: Buffer<R, L>,
}
impl<L: Read + Write, R: Read + Write> Pipe<L, R> {
pub fn new(left: L, right: R) -> Self {
Self {
left,
right,
buffer_lr: Buffer::new(),
buffer_rl: Buffer::new(),
}
}
pub(super) fn left(&self) -> &L {
&self.left
}
pub(super) fn left_mut(&mut self) -> &mut L {
&mut self.left
}
pub(super) fn right(&self) -> &R {
&self.right
}
pub(crate) fn both_mut(&mut self) -> (&mut L, &mut R) {
(&mut self.left, &mut self.right)
}
pub fn read_left(&mut self) -> io::Result<()> {
self.buffer_lr.read(&mut self.left)
}
pub fn write_left(&mut self) -> io::Result<()> {
self.buffer_rl.write(&mut self.left)
}
pub fn read_right(&mut self) -> io::Result<()> {
self.buffer_rl.read(&mut self.right)
}
pub fn write_right(&mut self) -> io::Result<()> {
self.buffer_lr.write(&mut self.right)
}
pub fn flush_left(&mut self) -> io::Result<()> {
self.buffer_rl.flush(&mut self.left)
}
}
const BUFSIZE: usize = 6 * 1024;
struct Buffer<R, W> {
buffer: [u8; BUFSIZE],
start: usize,
end: usize,
marker: PhantomData<(R, W)>,
}
impl<R: Read, W: Write> Buffer<R, W> {
const fn new() -> Self {
Self {
buffer: [0; BUFSIZE],
start: 0,
end: 0,
marker: PhantomData,
}
}
fn read(&mut self, read: &mut R) -> io::Result<()> {
let buffer = &mut self.buffer[self.end..];
let len = read.read(buffer)?;
self.end += len;
Ok(())
}
fn write(&mut self, write: &mut W) -> io::Result<()> {
let buffer = &self.buffer[self.start..self.end];
let len = write.write(buffer)?;
if len == buffer.len() {
self.start = 0;
self.end = 0;
} else {
self.start += len;
}
Ok(())
}
fn flush(&mut self, write: &mut W) -> io::Result<()> {
let buffer = &self.buffer[self.start..self.end];
write.write_all(buffer)?;
self.start = 0;
self.end = 0;
write.flush()
}
}
impl<R: Read, W: Write> Default for Buffer<R, W> {
fn default() -> Self {
Self::new()
}
}