use std::{fmt::{self, Debug, Formatter, Pointer}, marker::PhantomData, mem::forget, num::NonZero, ops::Bound, ptr::NonNull};
use crate::{inner::InnerHeader, Src, SrcSlice, SrcTarget, WeakSrcIndex};
const fn non_null_max<T>() -> NonNull<T> {
NonNull::without_provenance(NonZero::<usize>::MAX)
}
pub struct WeakSrc<T: SrcTarget + ?Sized> {
pub(crate) header: NonNull<InnerHeader>,
pub(crate) start: NonNull<T::Item>,
pub(crate) len: T::Len,
pub(crate) _phantom: PhantomData<*const T>,
}
impl<T: SrcTarget + ?Sized> WeakSrc<T> {
unsafe fn header(&self) -> &InnerHeader {
unsafe { InnerHeader::get_header(self.header) }
}
#[inline]
pub fn dangling() -> WeakSrc<T> {
WeakSrc {
header: non_null_max(),
start: non_null_max(),
len: T::Len::default(),
_phantom: PhantomData,
}
}
#[inline]
pub fn is_dangling(&self) -> bool {
self.header == non_null_max()
}
pub fn upgrade(&self) -> Option<Src<T>> {
if self.is_dangling() {
return None
}
let header = unsafe { self.header() };
if header.strong_count() == 0 {
return None
}
header.inc_strong_count();
Some(Src {
header: self.header,
start: self.start,
len: self.len,
_phantom: PhantomData,
})
}
#[inline]
pub fn ptr_eq<U: SrcTarget<Item = T::Item> + ?Sized>(&self, other: &WeakSrc<U>) -> bool {
self.start == other.start
}
#[inline]
pub fn same_root<U: SrcTarget<Item = T::Item> + ?Sized>(&self, other: &WeakSrc<U>) -> bool {
self.header == other.header
}
#[inline]
pub fn is_root(&self) -> bool {
if self.is_dangling() {
return true
}
let header = unsafe { self.header() };
let root_start = unsafe { InnerHeader::get_body_ptr(self.header) };
self.start == root_start && T::len_as_usize(self.len) == header.len()
}
pub fn strong_count(&self) -> usize {
if !self.is_dangling() {
unsafe { self.header() }.strong_count()
} else {
0
}
}
pub fn weak_count(&self) -> usize {
if !self.is_dangling() {
let header = unsafe { self.header() };
if header.strong_count() > 0 {
header.weak_count() - 1 } else {
0
}
} else {
0
}
}
pub fn root(&self) -> WeakSrc<[T::Item]> {
if self.is_dangling() {
return WeakSrc::dangling()
}
let header = unsafe { self.header() };
let start = unsafe { InnerHeader::get_body_ptr(self.header) };
header.inc_weak_count();
WeakSrc {
header: self.header,
start,
len: header.len(),
_phantom: PhantomData,
}
}
}
impl<T: SrcSlice + ?Sized> WeakSrc<T> {
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
}
impl<T: Sized> WeakSrc<T> {
#[inline]
pub fn as_slice(&self) -> WeakSrc<[T]> {
if !self.is_dangling() {
unsafe { self.header() }.inc_weak_count();
}
WeakSrc {
header: self.header,
start: self.start,
len: 1,
_phantom: PhantomData,
}
}
}
impl<T> WeakSrc<[T]> {
#[inline]
pub fn slice<I: WeakSrcIndex<[T]>>(&self, index: I) -> WeakSrc<I::Output> {
index.get_weak(self.clone())
}
pub(crate) fn into_item(self, index: usize) -> WeakSrc<T> {
let len = if self.is_dangling() {
0
} else {
let header = unsafe { self.header() };
header.len()
};
assert!(index < len, "index {index} out of range for slice of length {}", len);
let start_ptr = unsafe { self.start.add(index) };
let this = WeakSrc {
header: self.header,
start: start_ptr,
len: (),
_phantom: PhantomData,
};
forget(self); this
}
pub(crate) fn into_slice_from_bounds(self, start: Bound<usize>, end: Bound<usize>) -> WeakSrc<[T]> {
let len = if self.is_dangling() {
0
} else {
let header = unsafe { self.header() };
header.len()
};
let start_inc = match start {
Bound::Excluded(val) => val + 1,
Bound::Included(val) => val,
Bound::Unbounded => 0,
};
let end_exc = match end {
Bound::Excluded(val) => val,
Bound::Included(val) => val + 1,
Bound::Unbounded => len,
};
assert!(start_inc <= end_exc, "slice index starts at {start_inc} but ends at {end_exc}");
assert!(end_exc <= len, "range end index {end_exc} out of range for slice of length {}", len);
let len = end_exc - start_inc;
let start_ptr = unsafe { self.start.add(start_inc) };
let this = WeakSrc {
header: self.header,
start: start_ptr,
len,
_phantom: PhantomData,
};
forget(self); this
}
}
impl<T: SrcTarget + ?Sized> Clone for WeakSrc<T> {
fn clone(&self) -> Self {
if !self.is_dangling() {
unsafe { self.header() }.inc_weak_count();
}
Self {
header: self.header,
start: self.start,
len: self.len,
_phantom: PhantomData,
}
}
}
impl<T: SrcTarget + ?Sized> Debug for WeakSrc<T> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "(WeakSrc)")
}
}
impl<T: SrcTarget + ?Sized> Pointer for WeakSrc<T> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Pointer::fmt(&self.start, f)
}
}
impl<T: SrcTarget + ?Sized> Default for WeakSrc<T> {
#[inline]
fn default() -> Self {
Self::dangling()
}
}
impl<T: SrcTarget + ?Sized> Drop for WeakSrc<T> {
fn drop(&mut self) {
if !self.is_dangling() {
unsafe { InnerHeader::drop_weak::<T::Item>(self.header); }
}
}
}
#[cfg(test)]
mod tests {
use std::cell::Cell;
use crate::*;
#[test]
fn dangling() {
let w: WeakSrc<[u8]> = WeakSrc::dangling();
assert!(w.is_dangling());
assert!(w.upgrade().is_none());
}
#[test]
fn is_dangling() {
{ let w: WeakSrc<[u8]> = WeakSrc::dangling();
assert!(w.is_dangling());
}
{ let s: Src<[u8]> = Src::from_default(0);
let w: WeakSrc<[u8]> = Src::downgrade(&s);
assert!(!w.is_dangling());
std::mem::drop(s);
assert!(!w.is_dangling());
}
}
#[test]
fn upgrade() {
{ let w: WeakSrc<[u8]> = WeakSrc::dangling();
assert!(w.upgrade().is_none());
}
{ let s1: Src<[u8]> = Src::from_default(0);
let w: WeakSrc<[u8]> = Src::downgrade(&s1);
let s2: Src<[u8]> = w.upgrade().unwrap();
assert!(Src::ptr_eq(&s1, &s2));
}
}
#[test]
fn ptr_eq() {
{ let w1: WeakSrc<[u8]> = WeakSrc::dangling();
let w2: WeakSrc<[u8]> = WeakSrc::dangling();
assert!(w1.ptr_eq(&w2));
}
{ let s: Src<[u8]> = Src::from_default(1);
let w1: WeakSrc<[u8]> = Src::downgrade(&s);
let w2: WeakSrc<[u8]> = w1.clone();
assert!(w1.ptr_eq(&w2));
let w3: WeakSrc<[u8]> = WeakSrc::dangling();
assert!(!w1.ptr_eq(&w3));
assert!(!w2.ptr_eq(&w3));
let w4: WeakSrc<[u8]> = Src::downgrade(&s).slice(1..);
let w5: WeakSrc<[u8]> = Src::downgrade(&s).slice(1..);
assert!(w4.ptr_eq(&w5));
assert!(!w4.ptr_eq(&w1));
assert!(!w4.ptr_eq(&w3));
}
{ let s1: Src<[u8]> = Src::from_default(0);
let w1: WeakSrc<[u8]> = Src::downgrade(&s1);
let s2: Src<[u8]> = Src::from_default(0);
let w2: WeakSrc<[u8]> = Src::downgrade(&s2);
assert!(!w1.ptr_eq(&w2));
let w3: WeakSrc<[u8]> = WeakSrc::dangling();
assert!(!w1.ptr_eq(&w3));
assert!(!w2.ptr_eq(&w3));
std::mem::drop((s1, s2));
assert!(!w1.ptr_eq(&w3));
assert!(!w2.ptr_eq(&w3));
}
}
#[test]
fn same_root() {
{ let w1: WeakSrc<[u8]> = WeakSrc::dangling();
let w2: WeakSrc<[u8]> = WeakSrc::dangling();
assert!(w1.same_root(&w2));
}
{ let s: Src<[u8]> = Src::from_default(1);
let w1: WeakSrc<[u8]> = Src::downgrade(&s);
let w2: WeakSrc<[u8]> = w1.clone();
assert!(w1.same_root(&w2));
let w3: WeakSrc<[u8]> = WeakSrc::dangling();
assert!(!w1.same_root(&w3));
assert!(!w2.same_root(&w3));
let w4: WeakSrc<[u8]> = Src::downgrade(&s).slice(1..);
assert!(w4.same_root(&w1));
assert!(!w4.same_root(&w3));
}
{ let s1: Src<[u8]> = Src::from_default(0);
let w1: WeakSrc<[u8]> = Src::downgrade(&s1);
let s2: Src<[u8]> = Src::from_default(0);
let w2: WeakSrc<[u8]> = Src::downgrade(&s2);
assert!(!w1.same_root(&w2));
let w3: WeakSrc<[u8]> = WeakSrc::dangling();
assert!(!w1.same_root(&w3));
assert!(!w2.same_root(&w3));
std::mem::drop((s1, s2));
assert!(!w1.same_root(&w3));
assert!(!w2.same_root(&w3));
}
}
#[test]
fn is_root() {
{ let w: WeakSrc<[u8]> = WeakSrc::dangling();
assert!(w.is_root());
}
{
let s: Src<[u8]> = Src::from_default(1);
let w1: WeakSrc<[u8]> = Src::downgrade(&s);
assert!(w1.is_root());
let w2: WeakSrc<[u8]> = Src::downgrade(&s).slice(1..);
assert!(!w2.is_root());
std::mem::drop(s);
assert!(w1.is_root());
assert!(!w2.is_root());
}
}
#[test]
fn strong_count() {
{ let w: WeakSrc<[u8]> = WeakSrc::dangling();
assert_eq!(w.strong_count(), 0);
}
{ let s1: Src<[u8]> = Src::from_default(0);
let w: WeakSrc<[u8]> = Src::downgrade(&s1);
assert_eq!(w.strong_count(), 1);
let s2: Src<[u8]> = s1.clone();
assert_eq!(w.strong_count(), 2);
std::mem::drop(s1);
assert_eq!(w.strong_count(), 1);
std::mem::drop(s2);
assert_eq!(w.strong_count(), 0);
}
}
#[test]
fn weak_count() {
{ let w: WeakSrc<[u8]> = WeakSrc::dangling();
assert_eq!(w.weak_count(), 0);
}
{ let s: Src<[u8]> = Src::from_default(0);
let w1: WeakSrc<[u8]> = Src::downgrade(&s);
assert_eq!(w1.weak_count(), 1);
let w2: WeakSrc<[u8]> = w1.clone();
assert_eq!(w1.weak_count(), 2);
assert_eq!(w2.weak_count(), 2);
let w3: WeakSrc<[u8]> = Src::downgrade(&s);
assert_eq!(w1.weak_count(), 3);
assert_eq!(w2.weak_count(), 3);
assert_eq!(w3.weak_count(), 3);
std::mem::drop(w1);
assert_eq!(w2.weak_count(), 2);
assert_eq!(w3.weak_count(), 2);
std::mem::drop(s);
assert_eq!(w2.weak_count(), 0);
assert_eq!(w3.weak_count(), 0);
}
}
#[test]
fn len() {
{ let w: WeakSrc<[u8]> = WeakSrc::dangling();
assert_eq!(w.len(), 0);
}
{ let s: Src<[u8]> = Src::from_default(0);
let w: WeakSrc<[u8]> = Src::downgrade(&s);
assert_eq!(w.len(), 0);
let s: Src<[u8]> = Src::from_default(1);
let w: WeakSrc<[u8]> = Src::downgrade(&s);
assert_eq!(w.len(), 1);
let s: Src<[u8]> = Src::from_default(17);
let w: WeakSrc<[u8]> = Src::downgrade(&s);
assert_eq!(w.len(), 17);
let w: WeakSrc<[u8]> = w.slice(3..14);
assert_eq!(w.len(), 11);
let w: WeakSrc<[u8]> = w.slice(3..3);
assert_eq!(w.len(), 0);
}
}
#[test]
fn is_empty() {
{ let w: WeakSrc<[u8]> = WeakSrc::dangling();
assert!(w.is_empty());
}
{ let s: Src<[u8]> = Src::from_default(0);
let w: WeakSrc<[u8]> = Src::downgrade(&s);
assert!(w.is_empty());
let s: Src<[u8]> = Src::from_default(1);
let w: WeakSrc<[u8]> = Src::downgrade(&s);
assert!(!w.is_empty());
let s: Src<[u8]> = Src::from_default(17);
let w: WeakSrc<[u8]> = Src::downgrade(&s);
assert!(!w.is_empty());
let w: WeakSrc<[u8]> = w.slice(3..14);
assert!(!w.is_empty());
let w: WeakSrc<[u8]> = w.slice(3..3);
assert!(w.is_empty());
}
}
#[test]
fn root() {
{ let w1: WeakSrc<[u8]> = WeakSrc::dangling();
let w2: WeakSrc<[u8]> = w1.root();
assert!(w2.is_root());
assert!(w1.ptr_eq(&w2));
}
{ let s: Src<[u8]> = Src::from_default(1);
let w: WeakSrc<[u8]> = Src::downgrade(&s);
assert!(w.is_root());
let w: WeakSrc<[u8]> = w.slice(1..);
assert!(!w.is_root());
let w: WeakSrc<[u8]> = w.root();
assert!(w.is_root());
}
}
#[test]
fn slice() {
{ let w1: WeakSrc<[u8]> = WeakSrc::dangling();
let w2: WeakSrc<[u8]> = w1.slice(..);
assert!(WeakSrc::ptr_eq(&w1, &w2));
}
{ let s1: Src<[u8]> = Src::from_array([1, 2, 3]);
let w1: WeakSrc<[u8]> = Src::downgrade(&s1);
let s1: Src<[u8]> = w1.upgrade().unwrap();
assert_eq!(&*s1, &[1, 2, 3]);
let w1: WeakSrc<[u8]> = w1.slice(1..);
let s1: Src<[u8]> = w1.upgrade().unwrap();
assert_eq!(&*s1, &[2, 3]);
let w2: WeakSrc<[u8]> = w1.slice(..1);
let s2: Src<[u8]> = w2.upgrade().unwrap();
assert_eq!(&*s2, &[2]);
assert!(w1.same_root(&w2));
}
{ let s1: Src<[u8]> = Src::from_array([1, 2, 3]);
let w1: WeakSrc<[u8]> = Src::downgrade(&s1);
let s1: Src<[u8]> = w1.upgrade().unwrap();
assert_eq!(&*s1, &[1, 2, 3]);
let w2: WeakSrc<u8> = w1.slice(2);
let s2: Src<u8> = w2.upgrade().unwrap();
assert_eq!(&*s2, &3);
let w2: WeakSrc<[u8]> = w2.as_slice();
let s2: Src<[u8]> = w2.upgrade().unwrap();
assert_eq!(&*s2, &[3]);
assert!(w1.same_root(&w2));
}
{ let s1: Src<[u8]> = Src::from_array([1, 2, 3]);
let w1: WeakSrc<[u8]> = Src::downgrade(&s1);
let s1: Src<[u8]> = w1.upgrade().unwrap();
assert_eq!(&*s1, &[1, 2, 3]);
let w1: WeakSrc<[u8]> = w1.slice(1..);
let s1: Src<[u8]> = w1.upgrade().unwrap();
assert_eq!(&*s1, &[2, 3]);
let w2: WeakSrc<u8> = w1.slice(0);
let s2: Src<u8> = w2.upgrade().unwrap();
assert_eq!(&*s2, &2);
let w2: WeakSrc<[u8]> = w2.as_slice();
let s2: Src<[u8]> = w2.upgrade().unwrap();
assert_eq!(&*s2, &[2]);
assert!(w1.same_root(&w2));
}
}
#[test]
fn as_slice() {
{ let w: WeakSrc<u8> = WeakSrc::dangling();
let w: WeakSrc<[u8]> = w.as_slice();
assert!(w.is_dangling());
}
{ let s1: Src<u8> = Src::single(42);
let w1: WeakSrc<u8> = Src::downgrade(&s1);
let w2: WeakSrc<[u8]> = w1.as_slice();
let s2: Src<[u8]> = w2.upgrade().unwrap();
assert_eq!([*s1], *s2);
}
{ let s1: Src<[u8]> = Src::from_array([1, 2, 3]);
let w1: WeakSrc<[u8]> = Src::downgrade(&s1);
let w2: WeakSrc<u8> = w1.slice(1);
let s2: Src<u8> = w2.upgrade().unwrap();
let w3: WeakSrc<[u8]> = w2.as_slice();
let s3: Src<[u8]> = w3.upgrade().unwrap();
assert_eq!(s1[1], *s2);
assert_eq!([*s2], *s3);
}
}
#[test]
fn clone() {
{ let w1: WeakSrc<[u8]> = WeakSrc::dangling();
assert_eq!(w1.weak_count(), 0);
let w2: WeakSrc<[u8]> = w1.clone();
assert_eq!(w1.weak_count(), 0);
assert_eq!(w2.weak_count(), 0);
}
{ let s1: Src<[u8]> = Src::from_array([1, 2, 3]);
let w1: WeakSrc<[u8]> = Src::downgrade(&s1);
assert_eq!(w1.weak_count(), 1);
let w2: WeakSrc<[u8]> = w1.clone();
assert_eq!(w1.weak_count(), 2);
let s2: Src<[u8]> = w2.upgrade().unwrap();
assert_eq!(*s1, *s2);
assert!(w1.ptr_eq(&w2));
std::mem::drop((s1, s2));
assert_eq!(w1.weak_count(), 0);
}
}
#[test]
fn drop() {
let drop_flags: [_; 3] = std::array::from_fn(|_| Cell::new(false));
struct DropFlagger<'a>(&'a Cell<bool>);
impl Drop for DropFlagger<'_> {
fn drop(&mut self) {
self.0.update(|v| !v)
}
}
assert!(!drop_flags.iter().any(Cell::get));
let s: Src<[DropFlagger<'_>]> = Src::from_iter(drop_flags.iter().map(DropFlagger));
assert!(!drop_flags.iter().any(Cell::get));
let w1: WeakSrc<[DropFlagger<'_>]> = Src::downgrade(&s);
assert!(!drop_flags.iter().any(Cell::get));
assert_eq!(w1.weak_count(), 1);
let w2: WeakSrc<[DropFlagger<'_>]> = w1.clone();
assert!(!drop_flags.iter().any(Cell::get));
assert_eq!(w1.weak_count(), 2);
assert_eq!(w2.weak_count(), 2);
std::mem::drop(w1);
assert!(!drop_flags.iter().any(Cell::get));
assert_eq!(w2.weak_count(), 1);
std::mem::drop(s);
assert!(drop_flags.iter().all(Cell::get));
assert_eq!(w2.weak_count(), 0);
std::mem::drop(w2);
assert!(drop_flags.iter().all(Cell::get));
}
}