use std::{fmt::{self, Debug, Formatter, Pointer}, marker::PhantomData, mem::forget, ptr::NonNull};
use crate::{inner::AllocUninit, InnerHeader, Src, SrcSlice, SrcTarget, UniqueSrc, WeakSrc};
pub struct UninitSrc<T: SrcTarget + ?Sized> {
pub(crate) header: NonNull<InnerHeader>,
pub(crate) len: T::Len,
pub(crate) _phantom: PhantomData<*const T>,
}
impl<T: SrcTarget + ?Sized> UninitSrc<T> {
fn header(&self) -> &InnerHeader {
unsafe { InnerHeader::get_header(self.header) }
}
pub fn downgrade(&self) -> WeakSrc<T> {
self.header().inc_weak_count();
let start = unsafe { InnerHeader::get_body_ptr::<T::Item>(self.header) };
WeakSrc {
header: self.header,
start,
len: self.len,
_phantom: PhantomData,
}
}
}
impl<T: SrcSlice + ?Sized> UninitSrc<T> {
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
}
impl<T: Sized> UninitSrc<T> {
#[inline]
pub fn single() -> UninitSrc<T> {
let this = UninitSrc::<[T]>::new(1);
debug_assert_eq!(this.len, 1);
let this2 = UninitSrc {
header: this.header,
len: (),
_phantom: PhantomData,
};
forget(this);
this2
}
#[inline]
pub fn init(self, value: T) -> Src<T> {
UniqueSrc::into_shared(self.init_unique(value))
}
pub fn init_unique(self, value: T) -> UniqueSrc<T> {
let start = unsafe { InnerHeader::get_body_ptr::<T>(self.header) };
unsafe { start.write(value); }
let this = UniqueSrc {
header: self.header,
start,
len: self.len,
_phantom: PhantomData,
};
forget(self); this
}
#[inline]
pub fn as_slice(self) -> UninitSrc<[T]> {
let this = UninitSrc {
header: self.header,
len: 1,
_phantom: PhantomData,
};
forget(self); this
}
}
impl<T> UninitSrc<[T]> {
#[inline]
pub fn new(len: usize) -> UninitSrc<[T]> {
let header = InnerHeader::new_inner::<T, AllocUninit>(len);
Self {
header,
len,
_phantom: PhantomData,
}
}
#[inline]
pub fn init_from_fn<F: FnMut(usize) -> T>(self, f: F) -> Src<[T]> {
UniqueSrc::into_shared(self.init_unique_from_fn(f))
}
pub fn init_unique_from_fn<F: FnMut(usize) -> T>(self, mut f: F) -> UniqueSrc<[T]> {
let header = self.header();
let start = unsafe { InnerHeader::get_body_ptr::<T>(self.header) };
let mut guard = PartialInitGuard::<T> { header: self.header, initialized: 0, _phantom: PhantomData };
for i in 0..header.len() {
let ptr = unsafe { InnerHeader::get_elem_ptr::<T>(self.header, i) };
let val = f(i);
unsafe { ptr.write(val) };
guard.initialized += 1;
}
forget(guard);
let this = UniqueSrc {
header: self.header,
start,
len: self.len,
_phantom: PhantomData,
};
forget(self); this
}
#[inline]
pub fn init_from_default(self) -> Src<[T]> where T: Default {
self.init_from_fn(|_| T::default())
}
#[inline]
pub fn init_unique_from_default(self) -> UniqueSrc<[T]> where T: Default {
self.init_unique_from_fn(|_| T::default())
}
#[inline]
pub fn init_filled(self, value: &T) -> Src<[T]> where T: Clone {
self.init_from_fn(|_| value.clone())
}
#[inline]
pub fn init_unique_filled(self, value: &T) -> UniqueSrc<[T]> where T: Clone {
self.init_unique_from_fn(|_| value.clone())
}
}
impl<T: SrcTarget + ?Sized> Debug for UninitSrc<T> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "(UninitSrc)")
}
}
impl<T: SrcTarget + ?Sized> Pointer for UninitSrc<T> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let start = unsafe { InnerHeader::get_body_ptr::<T::Item>(self.header) };
Pointer::fmt(&start, f)
}
}
impl<T: SrcTarget + ?Sized> Drop for UninitSrc<T> {
fn drop(&mut self) {
unsafe { InnerHeader::drop_weak::<T::Item>(self.header); }
}
}
struct PartialInitGuard<T> {
header: NonNull<InnerHeader>,
initialized: usize,
_phantom: PhantomData<*const T>,
}
impl<T> Drop for PartialInitGuard<T> {
fn drop(&mut self) {
unsafe { InnerHeader::drop_body_up_to::<T>(self.header, self.initialized); }
}
}
#[cfg(test)]
mod tests {
use std::{cell::Cell, ops::Deref, panic::{catch_unwind, AssertUnwindSafe}};
use crate::*;
#[test]
fn downgrade() {
let u: UninitSrc<[u8]> = UninitSrc::new(3);
let w: WeakSrc<[u8]> = u.downgrade();
assert!(w.upgrade().is_none());
let s1: Src<[u8]> = u.init_from_default();
let s2: Src<[u8]> = w.upgrade().unwrap();
assert_eq!(s1, s2);
assert!(Src::ptr_eq(&s1, &s2));
}
#[test]
fn len() {
let u: UninitSrc<[u8]> = UninitSrc::new(0);
assert_eq!(u.len(), 0);
let u: UninitSrc<[u8]> = UninitSrc::new(1);
assert_eq!(u.len(), 1);
let u: UninitSrc<[u8]> = UninitSrc::new(17);
assert_eq!(u.len(), 17);
}
#[test]
fn is_empty() {
let u: UninitSrc<[u8]> = UninitSrc::new(0);
assert!(u.is_empty());
let u: UninitSrc<[u8]> = UninitSrc::new(1);
assert!(!u.is_empty());
let u: UninitSrc<[u8]> = UninitSrc::new(17);
assert!(!u.is_empty());
}
#[test]
fn single() {
let u: UninitSrc<u8> = UninitSrc::single();
let s: Src<u8> = u.init(42);
assert!(Src::is_root(&s));
let s: Src<[u8]> = Src::as_slice(&s);
assert_eq!(s.len(), 1);
}
#[test]
fn init() {
let u: UninitSrc<u8> = UninitSrc::single();
let s: Src<u8> = u.init(42);
assert_eq!(*s, 42);
}
#[test]
fn init_unique() {
let u: UninitSrc<u8> = UninitSrc::single();
let u: UniqueSrc<u8> = u.init_unique(42);
assert_eq!(*u, 42);
}
#[test]
fn as_slice() {
let u: UninitSrc<u8> = UninitSrc::single();
let u: UninitSrc<[u8]> = u.as_slice();
assert_eq!(u.len(), 1);
}
#[test]
fn new() {
let u: UninitSrc<[u8]> = UninitSrc::new(3);
let s: Src<[u8]> = u.init_from_fn(|i| i as _);
assert!(Src::is_root(&s));
assert_eq!(s.len(), 3);
}
#[test]
fn init_from_fn() {
{ let u: UninitSrc<[u8]> = UninitSrc::new(3);
let s: Src<[u8]> = u.init_from_fn(|i| i as _);
assert_eq!(*s, [0, 1, 2]);
}
{ let drop_flags: [_; 6] = std::array::from_fn(|_| AssertUnwindSafe(Cell::new(false)));
struct DropFlagger<'a>(&'a Cell<bool>);
impl Drop for DropFlagger<'_> {
fn drop(&mut self) {
self.0.update(|v| !v)
}
}
let _: Result<_, _> = catch_unwind(|| {
let u: UninitSrc<[DropFlagger<'_>]> = UninitSrc::new(drop_flags.len());
let _: Src<[DropFlagger<'_>]> = u.init_from_fn(|i| {
if i >= 3 { panic!() }
DropFlagger(&drop_flags[i])
});
});
assert!(drop_flags[..3].iter().map(Deref::deref).all(Cell::get));
assert!(!drop_flags[3..].iter().map(Deref::deref).any(Cell::get));
}
}
#[test]
fn init_unique_from_fn() {
{ let u: UninitSrc<[u8]> = UninitSrc::new(3);
let u: UniqueSrc<[u8]> = u.init_unique_from_fn(|i| i as _);
assert_eq!(*u, [0, 1, 2]);
}
{ let drop_flags: [_; 6] = std::array::from_fn(|_| AssertUnwindSafe(Cell::new(false)));
struct DropFlagger<'a>(&'a Cell<bool>);
impl Drop for DropFlagger<'_> {
fn drop(&mut self) {
self.0.update(|v| !v)
}
}
let _: Result<_, _> = catch_unwind(|| {
let u: UninitSrc<[DropFlagger<'_>]> = UninitSrc::new(drop_flags.len());
let _: UniqueSrc<[DropFlagger<'_>]> = u.init_unique_from_fn(|i| {
if i >= 3 { panic!() }
DropFlagger(&drop_flags[i])
});
});
assert!(drop_flags[..3].iter().map(Deref::deref).all(Cell::get));
assert!(!drop_flags[3..].iter().map(Deref::deref).any(Cell::get));
}
}
#[test]
fn init_from_default() {
let u: UninitSrc<[u8]> = UninitSrc::new(3);
let s: Src<[u8]> = u.init_from_default();
assert_eq!(*s, [0, 0, 0]);
}
#[test]
fn init_unique_from_default() {
let u: UninitSrc<[u8]> = UninitSrc::new(3);
let u: UniqueSrc<[u8]> = u.init_unique_from_default();
assert_eq!(*u, [0, 0, 0]);
}
#[test]
fn init_filled() {
let u: UninitSrc<[u8]> = UninitSrc::new(3);
let s: Src<[u8]> = u.init_filled(&42);
assert_eq!(*s, [42, 42, 42]);
}
#[test]
fn init_unique_filled() {
let u: UninitSrc<[u8]> = UninitSrc::new(3);
let u: UniqueSrc<[u8]> = u.init_unique_filled(&42);
assert_eq!(*u, [42, 42, 42]);
}
#[test]
fn drop() {
let u: UninitSrc<[u8]> = UninitSrc::new(3);
let w: WeakSrc<[u8]> = u.downgrade();
assert!(w.upgrade().is_none());
std::mem::drop(u);
assert!(w.upgrade().is_none());
}
}