You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
collect/src/buffers.rs

399 lines
8.7 KiB

//! Buffers and helpers
use super::*;
use std::num::NonZeroUsize;
#[cfg(feature="bytes")]
/// Default mutable buffer
#[allow(dead_code)]
pub type DefaultMut = bytes::BytesMut;
#[cfg(not(feature="bytes"))]
/// Default mutable buffer
#[allow(dead_code)]
pub type DefaultMut = Vec<u8>;
/// Default immutable buffer
#[allow(dead_code)]
pub type Default = <DefaultMut as MutBuffer>::Frozen;
/// Reader from a mutable reference of a `Buffer`.
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct BufferReader<'a, B: ?Sized>(&'a mut B, usize);
/// Writer to a mutable reference of a `MutBuffer`.
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct BufferWriter<'a, B: ?Sized>(&'a mut B, usize);
#[allow(dead_code)]
const _: () = {
impl<'a, B: ?Sized + Buffer> BufferReader<'a, B>
{
#[inline(always)]
pub fn get(&self) -> &B
{
&self.0
}
#[inline(always)]
pub fn get_mut(&mut self) -> &B
{
&mut self.0
}
#[inline(always)]
pub fn amount_read(&self) -> usize
{
self.1
}
}
impl<'a, 'b: 'a, B: Buffer + 'b> BufferReader<'a, B>
{
#[inline]
pub fn unsize(self) -> BufferReader<'a, (dyn Buffer + 'b)>
{
BufferReader(self.0, self.1)
}
}
impl<'a, B: ?Sized + Buffer> BufferWriter<'a, B>
{
#[inline(always)]
pub fn get(&self) -> &B
{
&self.0
}
#[inline(always)]
pub fn get_mut(&mut self) -> &B
{
&mut self.0
}
#[inline(always)]
pub fn amount_written(&self) -> usize
{
self.1
}
}
impl<'a, 'b: 'a, B: Buffer + 'b> BufferWriter<'a, B>
{
#[inline]
pub fn unsize(self) -> BufferWriter<'a, (dyn Buffer + 'b)>
{
BufferWriter(self.0, self.1)
}
}
};
impl<'a, B: ?Sized + Buffer> io::Read for BufferReader<'a, B>
{
#[inline]
#[instrument(level="trace", skip_all, fields(buf = ?buf.len()))]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let adv = self.0.copy_to_slice(self.1, buf);
self.1 += adv;
Ok(adv)
}
}
impl<'a, B: ?Sized + MutBuffer> io::Write for BufferWriter<'a, B>
{
#[inline]
#[instrument(level="trace", skip_all, fields(buf = ?buf.len()))]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let adv = self.0.copy_from_slice(self.1, buf);
self.1 += adv;
Ok(adv)
}
#[inline(always)]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
/// An immutable contiguous buffer
pub trait Buffer: AsRef<[u8]>
{
#[inline]
#[instrument(level="trace", skip_all, fields(buf = ?slice.len()))]
fn copy_to_slice(&self, st: usize, slice: &mut [u8]) -> usize
{
let by = self.as_ref();
if st >= by.len() {
return 0;
}
let by = &by[st..];
let len = std::cmp::min(by.len(), slice.len());
// SAFETY: We know `self`'s AsRef impl cannot overlap with `slice`, since `slice` is a mutable reference.
if len > 0 {
unsafe {
std::ptr::copy_nonoverlapping(by.as_ptr(), slice.as_mut_ptr(), len)
}
}
len
}
}
pub trait BufferExt: Buffer
{
#[inline(always)]
fn reader_from(&mut self, st: usize) -> BufferReader<'_, Self>
{
BufferReader(self, st)
}
#[inline]
fn reader(&mut self) -> BufferReader<'_, Self>
{
self.reader_from(0)
}
}
impl<B: Buffer> BufferExt for B{}
impl<T: ?Sized> Buffer for T
where T: AsRef<[u8]>
{}
/// A mutable contiguous buffer
pub trait MutBuffer: AsMut<[u8]>
{
type Frozen: Sized + Buffer;
/// Make immutable
fn freeze(self) -> Self::Frozen;
#[inline]
#[instrument(level="debug", skip_all, fields(st, buflen = ?slice.len()))]
fn copy_from_slice(&mut self, st: usize, slice: &[u8]) -> usize
{
let by = self.as_mut();
dbg!(&by);
if st >= by.len() {
return 0;
}
dbg!(st);
let by = &mut by[st..];
let len = std::cmp::min(by.len(), slice.len());
if len > 0 {
// SAFETY: We know `self`'s AsRef impl cannot overlap with `slice`, since `slice` is a mutable reference.
unsafe {
std::ptr::copy_nonoverlapping(slice.as_ptr(), by.as_mut_ptr(), len);
}
}
len
}
}
pub trait MutBufferExt: MutBuffer
{
#[inline(always)]
#[instrument(level="info", skip(self))]
fn writer_from(&mut self, st: usize) -> BufferWriter<'_, Self>
{
debug!("creating writer at start {st}");
BufferWriter(self, st)
}
#[inline]
//#[instrument(level="info", skip(self))]
fn writer(&mut self) -> BufferWriter<'_, Self>
{
self.writer_from(0)
}
}
impl<B: ?Sized + MutBuffer> MutBufferExt for B{}
#[cfg(feature="bytes")]
impl MutBuffer for bytes::BytesMut
{
type Frozen = bytes::Bytes;
#[inline(always)]
#[instrument(level="trace")]
fn freeze(self) -> Self::Frozen {
bytes::BytesMut::freeze(self)
}
//TODO: XXX: Impl copy_from_slice() as is done in impl for Vec<u8>
/*#[instrument]
fn copy_from_slice(&mut self, st: usize, buf: &[u8]) -> usize
{
//TODO: Special case for `st == 0` maybe? No slicing of the BytesMut might increase perf? Idk.
if (st + buf.len()) <= self.len() {
// We can put `buf` in st..buf.len()
self[st..].copy_from_slice(buf);
} else if st <= self.len() {
// The start is lower but the end is not
let rem = self.len() - st;
self[st..].copy_from_slice(&buf[..rem]);
self.extend_from_slice(&buf[rem..]);
} else {
// it is past the end, extend.
self.extend_from_slice(buf);
}
buf.len()
}*/
}
impl MutBuffer for Vec<u8>
{
type Frozen = Box<[u8]>;
#[inline]
#[instrument(level="trace")]
fn freeze(self) -> Self::Frozen {
self.into_boxed_slice()
}
#[instrument(level="trace", skip_all, fields(st, buflen = ?buf.len()))]
fn copy_from_slice(&mut self, st: usize, buf: &[u8]) -> usize
{
if (st + buf.len()) <= self.len() {
// We can put `buf` in st..buf.len()
self[st..].copy_from_slice(buf);
} else if st <= self.len() {
// The start is lower but the end is not
let rem = self.len() - st;
self[st..].copy_from_slice(&buf[..rem]);
self.extend_from_slice(&buf[rem..]);
} else {
// it is past the end, extend.
self.extend_from_slice(buf);
}
buf.len()
}
}
/// A trait for buffers that can be allocated with a capacity
pub trait WithCapacity: Sized
{
fn wc_new() -> Self;
fn wc_with_capacity(_: usize) -> Self;
}
impl WithCapacity for Box<[u8]>
{
#[inline(always)]
#[instrument(level="info", fields(cap = "(unbound)"))]
fn wc_new() -> Self {
info!("creating new boxed slice with size 0");
Vec::wc_new().into_boxed_slice()
}
#[inline(always)]
#[instrument(level="info")]
fn wc_with_capacity(cap: usize) -> Self {
info!("creating new boxed slice with size {cap}");
Vec::wc_with_capacity(cap).into_boxed_slice()
}
}
pub trait WithCapExt: WithCapacity
{
fn maybe_with_capacity(maybe: Option<NonZeroUsize>) -> Self;
#[inline(always)]
fn try_with_capacity(cap: usize) -> Self
{
Self::maybe_with_capacity(NonZeroUsize::new(cap))
}
}
/// A type that can be used as a size for creating a `WithCapacity` buffer
pub trait TryCreateBuffer
{
fn create_buffer<T: WithCapacity>(&self) -> T;
}
impl TryCreateBuffer for Option<NonZeroUsize>
{
#[inline(always)]
fn create_buffer<T: WithCapacity>(&self) -> T {
T::maybe_with_capacity(*self)
}
}
impl TryCreateBuffer for usize
{
#[inline(always)]
fn create_buffer<T: WithCapacity>(&self) -> T {
T::try_with_capacity(*self)
}
}
impl<T: WithCapacity> WithCapExt for T
{
#[inline]
fn maybe_with_capacity(maybe: Option<NonZeroUsize>) -> Self {
match maybe {
Some(sz) => Self::wc_with_capacity(sz.into()),
None => Self::wc_new()
}
}
}
/// Implement `WithCapacity` for a type that supports it.
macro_rules! cap_buffer {
($name:ty) => {
impl $crate::buffers::WithCapacity for $name
{
#[inline(always)]
#[instrument(level="info", fields(cap = "(unbound)"))]
fn wc_new() -> Self
{
info!("creating {} with no cap", std::any::type_name::<Self>());
Self::new()
}
#[inline(always)]
#[instrument(level="info")]
fn wc_with_capacity(cap: usize) -> Self
{
info!("creating {} with {cap}", std::any::type_name::<Self>());
Self::with_capacity(cap)
}
}
};
}
pub mod prelude
{
/// Export these items anonymously.
macro_rules! export_anon {
($($name:ident),+ $(,)?) => {
$(
pub use super::$name as _;
)*
};
}
// Causes conflicts for `.writer()`, so remove them from prelude.
#[cfg(feature="bytes")]
export_anon!{
WithCapExt,
//BufferExt,
//MutBufferExt,
WithCapExt,
}
#[cfg(not(feature="bytes"))]
export_anon!{
WithCapExt,
BufferExt,
MutBufferExt,
WithCapExt,
}
pub use super::{
WithCapacity,
TryCreateBuffer,
MutBuffer,
Buffer,
};
}
pub(crate) use cap_buffer;
// cap_buffer impls
#[cfg(feature="bytes")] buffers::cap_buffer!(bytes::BytesMut);
cap_buffer!(Vec<u8>);