osom_lib_arc/carc/
weak.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 consts::MAX_REFERENCES,
10 errors::{MaxReferencesExceededError, WeakUpgradeError},
11};
12
13use super::{carc::CArc, internal::InternalArc};
14
15#[repr(transparent)]
21#[must_use]
22#[derive(Debug)]
23pub struct CWeak<T, TAllocator: Allocator> {
24 internal: InternalArc<T, TAllocator>,
25}
26
27unsafe impl<T: ReprC, TAllocator: Allocator> ReprC for CWeak<T, TAllocator> {
28 const CHECK: () = const {
29 osom_lib_reprc::hidden::is_reprc::<T>();
30 osom_lib_reprc::hidden::is_reprc::<InternalArc<T, TAllocator>>();
31 };
32}
33
34impl<T, TAllocator: Allocator> CWeak<T, TAllocator> {
35 #[inline(always)]
37 #[must_use]
38 pub fn strong_count(&self) -> u32 {
39 self.internal.strong().load(Ordering::Relaxed)
40 }
41
42 #[inline(always)]
44 #[must_use]
45 pub fn weak_count(&self) -> u32 {
46 self.internal.weak().load(Ordering::Relaxed)
47 }
48
49 #[inline]
55 #[must_use]
56 pub fn data(&self) -> &T
57 where
58 T: Copy,
59 {
60 self.internal.data()
61 }
62
63 pub fn upgrade(&self) -> Result<CArc<T, TAllocator>, WeakUpgradeError> {
69 let strong = self.internal.strong();
70 let mut current = strong.load(Ordering::Relaxed);
71
72 loop {
73 if current == 0 {
74 return Err(WeakUpgradeError::NoStrongReferencesAlive);
75 }
76
77 if current >= MAX_REFERENCES {
78 return Err(WeakUpgradeError::MaxReferencesExceeded);
79 }
80
81 match strong.compare_exchange_weak(current, current + 1, Ordering::Acquire, Ordering::Relaxed) {
82 Ok(_) => return Ok(CArc::from_internal(self.internal.clone())),
83 Err(new) => current = new,
84 }
85 }
86 }
87
88 #[inline(always)]
96 #[must_use]
97 pub fn abandon(mut self) -> bool {
98 let result = self.internal_abandon();
99 core::mem::forget(self);
100 result
101 }
102
103 #[inline]
104 pub(super) fn from_internal(internal: InternalArc<T, TAllocator>) -> Self {
105 Self { internal }
106 }
107
108 fn internal_abandon(&mut self) -> bool {
109 let internal = unsafe { core::ptr::read(&raw const self.internal) };
110 let prev = internal.weak().fetch_sub(1, Ordering::Release);
111 if prev > 1 {
112 return false;
113 }
114
115 fence(Ordering::Acquire);
117 unsafe { internal.deallocate_memory() };
118 true
119 }
120}
121
122impl<T, TAllocator: Allocator> Drop for CWeak<T, TAllocator> {
123 fn drop(&mut self) {
124 let _ = self.internal_abandon();
125 }
126}
127
128impl<T, TAllocator: Allocator> Clone for CWeak<T, TAllocator> {
129 fn clone(&self) -> Self {
130 self.try_clone()
131 .expect("CWeak weak reference count is too high. Cannot exceed {MAX_REFERENCES}")
132 }
133}
134
135impl<T, TAllocator: Allocator> TryClone for CWeak<T, TAllocator> {
136 type Error = MaxReferencesExceededError;
137
138 fn try_clone(&self) -> Result<Self, Self::Error> {
139 let internal_clone = self.internal.clone();
140 let prev_value = internal_clone.weak().fetch_add(1, Ordering::Relaxed);
141 if prev_value >= MAX_REFERENCES {
142 internal_clone.weak().fetch_sub(1, Ordering::Relaxed);
143 return Err(MaxReferencesExceededError);
144 }
145 Ok(Self {
146 internal: internal_clone,
147 })
148 }
149}