use std::{
cmp::min,
io::{self, Read, Write},
net::TcpStream,
time::Duration,
};
#[derive(Debug)]
struct StringStream(Vec<u8>, usize);
impl Read for StringStream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let n = self.peek(buf)?;
self.1 += n;
Ok(n)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
const CHUNK_SIZE: usize = 1024;
let mut chunk: [u8; CHUNK_SIZE] = [0; CHUNK_SIZE];
let n = self.1;
while self.read(&mut chunk)? > 0 {
buf.write_all(&chunk)?;
}
Ok(self.1 - n)
}
}
impl StringStream {
fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
if buf.is_empty() || self.1 >= self.0.len() {
return Ok(0);
}
let src = &self.0[self.1..];
let n = min(buf.len(), src.len());
buf[..n].copy_from_slice(src);
Ok(n)
}
}
#[derive(Debug)]
enum HttpStreamInner {
Tcp(TcpStream),
String(StringStream, Vec<u8>),
Dummy,
}
#[derive(Debug)]
pub struct HttpStream {
inner: HttpStreamInner,
}
impl HttpStream {
pub fn set_read_timeout(&self, d: Option<Duration>) -> io::Result<()> {
match &self.inner {
HttpStreamInner::Tcp(tcp_stream) => tcp_stream.set_read_timeout(d),
HttpStreamInner::Dummy | HttpStreamInner::String(..) => Ok(()),
}
}
pub fn peek(&self, buf: &mut [u8]) -> std::io::Result<usize> {
match &self.inner {
HttpStreamInner::Tcp(tcp_stream) => tcp_stream.peek(buf),
HttpStreamInner::Dummy => Ok(0),
HttpStreamInner::String(read, _) => read.peek(buf),
}
}
pub fn is_ready(&self) -> std::io::Result<bool> {
let mut buf = [0_u8; 1];
let n = match &self.inner {
HttpStreamInner::Tcp(tcp_stream) => tcp_stream.peek(&mut buf)?,
HttpStreamInner::String(string_stream, _) => string_stream.peek(&mut buf)?,
HttpStreamInner::Dummy => 0,
};
Ok(n > 0)
}
}
impl Read for HttpStream {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match &mut self.inner {
HttpStreamInner::Tcp(tcp_stream) => tcp_stream.read(buf),
HttpStreamInner::Dummy => Ok(0),
HttpStreamInner::String(buf_reader, _) => buf_reader.read(buf),
}
}
}
impl Write for HttpStream {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
match &mut self.inner {
HttpStreamInner::Tcp(tcp_stream) => tcp_stream.write(buf),
HttpStreamInner::Dummy => Ok(0),
HttpStreamInner::String(_, w) => w.write(buf),
}
}
fn flush(&mut self) -> std::io::Result<()> {
match &mut self.inner {
HttpStreamInner::Tcp(tcp_stream) => tcp_stream.flush(),
HttpStreamInner::Dummy | HttpStreamInner::String(..) => Ok(()),
}
}
}
impl From<TcpStream> for HttpStream {
fn from(value: TcpStream) -> Self {
Self {
inner: HttpStreamInner::Tcp(value),
}
}
}
impl From<String> for HttpStream {
fn from(value: String) -> Self {
let src_vec = value.into_bytes();
let stream = StringStream(src_vec, 0);
Self {
inner: HttpStreamInner::String(stream, Vec::new()),
}
}
}
impl<'a> From<&'a str> for HttpStream {
fn from(value: &'a str) -> Self {
Self::from(value.to_string())
}
}
impl HttpStream {
#[must_use]
pub fn dummy() -> Self {
Self {
inner: HttpStreamInner::Dummy,
}
}
}