httplz/crates/httplz-ext/src/lib.rs
2024-10-14 23:49:23 -04:00

117 lines
2.1 KiB
Rust

use std::io::{Read, Result as IOResult};
pub struct NotEnoughSpace;
pub struct Buf<T, U> {
written_len: usize,
data: T,
_dt: core::marker::PhantomData<U>,
}
impl<T, U> Buf<T, U> {
pub fn new(data: T) -> Self {
Self {
data,
written_len: 0,
_dt: Default::default(),
}
}
}
impl<T, U> Buf<T, U>
where
T: AsRef<[U]>,
{
pub fn remaining(&self) -> &[U] {
&self.data.as_ref()[self.written_len..]
}
pub fn filled(&self) -> &[U] {
&self.data.as_ref()[..self.written_len]
}
}
impl<T, U> Buf<T, U>
where
T: AsRef<[U]>,
T: AsMut<[U]>,
{
pub fn remaining_mut(&mut self) -> &mut [U] {
&mut self.data.as_mut()[self.written_len..]
}
pub fn extend_from_slice(&mut self, s: &[U]) -> Result<(), NotEnoughSpace>
where
U: Copy,
{
if self.remaining().len() < s.len() {
return Err(NotEnoughSpace);
}
self.remaining_mut()[..s.len()].copy_from_slice(s);
self.written_len += s.len();
Ok(())
}
pub fn clear(&mut self) {
self.written_len = 0;
}
pub fn pop_front_alloc(&mut self, amt: usize)
where
U: Copy + Default,
{
let to_copy = &self.filled()[amt..];
let buf_sz = to_copy.len();
let mut buf = vec![Default::default(); buf_sz].into_boxed_slice();
buf.copy_from_slice(to_copy);
self.clear();
let _ = self.extend_from_slice(&buf);
}
pub fn pop_front(&mut self, amt: usize)
where
U: Copy,
{
if amt > self.filled().len() {
panic!("Filled not big enough");
}
let data = self.data.as_mut();
let src = &data[amt..];
let count = data.len() - amt;
// SAFETY:
// - src comes from data
// - U is copy
// - count is within bounds of data
unsafe { core::ptr::copy(src.as_ptr(), data.as_mut_ptr(), count) }
self.written_len -= amt;
}
}
impl<T> Buf<T, u8>
where
T: AsRef<[u8]> + AsMut<[u8]>,
{
pub fn read_from(&mut self, mut r: impl Read) -> IOResult<usize> {
let remaining = self.remaining_mut();
let amt = r.read(remaining)?;
self.written_len += amt;
Ok(amt)
}
}
impl<T> httplz::Write for Buf<T, u8>
where
T: AsRef<[u8]> + AsMut<[u8]>,
{
fn write(&mut self, buf: &[u8]) -> httplz::Written {
self.extend_from_slice(buf)
.map_err(|_| httplz::ErrorKind::BufNotBigEnough.into())
}
}