Skip to main content

osom_lib_arc/carc_array/
weak_array.rs

1//! Holds the definition of [`CWeak`].
2use core::sync::atomic::{Ordering, fence};
3
4use osom_lib_alloc::traits::Allocator;
5use osom_lib_reprc::traits::ReprC;
6use osom_lib_try_clone::TryClone;
7
8use crate::{
9    carc_array::{CArcArray, internal::InternalArcArray},
10    consts::MAX_REFERENCES,
11    errors::{MaxReferencesExceededError, WeakUpgradeError},
12};
13
14/// A weak reference to the underlying [`CArcArray`].
15///
16/// This object cannot inspect the underlying value (unless `T` is `Copy`).
17/// But it does track weak references, and each weak reference can build
18/// a strong reference, assuming any other strong reference is alive.
19#[repr(transparent)]
20#[must_use]
21#[derive(Debug)]
22pub struct CWeakArray<T, TAllocator: Allocator> {
23    internal: InternalArcArray<T, TAllocator>,
24}
25
26unsafe impl<T: ReprC, TAllocator: Allocator> ReprC for CWeakArray<T, TAllocator> {
27    const CHECK: () = const {
28        osom_lib_reprc::hidden::is_reprc::<T>();
29        osom_lib_reprc::hidden::is_reprc::<InternalArcArray<T, TAllocator>>();
30    };
31}
32
33impl<T, TAllocator: Allocator> CWeakArray<T, TAllocator> {
34    /// Returns the number of strong references to the [`CWeakArray`].
35    #[inline(always)]
36    #[must_use]
37    pub fn strong_count(&self) -> u32 {
38        self.internal.strong().load(Ordering::Relaxed)
39    }
40
41    /// Returns the number of weak references to the [`CWeakArray`].
42    #[inline(always)]
43    #[must_use]
44    pub fn weak_count(&self) -> u32 {
45        self.internal.weak().load(Ordering::Relaxed)
46    }
47
48    /// Upgrades current weak reference to the strong [`CArcArray`].
49    ///
50    /// # Errors
51    ///
52    /// For details see [`WeakUpgradeError`].
53    pub fn upgrade(&self) -> Result<CArcArray<T, TAllocator>, WeakUpgradeError> {
54        let strong = self.internal.strong();
55        let mut current = strong.load(Ordering::Relaxed);
56
57        loop {
58            if current == 0 {
59                return Err(WeakUpgradeError::NoStrongReferencesAlive);
60            }
61
62            if current >= MAX_REFERENCES {
63                return Err(WeakUpgradeError::MaxReferencesExceeded);
64            }
65
66            match strong.compare_exchange_weak(current, current + 1, Ordering::Acquire, Ordering::Relaxed) {
67                Ok(_) => return Ok(CArcArray::from_internal(self.internal.raw_clone())),
68                Err(new) => current = new,
69            }
70        }
71    }
72
73    /// Returns a reference to the underlying slice.
74    ///
75    /// This function is only available if `T` implements `Copy`.
76    /// That is because being `Copy` means it is not `Drop`. And
77    /// so we don't need strong references to keep the data alive.
78    #[inline]
79    #[must_use]
80    pub fn data(&self) -> &[T]
81    where
82        T: Copy,
83    {
84        self.internal.data_slice()
85    }
86
87    /// Abandons current weak reference.
88    ///
89    /// If the internal weak counter is positive it returns false.
90    ///
91    /// Otherwise it deallocates the underlying memory and returns true.
92    /// In particular only single (the last) [`CWeakArray`] returns true
93    /// by calling this.
94    #[inline(always)]
95    #[must_use]
96    pub fn abandon(mut self) -> bool {
97        let result = self.internal_abandon();
98        core::mem::forget(self);
99        result
100    }
101
102    #[inline]
103    pub(super) fn from_internal(internal: InternalArcArray<T, TAllocator>) -> Self {
104        Self { internal }
105    }
106
107    fn internal_abandon(&mut self) -> bool {
108        let internal = unsafe { core::ptr::read(&raw const self.internal) };
109        let prev = internal.weak().fetch_sub(1, Ordering::Release);
110        if prev > 1 {
111            return false;
112        }
113
114        // Synchronize with all prior Release decrements before deallocating.
115        fence(Ordering::Acquire);
116        unsafe { internal.deallocate_memory() };
117        true
118    }
119}
120
121impl<T, TAllocator: Allocator> Drop for CWeakArray<T, TAllocator> {
122    fn drop(&mut self) {
123        let _ = self.internal_abandon();
124    }
125}
126
127impl<T, TAllocator: Allocator> Clone for CWeakArray<T, TAllocator> {
128    fn clone(&self) -> Self {
129        self.try_clone()
130            .expect("CWeakArray weak reference count is too high. Cannot exceed {MAX_REFERENCES}")
131    }
132}
133
134impl<T, TAllocator: Allocator> TryClone for CWeakArray<T, TAllocator> {
135    type Error = MaxReferencesExceededError;
136
137    fn try_clone(&self) -> Result<Self, Self::Error> {
138        let internal_clone = self.internal.raw_clone();
139        let prev_value = internal_clone.weak().fetch_add(1, Ordering::Relaxed);
140        if prev_value >= MAX_REFERENCES {
141            internal_clone.weak().fetch_sub(1, Ordering::Relaxed);
142            return Err(MaxReferencesExceededError);
143        }
144        Ok(Self {
145            internal: internal_clone,
146        })
147    }
148}