use crate::loom::atomic::Ordering; use crate::{Core, Full, Ref, Slot}; use alloc::boxed::Box; use core::{fmt, ptr}; #[cfg(all(loom, test))] mod tests; #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] pub struct ThingBuf { pub(crate) core: Core, pub(crate) slots: Box<[Slot]>, } // === impl ThingBuf === impl ThingBuf { pub fn new(capacity: usize) -> Self { assert!(capacity > 0); Self { core: Core::new(capacity), slots: Slot::make_boxed_array(capacity), } } pub fn push_ref(&self) -> Result, Full> { self.core.push_ref(&*self.slots).map_err(|e| match e { crate::mpsc::TrySendError::Full(()) => Full(()), _ => unreachable!(), }) } #[inline] pub fn push_with(&self, f: impl FnOnce(&mut T) -> U) -> Result { self.push_ref().map(|mut r| r.with_mut(f)) } pub fn pop_ref(&self) -> Option> { self.core.pop_ref(&*self.slots).ok() } #[inline] pub fn pop_with(&self, f: impl FnOnce(&mut T) -> U) -> Option { self.pop_ref().map(|mut r| r.with_mut(f)) } } impl ThingBuf { #[inline] pub fn capacity(&self) -> usize { self.slots.len() } #[inline] pub fn len(&self) -> usize { self.core.len() } #[inline] pub fn is_empty(&self) -> bool { self.len() == 0 } } impl Drop for ThingBuf { fn drop(&mut self) { let tail = self.core.tail.load(Ordering::SeqCst); let (idx, gen) = self.core.idx_gen(tail); let num_initialized = if gen > 0 { self.capacity() } else { idx }; for slot in &self.slots[..num_initialized] { unsafe { slot.value .with_mut(|value| ptr::drop_in_place((*value).as_mut_ptr())); } } } } impl fmt::Debug for ThingBuf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ThingBuf") .field("len", &self.len()) .field("slots", &format_args!("[...]")) .field("core", &self.core) .finish() } }