use std::alloc::Layout;
use std::ptr::NonNull;
use std::sync::Arc;
use super::pool::PoolInner;
pub(super) struct RawAllocation {
pub(super) ptr: NonNull<u8>,
pub(super) layout: Layout,
}
unsafe impl Send for RawAllocation {}
pub(crate) struct AlignedBuffer {
raw: Option<RawAllocation>,
pool: Arc<PoolInner>,
}
impl AlignedBuffer {
pub(super) fn new(raw: RawAllocation, pool: Arc<PoolInner>) -> Self {
Self {
raw: Some(raw),
pool,
}
}
pub(crate) fn as_slice(&self) -> &[u8] {
let raw = self.raw_ref();
unsafe { std::slice::from_raw_parts(raw.ptr.as_ptr(), raw.layout.size()) }
}
pub(crate) fn as_mut_slice(&mut self) -> &mut [u8] {
let raw = self.raw_ref();
let ptr = raw.ptr.as_ptr();
let len = raw.layout.size();
unsafe { std::slice::from_raw_parts_mut(ptr, len) }
}
pub(crate) fn as_ptr(&self) -> *const u8 {
self.raw_ref().ptr.as_ptr()
}
pub(crate) fn as_mut_ptr(&mut self) -> *mut u8 {
self.raw_ref().ptr.as_ptr()
}
pub(crate) fn len(&self) -> usize {
self.raw_ref().layout.size()
}
pub(crate) fn align(&self) -> usize {
self.raw_ref().layout.align()
}
fn raw_ref(&self) -> &RawAllocation {
match self.raw.as_ref() {
Some(r) => r,
None => unreachable_invariant(),
}
}
}
#[cold]
#[inline(never)]
fn unreachable_invariant() -> ! {
std::process::abort();
}
impl Drop for AlignedBuffer {
fn drop(&mut self) {
if let Some(raw) = self.raw.take() {
self.pool.return_allocation(raw);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::buffer::pool::AlignedBufferPool;
#[test]
fn test_buffer_len_matches_pool_block_size() {
let pool = AlignedBufferPool::new(4, 4096, 512).expect("build pool");
let buf = pool.lease();
assert_eq!(buf.len(), 4096);
}
#[test]
fn test_buffer_align_matches_pool_block_align() {
let pool = AlignedBufferPool::new(4, 4096, 512).expect("build pool");
let buf = pool.lease();
assert_eq!(buf.align(), 512);
assert_eq!((buf.as_ptr() as usize) % 512, 0);
}
#[test]
fn test_buffer_as_slice_zero_initialised() {
let pool = AlignedBufferPool::new(4, 4096, 512).expect("build pool");
let buf = pool.lease();
assert!(buf.as_slice().iter().all(|&b| b == 0));
}
#[test]
fn test_buffer_as_mut_slice_writes_visible() {
let pool = AlignedBufferPool::new(4, 4096, 512).expect("build pool");
let mut buf = pool.lease();
buf.as_mut_slice()[0] = 0xAB;
buf.as_mut_slice()[4095] = 0xCD;
assert_eq!(buf.as_slice()[0], 0xAB);
assert_eq!(buf.as_slice()[4095], 0xCD);
}
}