use core::mem::MaybeUninit;
use core::ptr::NonNull;
use std::alloc::{self, Layout};
use std::io;
use super::owned::{IoBuf, IoBufMut};
pub struct AlignedBuf {
ptr: NonNull<u8>,
len: usize,
layout: Layout,
}
unsafe impl Send for AlignedBuf {}
unsafe impl Sync for AlignedBuf {}
impl AlignedBuf {
pub fn new(capacity: usize, align: usize) -> io::Result<Self> {
Self::alloc(capacity, align, false)
}
pub fn zeroed(len: usize, align: usize) -> io::Result<Self> {
let mut buf = Self::alloc(len, align, true)?;
buf.len = len;
Ok(buf)
}
fn alloc(capacity: usize, align: usize, zeroed: bool) -> io::Result<Self> {
if !align.is_power_of_two() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"the alignment is not a power of two",
));
}
let layout = Layout::from_size_align(capacity, align).map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidInput,
"the buffer is larger than memory can hold",
)
})?;
if capacity == 0 {
return Ok(Self {
ptr: NonNull::new(core::ptr::without_provenance_mut(align))
.unwrap_or(NonNull::dangling()),
len: 0,
layout,
});
}
let raw = unsafe {
if zeroed {
alloc::alloc_zeroed(layout)
} else {
alloc::alloc(layout)
}
};
let ptr = NonNull::new(raw).ok_or_else(|| {
io::Error::new(
io::ErrorKind::OutOfMemory,
"the allocator has no memory for the buffer",
)
})?;
Ok(Self {
ptr,
len: 0,
layout,
})
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn capacity(&self) -> usize {
self.layout.size()
}
pub fn alignment(&self) -> usize {
self.layout.align()
}
pub fn as_ptr(&self) -> *const u8 {
self.ptr.as_ptr()
}
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.ptr.as_ptr()
}
pub fn clear(&mut self) {
self.len = 0;
}
pub fn truncate(&mut self, len: usize) {
self.len = self.len.min(len);
}
pub fn extend_from_slice(&mut self, bytes: &[u8]) -> usize {
let n = bytes.len().min(self.capacity() - self.len);
unsafe {
core::ptr::copy_nonoverlapping(bytes.as_ptr(), self.ptr.as_ptr().add(self.len), n);
}
self.len += n;
n
}
pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<u8>] {
unsafe {
core::slice::from_raw_parts_mut(
self.ptr.as_ptr().add(self.len).cast::<MaybeUninit<u8>>(),
self.capacity() - self.len,
)
}
}
pub unsafe fn set_len(&mut self, len: usize) {
self.len = len;
}
}
impl Default for AlignedBuf {
fn default() -> Self {
Self {
ptr: NonNull::dangling(),
len: 0,
layout: Layout::new::<()>(),
}
}
}
impl Drop for AlignedBuf {
fn drop(&mut self) {
if self.layout.size() != 0 {
unsafe { alloc::dealloc(self.ptr.as_ptr(), self.layout) };
}
}
}
impl core::ops::Deref for AlignedBuf {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
}
}
impl core::ops::DerefMut for AlignedBuf {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
}
}
impl core::fmt::Debug for AlignedBuf {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("AlignedBuf")
.field("len", &self.len)
.field("capacity", &self.capacity())
.field("alignment", &self.alignment())
.finish()
}
}
unsafe impl IoBuf for AlignedBuf {
fn stable_ptr(&self) -> *const u8 {
self.as_ptr()
}
fn bytes_init(&self) -> usize {
self.len
}
fn bytes_total(&self) -> usize {
self.capacity()
}
}
unsafe impl IoBufMut for AlignedBuf {
fn stable_mut_ptr(&mut self) -> *mut u8 {
self.as_mut_ptr()
}
unsafe fn set_init(&mut self, pos: usize) {
self.len = pos;
}
}