use crate::Error;
use std::io::{Read, Write};
pub trait StreamBackend: Send + 'static {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error<'static>> {
let _ = buf;
Err(Error::from_message("Read not supported"))
}
fn write(&mut self, buf: &[u8]) -> Result<usize, Error<'static>> {
let _ = buf;
Err(Error::from_message("Write not supported"))
}
fn close(&mut self) -> Result<(), Error<'static>> {
Ok(())
}
fn data_available(&mut self) -> Result<bool, Error<'static>> {
Ok(true)
}
fn skip(&mut self, count: usize) -> Result<usize, Error<'static>> {
let mut buf = vec![0u8; count.min(8192)];
let mut total_skipped = 0;
while total_skipped < count {
let to_skip = (count - total_skipped).min(buf.len());
let n = self.read(&mut buf[..to_skip])?;
if n == 0 {
break; }
total_skipped += n;
}
Ok(total_skipped)
}
fn supports_mark(&self) -> bool {
false
}
fn mark(&mut self) -> Result<StreamMark, Error<'static>> {
Err(Error::from_message("Mark not supported"))
}
fn seek(&mut self, _mark: &StreamMark) -> Result<(), Error<'static>> {
Err(Error::from_message("Seek not supported"))
}
fn reset(&mut self) -> Result<(), Error<'static>> {
Err(Error::from_message("Reset not supported"))
}
fn supports_reset(&self) -> bool {
false
}
}
pub struct StreamMark {
pub(crate) position: u64,
}
impl<T> StreamBackend for T
where
T: Read + Write + Send + 'static,
{
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error<'static>> {
Read::read(self, buf).map_err(|e| Error::from_message(&e.to_string()))
}
fn write(&mut self, buf: &[u8]) -> Result<usize, Error<'static>> {
Write::write(self, buf).map_err(|e| Error::from_message(&e.to_string()))
}
fn close(&mut self) -> Result<(), Error<'static>> {
Write::flush(self).map_err(|e| Error::from_message(&e.to_string()))
}
}
pub struct BufferBackend {
buffer: Vec<u8>,
read_pos: usize,
write_pos: usize,
}
impl Default for BufferBackend {
fn default() -> Self {
Self::new()
}
}
impl BufferBackend {
pub fn new() -> Self {
Self {
buffer: Vec::new(),
read_pos: 0,
write_pos: 0,
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
buffer: Vec::with_capacity(capacity),
read_pos: 0,
write_pos: 0,
}
}
pub fn from_vec(buffer: Vec<u8>) -> Self {
let len = buffer.len();
Self {
buffer,
read_pos: 0,
write_pos: len,
}
}
}
impl StreamBackend for BufferBackend {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error<'static>> {
let available = self.write_pos.saturating_sub(self.read_pos);
let to_read = buf.len().min(available);
if to_read > 0 {
buf[..to_read].copy_from_slice(&self.buffer[self.read_pos..self.read_pos + to_read]);
self.read_pos += to_read;
}
Ok(to_read)
}
fn write(&mut self, buf: &[u8]) -> Result<usize, Error<'static>> {
if self.write_pos + buf.len() > self.buffer.len() {
self.buffer.resize(self.write_pos + buf.len(), 0);
}
self.buffer[self.write_pos..self.write_pos + buf.len()].copy_from_slice(buf);
self.write_pos += buf.len();
Ok(buf.len())
}
fn reset(&mut self) -> Result<(), Error<'static>> {
self.read_pos = 0;
Ok(())
}
fn supports_reset(&self) -> bool {
true
}
fn supports_mark(&self) -> bool {
true
}
fn mark(&mut self) -> Result<StreamMark, Error<'static>> {
Ok(StreamMark {
position: self.read_pos as u64,
})
}
fn seek(&mut self, mark: &StreamMark) -> Result<(), Error<'static>> {
let pos = mark.position as usize;
if pos <= self.write_pos {
self.read_pos = pos;
Ok(())
} else {
Err(Error::from_message("Seek position out of bounds"))
}
}
}
pub struct ReadOnlyBackend<R: Read + Send + 'static> {
reader: R,
}
impl<R: Read + Send + 'static> ReadOnlyBackend<R> {
pub fn new(reader: R) -> Self {
Self { reader }
}
}
impl<R: Read + Send + 'static> StreamBackend for ReadOnlyBackend<R> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error<'static>> {
self.reader
.read(buf)
.map_err(|e| Error::from_message(&e.to_string()))
}
}
pub struct WriteOnlyBackend<W: Write + Send + 'static> {
writer: W,
}
impl<W: Write + Send + 'static> WriteOnlyBackend<W> {
pub fn new(writer: W) -> Self {
Self { writer }
}
}
impl<W: Write + Send + 'static> StreamBackend for WriteOnlyBackend<W> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Error<'static>> {
self.writer
.write(buf)
.map_err(|e| Error::from_message(&e.to_string()))
}
fn close(&mut self) -> Result<(), Error<'static>> {
self.writer
.flush()
.map_err(|e| Error::from_message(&e.to_string()))
}
}