use std::mem::MaybeUninit;
use std::ptr;
use crate::sys;
#[doc(hidden)] pub struct ExtendBuffer<T, const N: usize> {
buf: [MaybeUninit<T>; N],
len: usize,
}
impl<T, const N: usize> Default for ExtendBuffer<T, N> {
fn default() -> Self {
Self {
buf: [const { MaybeUninit::uninit() }; N],
len: 0,
}
}
}
impl<T, const N: usize> ExtendBufferTrait<T> for ExtendBuffer<T, N> {
fn push(&mut self, value: T) {
self.buf[self.len].write(value);
self.len += 1;
}
fn is_full(&self) -> bool {
self.len == N
}
fn drain_as_mut_slice(&mut self) -> &mut [T] {
if N == 0 {
return &mut [];
}
sys::strict_assert!(self.len <= N);
let len = self.len;
self.len = 0;
unsafe { std::slice::from_raw_parts_mut(self.buf[0].as_mut_ptr(), len) }
}
}
impl<T, const N: usize> Drop for ExtendBuffer<T, N> {
fn drop(&mut self) {
if N == 0 {
return;
}
sys::strict_assert!(self.len <= N);
let slice = ptr::slice_from_raw_parts_mut(self.buf[0].as_mut_ptr(), self.len);
unsafe {
ptr::drop_in_place(slice);
}
}
}
#[test]
fn test_extend_buffer_drop() {
use std::rc::Rc;
let mut buf = ExtendBuffer::<Rc<i32>, 1>::default();
let value = Rc::new(42);
buf.push(Rc::clone(&value));
assert_eq!(Rc::strong_count(&value), 2);
let slice = buf.drain_as_mut_slice();
assert_eq!(Rc::strong_count(&value), 2);
unsafe {
ptr::drop_in_place(&mut slice[0]);
}
assert_eq!(Rc::strong_count(&value), 1);
drop(buf);
assert_eq!(Rc::strong_count(&value), 1);
}
#[doc(hidden)] pub trait ExtendBufferTrait<T> {
fn push(&mut self, value: T);
fn is_full(&self) -> bool;
fn drain_as_mut_slice(&mut self) -> &mut [T];
}