use super::{IoBuf, IoBufMut, Slice};
use core::{ops, ptr, slice};
pub trait BoundedBuf: Unpin + 'static {
type Buf: IoBuf;
type Bounds: ops::RangeBounds<usize>;
fn slice(self, range: impl ops::RangeBounds<usize>) -> Slice<Self::Buf>;
fn slice_full(self) -> Slice<Self::Buf>;
fn get_buf(&self) -> &Self::Buf;
fn bounds(&self) -> Self::Bounds;
fn from_buf_bounds(buf: Self::Buf, bounds: Self::Bounds) -> Self;
fn stable_ptr(&self) -> *const u8;
fn bytes_init(&self) -> usize;
fn bytes_total(&self) -> usize;
fn chunk(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.stable_ptr(), self.bytes_init()) }
}
}
impl<T: IoBuf> BoundedBuf for T {
type Buf = Self;
type Bounds = ops::RangeFull;
fn slice(self, range: impl ops::RangeBounds<usize>) -> Slice<Self> {
use ops::Bound;
let begin = match range.start_bound() {
Bound::Included(&n) => n,
Bound::Excluded(&n) => n.checked_add(1).expect("out of range"),
Bound::Unbounded => 0,
};
assert!(begin < self.bytes_total());
let end = match range.end_bound() {
Bound::Included(&n) => n.checked_add(1).expect("out of range"),
Bound::Excluded(&n) => n,
Bound::Unbounded => self.bytes_total(),
};
assert!(end <= self.bytes_total());
assert!(begin <= self.bytes_init());
Slice::new(self, begin, end)
}
fn slice_full(self) -> Slice<Self> {
let end = self.bytes_total();
Slice::new(self, 0, end)
}
fn get_buf(&self) -> &Self {
self
}
fn bounds(&self) -> Self::Bounds {
..
}
fn from_buf_bounds(buf: Self, _: ops::RangeFull) -> Self {
buf
}
fn stable_ptr(&self) -> *const u8 {
IoBuf::stable_ptr(self)
}
fn bytes_init(&self) -> usize {
IoBuf::bytes_init(self)
}
fn bytes_total(&self) -> usize {
IoBuf::bytes_total(self)
}
}
pub trait BoundedBufMut: BoundedBuf<Buf = Self::BufMut> {
type BufMut: IoBufMut;
fn stable_mut_ptr(&mut self) -> *mut u8;
unsafe fn set_init(&mut self, pos: usize);
fn put_slice(&mut self, src: &[u8]) {
let init = self.bytes_init();
assert!(self.bytes_total() - init >= src.len());
unsafe {
let dst = self.stable_mut_ptr().add(init);
ptr::copy_nonoverlapping(src.as_ptr(), dst, src.len());
self.set_init(init + src.len());
}
}
}
impl<T: IoBufMut> BoundedBufMut for T {
type BufMut = T;
fn stable_mut_ptr(&mut self) -> *mut u8 {
IoBufMut::stable_mut_ptr(self)
}
unsafe fn set_init(&mut self, pos: usize) {
unsafe { IoBufMut::set_init(self, pos) }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn put_slice_appends() {
let mut buf = Vec::with_capacity(64);
buf.put_slice(b"hello");
assert_eq!(&buf, b"hello");
buf.put_slice(b" world");
assert_eq!(&buf, b"hello world");
}
#[test]
fn put_slice_empty() {
let mut buf = Vec::with_capacity(16);
buf.put_slice(b"");
assert!(buf.is_empty());
buf.put_slice(b"abc");
assert_eq!(&buf, b"abc");
buf.put_slice(b"");
assert_eq!(&buf, b"abc");
}
#[test]
fn put_slice_fills_capacity() {
let mut buf = Vec::with_capacity(5);
buf.put_slice(b"ab");
buf.put_slice(b"cde");
assert_eq!(&buf, b"abcde");
assert_eq!(buf.len(), 5);
}
#[test]
#[should_panic]
fn put_slice_exceeds_capacity() {
let mut buf = Vec::with_capacity(4);
buf.put_slice(b"abcde");
}
#[test]
fn chunk_returns_initialized() {
let buf = b"hello".to_vec();
assert_eq!(buf.chunk(), b"hello");
}
#[test]
fn chunk_empty() {
let buf = Vec::<u8>::with_capacity(16);
assert_eq!(buf.chunk(), b"");
}
#[test]
fn chunk_after_put_slice() {
let mut buf = Vec::with_capacity(32);
buf.put_slice(b"foo");
buf.put_slice(b"bar");
assert_eq!(buf.chunk(), b"foobar");
}
}