use std::{io, mem::MaybeUninit};
use crate::buf::IoBuf;
pub trait SetLen {
unsafe fn set_len(&mut self, len: usize);
}
pub trait IoBufMut: IoBuf + SetLen {
fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>];
fn reserve(&mut self, additional: usize) -> io::Result<()> {
let initialized = <Self as IoBuf>::as_init(self).len();
let capacity = self.as_uninit().len();
if additional <= capacity.saturating_sub(initialized) {
Ok(())
} else {
Err(io::Error::new(
io::ErrorKind::Unsupported,
"buffer does not support reserving additional capacity",
))
}
}
}
impl<B: SetLen + ?Sized> SetLen for Box<B> {
#[inline]
unsafe fn set_len(&mut self, len: usize) {
unsafe { (**self).set_len(len) }
}
}
impl<B: SetLen + ?Sized> SetLen for &'static mut B {
#[inline]
unsafe fn set_len(&mut self, len: usize) {
unsafe { (**self).set_len(len) }
}
}
impl<B: IoBufMut + ?Sized> IoBufMut for Box<B> {
#[inline]
fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
(**self).as_uninit()
}
#[inline]
fn reserve(&mut self, additional: usize) -> io::Result<()> {
(**self).reserve(additional)
}
}
impl<B: IoBufMut + ?Sized> IoBufMut for &'static mut B {
#[inline]
fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
(**self).as_uninit()
}
#[inline]
fn reserve(&mut self, additional: usize) -> io::Result<()> {
(**self).reserve(additional)
}
}
impl SetLen for Vec<u8> {
#[inline]
unsafe fn set_len(&mut self, len: usize) {
assert!(len <= self.capacity(), "initialized length exceeds buffer capacity");
unsafe { Vec::set_len(self, len) }
}
}
impl IoBufMut for Vec<u8> {
fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
let ptr = self.as_mut_ptr().cast::<MaybeUninit<u8>>();
let capacity = self.capacity();
unsafe { std::slice::from_raw_parts_mut(ptr, capacity) }
}
fn reserve(&mut self, additional: usize) -> io::Result<()> {
self.try_reserve(additional)
.map_err(|error| io::Error::new(io::ErrorKind::OutOfMemory, error))
}
}
impl SetLen for [u8] {
#[inline]
unsafe fn set_len(&mut self, len: usize) {
assert!(len <= self.len(), "initialized length exceeds buffer capacity");
}
}
impl IoBufMut for [u8] {
#[inline]
fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
unsafe { &mut *(self as *mut [u8] as *mut [MaybeUninit<u8>]) }
}
}
impl<const N: usize> SetLen for [u8; N] {
#[inline]
unsafe fn set_len(&mut self, len: usize) {
assert!(len <= N, "initialized length exceeds buffer capacity");
}
}
impl<const N: usize> IoBufMut for [u8; N] {
#[inline]
fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr().cast(), N) }
}
}
#[cfg(feature = "bytes")]
#[cfg_attr(docsrs, doc(cfg(feature = "bytes")))]
impl SetLen for bytes::BytesMut {
#[inline]
unsafe fn set_len(&mut self, len: usize) {
assert!(len <= self.capacity(), "initialized length exceeds buffer capacity");
unsafe { bytes::BytesMut::set_len(self, len) };
}
}
#[cfg(feature = "bytes")]
#[cfg_attr(docsrs, doc(cfg(feature = "bytes")))]
impl IoBufMut for bytes::BytesMut {
fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
let ptr = self.as_mut_ptr().cast::<MaybeUninit<u8>>();
let capacity = self.capacity();
unsafe { std::slice::from_raw_parts_mut(ptr, capacity) }
}
fn reserve(&mut self, additional: usize) -> io::Result<()> {
bytes::BytesMut::reserve(self, additional);
Ok(())
}
}
#[cfg(feature = "memmap2")]
#[cfg_attr(docsrs, doc(cfg(feature = "memmap2")))]
impl SetLen for memmap2::MmapMut {
#[inline]
unsafe fn set_len(&mut self, len: usize) {
assert!(len <= self.len(), "initialized length exceeds buffer capacity");
}
}
#[cfg(feature = "memmap2")]
#[cfg_attr(docsrs, doc(cfg(feature = "memmap2")))]
impl IoBufMut for memmap2::MmapMut {
fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
let bytes: &mut [u8] = self;
unsafe { &mut *(bytes as *mut [u8] as *mut [MaybeUninit<u8>]) }
}
}
#[cfg(all(test, feature = "bytes"))]
mod bytes_tests {
use super::{IoBufMut, SetLen};
use crate::buf::{IoBuf, IoBufExt, IoBufMutExt};
#[test]
fn bytes_mut_as_uninit_covers_full_capacity() {
let mut buf = bytes::BytesMut::with_capacity(16);
buf.extend_from_slice(b"abcd");
assert_eq!(buf.len(), 4);
assert_eq!(buf.as_uninit().len(), 16);
}
#[test]
fn bytes_mut_reserve_grows_spare_capacity() {
let mut buf = bytes::BytesMut::new();
buf.extend_from_slice(b"ab");
IoBufMut::reserve(&mut buf, 32).unwrap();
assert!(buf.capacity().saturating_sub(buf.len()) >= 32);
}
#[test]
fn slice_spare_tail_set_len_preserves_bytes_mut_prefix() {
let mut buf = bytes::BytesMut::new();
buf.extend_from_slice(b"abcd");
IoBufMut::reserve(&mut buf, 8).unwrap();
let start = buf.len();
let mut slice = IoBufExt::slice(buf, start..);
assert_eq!(slice.as_init(), b"");
assert!(slice.buf_capacity() >= 3);
{
let uninit = slice.as_uninit();
assert!(uninit.len() >= 3);
for (index, byte) in b"efg".iter().enumerate() {
uninit[index].write(*byte);
}
}
unsafe { SetLen::set_len(&mut slice, 3) };
let buf = slice.into_inner();
assert_eq!(buf.as_init(), b"abcdefg");
assert_eq!(&buf[..4], b"abcd");
}
}
#[cfg(all(test, feature = "memmap2"))]
mod memmap2_tests {
use super::{IoBufMut, SetLen};
use crate::buf::{IoBuf, IoBufExt, IoBufMutExt};
#[test]
fn mmap_mut_as_uninit_covers_full_mapping() {
let mut buf = memmap2::MmapMut::map_anon(16).unwrap();
buf[..4].copy_from_slice(b"abcd");
assert_eq!(buf.as_init().len(), 16);
assert_eq!(buf.as_uninit().len(), 16);
}
#[test]
fn mmap_mut_uninit_bytes_can_be_written() {
let mut buf = memmap2::MmapMut::map_anon(8).unwrap();
let uninit = buf.as_uninit();
uninit[0].write(b'a');
uninit[1].write(b'b');
assert_eq!(unsafe { uninit[0].assume_init() }, b'a');
assert_eq!(unsafe { uninit[1].assume_init() }, b'b');
}
#[test]
fn mmap_mut_set_len_within_mapping_is_noop() {
let mut buf = memmap2::MmapMut::map_anon(8).unwrap();
buf[..4].copy_from_slice(b"abcd");
unsafe { SetLen::set_len(&mut buf, 8) };
assert_eq!(buf.as_init(), &b"abcd\0\0\0\0"[..]);
}
#[test]
fn mmap_mut_reserve_is_unsupported() {
let mut buf = memmap2::MmapMut::map_anon(8).unwrap();
assert!(IoBufMut::reserve(&mut buf, 1).is_err());
}
#[test]
fn mmap_mut_slice_tail_can_be_read_into() {
let mut buf = memmap2::MmapMut::map_anon(8).unwrap();
buf[..4].copy_from_slice(b"abcd");
let mut slice = IoBufExt::slice(buf, 4..);
assert_eq!(slice.as_init().len(), 4);
assert!(slice.buf_capacity() >= 3);
{
let uninit = slice.as_uninit();
assert!(uninit.len() >= 3);
for (index, byte) in b"efg".iter().enumerate() {
uninit[index].write(*byte);
}
}
assert_eq!(&slice[..3], b"efg");
unsafe { SetLen::set_len(&mut slice, 3) };
let buf = slice.into_inner();
assert_eq!(buf.as_init(), &b"abcdefg\0"[..]);
assert_eq!(&buf[..4], b"abcd");
}
}