use std::fmt;
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
use std::slice;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use crate::size_class::{zero_buffer, BufferAllocation, SizeClassPool};
use crate::stats::PoolStats;
use crate::tls::store_tls_buffer;
pub struct FrozenBuffer {
ptr: NonNull<u8>,
len: usize,
capacity: usize,
owner: Arc<SizeClassPool>,
stats: Option<Arc<PoolStats>>,
}
unsafe impl Send for FrozenBuffer {}
unsafe impl Sync for FrozenBuffer {}
impl Deref for FrozenBuffer {
type Target = [u8];
fn deref(&self) -> &Self::Target {
unsafe { slice::from_raw_parts(self.ptr.as_ptr().cast_const(), self.len) }
}
}
impl AsRef<[u8]> for FrozenBuffer {
fn as_ref(&self) -> &[u8] {
self
}
}
impl Drop for FrozenBuffer {
fn drop(&mut self) {
if let Some(stats) = &self.stats {
stats.checked_out.fetch_sub(1, Ordering::Relaxed);
stats
.bytes_checked_out
.fetch_sub(self.len, Ordering::Relaxed);
}
zero_buffer(self.ptr, self.capacity);
let allocation = BufferAllocation { ptr: self.ptr };
self.owner.recycle_or_free(allocation);
}
}
pub struct PoolBuffer {
pub(crate) ptr: NonNull<u8>,
pub(crate) len: usize,
pub(crate) capacity: usize,
pub(crate) owner: Arc<SizeClassPool>,
pub(crate) stats: Option<Arc<PoolStats>>,
}
unsafe impl Send for PoolBuffer {}
unsafe impl Sync for PoolBuffer {}
impl PoolBuffer {
#[must_use]
pub fn freeze(self) -> FrozenBuffer {
let this = std::mem::ManuallyDrop::new(self);
FrozenBuffer {
ptr: this.ptr,
len: this.len,
capacity: this.capacity,
owner: unsafe { std::ptr::read(&raw const this.owner) },
stats: unsafe { std::ptr::read(&raw const this.stats) },
}
}
#[must_use]
pub fn len(&self) -> usize {
self.len
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[must_use]
pub fn capacity(&self) -> usize {
self.capacity
}
#[must_use]
pub fn as_ptr(&self) -> *const u8 {
self.ptr.as_ptr().cast_const()
}
#[must_use]
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.ptr.as_ptr()
}
}
impl AsRef<[u8]> for PoolBuffer {
fn as_ref(&self) -> &[u8] {
self
}
}
impl AsMut<[u8]> for PoolBuffer {
fn as_mut(&mut self) -> &mut [u8] {
self
}
}
impl Deref for PoolBuffer {
type Target = [u8];
fn deref(&self) -> &Self::Target {
unsafe { slice::from_raw_parts(self.ptr.as_ptr().cast_const(), self.len) }
}
}
impl DerefMut for PoolBuffer {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
}
}
impl fmt::Debug for PoolBuffer {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("PoolBuffer")
.field("len", &self.len)
.field("capacity", &self.capacity)
.finish_non_exhaustive()
}
}
impl Drop for PoolBuffer {
fn drop(&mut self) {
if let Some(stats) = &self.stats {
stats.checked_out.fetch_sub(1, Ordering::Relaxed);
stats
.bytes_checked_out
.fetch_sub(self.len, Ordering::Relaxed);
}
zero_buffer(self.ptr, self.capacity);
if !store_tls_buffer(self.capacity, self.ptr, Arc::clone(&self.owner)) {
let allocation = BufferAllocation { ptr: self.ptr };
self.owner.recycle_or_free(allocation);
}
}
}