osom_lib_arc/carc_array/
weak_array.rs1use 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#[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 #[inline(always)]
36 #[must_use]
37 pub fn strong_count(&self) -> u32 {
38 self.internal.strong().load(Ordering::Relaxed)
39 }
40
41 #[inline(always)]
43 #[must_use]
44 pub fn weak_count(&self) -> u32 {
45 self.internal.weak().load(Ordering::Relaxed)
46 }
47
48 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 #[inline]
79 #[must_use]
80 pub fn data(&self) -> &[T]
81 where
82 T: Copy,
83 {
84 self.internal.data_slice()
85 }
86
87 #[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 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}