osom_lib_arc/carc/
carc.rs1use core::{
3 borrow::Borrow,
4 cmp::Ordering as CmpOrdering,
5 hash::Hash,
6 ops::Deref,
7 sync::atomic::{Ordering, fence},
8};
9
10use osom_lib_alloc::traits::Allocator;
11use osom_lib_reprc::traits::ReprC;
12use osom_lib_try_clone::TryClone;
13
14use crate::{
15 consts::MAX_REFERENCES,
16 errors::{CArcError, MaxReferencesExceededError},
17};
18
19use super::{internal::InternalArc, weak::CWeak};
20
21#[repr(transparent)]
26#[must_use]
27#[derive(Debug)]
28pub struct CArc<T, TAllocator: Allocator> {
29 internal: InternalArc<T, TAllocator>,
30}
31
32unsafe impl<T: ReprC, TAllocator: Allocator> ReprC for CArc<T, TAllocator> {
33 const CHECK: () = const {
34 osom_lib_reprc::hidden::is_reprc::<T>();
35 osom_lib_reprc::hidden::is_reprc::<CWeak<T, TAllocator>>();
36 osom_lib_reprc::hidden::is_reprc::<InternalArc<T, TAllocator>>();
37 };
38}
39
40#[must_use]
43#[repr(C)]
44#[derive(Debug)]
45pub struct AbandonResult<T, TAllocator: Allocator> {
46 pub data: T,
48
49 pub weak: CWeak<T, TAllocator>,
51}
52
53unsafe impl<T: ReprC, TAllocator: Allocator> ReprC for AbandonResult<T, TAllocator> {
54 const CHECK: () = const {
55 osom_lib_reprc::hidden::is_reprc::<T>();
56 osom_lib_reprc::hidden::is_reprc::<CWeak<T, TAllocator>>();
57 };
58}
59
60impl<T, TAllocator: Allocator> CArc<T, TAllocator> {
61 #[inline]
67 pub fn new(value: T) -> Result<Self, CArcError>
68 where
69 TAllocator: Default,
70 {
71 let internal = InternalArc::new(value)?;
72 Ok(Self::from_internal(internal))
73 }
74
75 #[inline]
81 pub fn with_allocator(value: T, allocator: TAllocator) -> Result<Self, CArcError> {
82 let internal = InternalArc::with_allocator(value, allocator)?;
83 Ok(Self::from_internal(internal))
84 }
85
86 #[inline(always)]
88 #[must_use]
89 pub fn strong_count(carc: &Self) -> u32 {
90 carc.internal.strong().load(Ordering::Relaxed)
91 }
92
93 #[inline(always)]
95 #[must_use]
96 pub fn weak_count(carc: &Self) -> u32 {
97 carc.internal.weak().load(Ordering::Relaxed)
98 }
99
100 #[inline]
102 #[must_use]
103 pub const fn data(carc: &Self) -> &T {
104 carc.internal.data()
105 }
106
107 pub fn downgrade(carc: &Self) -> Result<CWeak<T, TAllocator>, MaxReferencesExceededError> {
113 let internal_clone = carc.internal.clone();
114 let prev_value = internal_clone.weak().fetch_add(1, Ordering::Relaxed);
115 if prev_value >= MAX_REFERENCES {
116 internal_clone.weak().fetch_sub(1, Ordering::Relaxed);
117 return Err(MaxReferencesExceededError);
118 }
119 Ok(CWeak::from_internal(internal_clone))
120 }
121
122 #[inline]
129 #[must_use]
130 pub fn abandon(mut carc: Self) -> Option<AbandonResult<T, TAllocator>> {
131 let result = unsafe { CArc::internal_abandon(&mut carc) };
132 core::mem::forget(carc);
133 result
134 }
135
136 #[inline(always)]
143 #[must_use]
144 pub const fn into_raw_ptr(carc: Self) -> *mut u8 {
145 let ptr = carc.internal.raw_ptr();
146 core::mem::forget(carc);
147 ptr
148 }
149
150 #[inline(always)]
161 pub const unsafe fn from_raw_ptr(ptr: *mut u8) -> Self {
162 let internal = InternalArc::from_raw_ptr(ptr);
163 Self { internal }
164 }
165
166 #[inline(always)]
167 pub(super) fn from_internal(internal: InternalArc<T, TAllocator>) -> Self {
168 Self { internal }
169 }
170
171 unsafe fn internal_abandon(carc: &mut Self) -> Option<AbandonResult<T, TAllocator>> {
172 let internal = unsafe { core::ptr::read(&raw const carc.internal) };
173 let prev = internal.strong().fetch_sub(1, Ordering::Release);
174 if prev > 1 {
175 return None;
176 }
177
178 let data = unsafe { internal.read_data() };
179
180 fence(Ordering::Acquire);
182
183 Some(AbandonResult {
184 data,
185 weak: CWeak::from_internal(internal),
186 })
187 }
188}
189
190impl<T, TAllocator: Allocator> Drop for CArc<T, TAllocator> {
191 fn drop(&mut self) {
192 let _ = unsafe { CArc::internal_abandon(self) };
193 }
194}
195
196impl<T, TAllocator: Allocator> AsRef<T> for CArc<T, TAllocator> {
197 fn as_ref(&self) -> &T {
198 CArc::data(self)
199 }
200}
201
202impl<T, TAllocator: Allocator> Deref for CArc<T, TAllocator> {
203 type Target = T;
204
205 fn deref(&self) -> &Self::Target {
206 CArc::data(self)
207 }
208}
209
210impl<T, TAllocator: Allocator> Borrow<T> for CArc<T, TAllocator> {
211 fn borrow(&self) -> &T {
212 CArc::data(self)
213 }
214}
215
216impl<T, TAllocator: Allocator> Clone for CArc<T, TAllocator> {
217 fn clone(&self) -> Self {
218 self.try_clone().expect("CArc strong reference count is too high.")
219 }
220}
221
222impl<T, TAllocator: Allocator> TryClone for CArc<T, TAllocator> {
223 type Error = MaxReferencesExceededError;
224
225 fn try_clone(&self) -> Result<Self, Self::Error> {
226 let internal_clone = self.internal.clone();
227 let prev_value = internal_clone.strong().fetch_add(1, Ordering::Relaxed);
228 if prev_value >= MAX_REFERENCES {
229 internal_clone.strong().fetch_sub(1, Ordering::Relaxed);
230 return Err(MaxReferencesExceededError);
231 }
232
233 Ok(Self {
234 internal: internal_clone,
235 })
236 }
237}
238
239impl<T: PartialEq, TAllocator: Allocator> PartialEq for CArc<T, TAllocator> {
240 fn eq(&self, other: &Self) -> bool {
241 self.internal.raw_equals(&other.internal) || CArc::data(self) == CArc::data(other)
242 }
243}
244
245impl<T: Eq, TAllocator: Allocator> Eq for CArc<T, TAllocator> {}
246
247impl<T: Hash, TAllocator: Allocator> Hash for CArc<T, TAllocator> {
248 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
249 CArc::data(self).hash(state);
250 }
251}
252
253impl<T: PartialOrd, TAllocator: Allocator> PartialOrd for CArc<T, TAllocator> {
254 fn partial_cmp(&self, other: &Self) -> Option<CmpOrdering> {
255 CArc::data(self).partial_cmp(CArc::data(other))
256 }
257}
258
259impl<T: Ord, TAllocator: Allocator> Ord for CArc<T, TAllocator> {
260 fn cmp(&self, other: &Self) -> CmpOrdering {
261 CArc::data(self).cmp(CArc::data(other))
262 }
263}