Skip to main content

osom_lib_arc/carc_array/
carc_array.rs

1use core::cmp::Ordering as CmpOrdering;
2use core::{
3    borrow::Borrow,
4    ops::Deref,
5    sync::atomic::{Ordering, fence},
6};
7
8use osom_lib_alloc::traits::Allocator;
9use osom_lib_primitives::length::Length;
10use osom_lib_reprc::traits::ReprC;
11use osom_lib_try_clone::TryClone;
12
13use crate::{
14    carc_array::{CWeakArray, internal::InternalArcArray},
15    consts::MAX_REFERENCES,
16    errors::MaxReferencesExceededError,
17};
18
19/// A smart pointer that can be used to share ownership of a value.
20///
21/// This struct is functionally similar to [`CArc<[T]>`][crate::carc::CArc]
22/// but comes with a builder for iteratively constructing the array.
23#[repr(transparent)]
24#[must_use]
25#[derive(Debug)]
26pub struct CArcArray<T, TAllocator: Allocator> {
27    internal: InternalArcArray<T, TAllocator>,
28}
29
30unsafe impl<T: ReprC, TAllocator: Allocator> ReprC for CArcArray<T, TAllocator> {
31    const CHECK: () = const {
32        osom_lib_reprc::hidden::is_reprc::<T>();
33        osom_lib_reprc::hidden::is_reprc::<CWeakArray<T, TAllocator>>();
34        osom_lib_reprc::hidden::is_reprc::<InternalArcArray<T, TAllocator>>();
35    };
36}
37
38impl<T, TAllocator: Allocator> CArcArray<T, TAllocator> {
39    #[inline]
40    pub(super) const fn from_internal(internal: InternalArcArray<T, TAllocator>) -> Self {
41        Self { internal }
42    }
43
44    /// Returns the number of strong references to the [`CArcArray`].
45    #[inline(always)]
46    #[must_use]
47    pub fn strong_count(carc: &Self) -> u32 {
48        carc.internal.strong().load(Ordering::Relaxed)
49    }
50
51    /// Returns the number of weak references to the [`CArcArray`].
52    #[inline(always)]
53    #[must_use]
54    pub fn weak_count(carc: &Self) -> u32 {
55        carc.internal.weak().load(Ordering::Relaxed)
56    }
57
58    /// Returns a reference to the underlying slice.
59    #[inline]
60    #[must_use]
61    pub const fn data(carc: &Self) -> &[T] {
62        carc.internal.data_slice()
63    }
64
65    /// Returns the length of the underlying slice.
66    #[inline]
67    pub const fn length(carc: &Self) -> Length {
68        carc.internal.size()
69    }
70
71    /// Creates a new [`CWeakArray`] reference to the [`CArcArray`].
72    ///
73    /// # Errors
74    ///
75    /// If the weak reference count is too high. Cannot exceed [`MAX_REFERENCES`].
76    pub fn downgrade(carc: &Self) -> Result<CWeakArray<T, TAllocator>, MaxReferencesExceededError> {
77        let internal_clone = carc.internal.raw_clone();
78        let prev_value = internal_clone.weak().fetch_add(1, Ordering::Relaxed);
79        if prev_value >= MAX_REFERENCES {
80            internal_clone.weak().fetch_sub(1, Ordering::Relaxed);
81            return Err(MaxReferencesExceededError);
82        }
83        Ok(CWeakArray::from_internal(internal_clone))
84    }
85
86    /// Abandons current [`CArcArray`].
87    ///
88    /// This function returns `None` if the underlying strong reference counter
89    /// is still positive. Otherwise it the final [`CWeakArray`]. In particular
90    /// this call drops the underlying data, but does not deallocate the memory.
91    #[inline]
92    #[must_use]
93    pub fn abandon(mut carc: Self) -> Option<CWeakArray<T, TAllocator>> {
94        let result = unsafe { CArcArray::internal_abandon(&mut carc) };
95        core::mem::forget(carc);
96        result
97    }
98
99    /// Converts the [`CArcArray`] into a raw pointer.
100    ///
101    /// # Notes
102    ///
103    /// * This method does not touch internal reference counters, `self` is simply forgotten.
104    /// * The caller must ensure that the pointer does not outlive the [`CArcArray`].
105    #[inline(always)]
106    #[must_use]
107    pub const fn into_raw_ptr(carc: Self) -> *mut u8 {
108        let ptr = carc.internal.raw_ptr();
109        core::mem::forget(carc);
110        ptr
111    }
112
113    /// Converts a raw pointer back to a [`CArcArray`].
114    ///
115    /// # Safety
116    ///
117    /// * The caller must ensure that the pointer came from the previous
118    ///   call to [`CArcArray::into_raw_ptr`].
119    /// * The caller must ensure that the raw pointer won't be used after
120    ///   the call.
121    ///
122    /// Otherwise the behavior is undefined.
123    #[inline(always)]
124    pub const unsafe fn from_raw_ptr(ptr: *mut u8) -> Self {
125        let internal = InternalArcArray::from_raw_ptr(ptr);
126        Self { internal }
127    }
128
129    unsafe fn internal_abandon(carc: &mut Self) -> Option<CWeakArray<T, TAllocator>> {
130        let mut internal = unsafe { core::ptr::read(&raw const carc.internal) };
131        let prev = internal.strong().fetch_sub(1, Ordering::Release);
132        if prev > 1 {
133            return None;
134        }
135
136        if core::mem::needs_drop::<T>() {
137            for item in internal.data_slice_mut() {
138                unsafe { core::ptr::drop_in_place(item) };
139            }
140        }
141
142        // Synchronize with all prior Release decrements before deallocating.
143        fence(Ordering::Acquire);
144
145        Some(CWeakArray::from_internal(internal))
146    }
147}
148
149impl<T, TAllocator: Allocator> Drop for CArcArray<T, TAllocator> {
150    fn drop(&mut self) {
151        let _ = unsafe { CArcArray::internal_abandon(self) };
152    }
153}
154
155impl<T, TAllocator: Allocator> AsRef<[T]> for CArcArray<T, TAllocator> {
156    fn as_ref(&self) -> &[T] {
157        self.internal.data_slice()
158    }
159}
160
161impl<T, TAllocator: Allocator> Deref for CArcArray<T, TAllocator> {
162    type Target = [T];
163
164    fn deref(&self) -> &Self::Target {
165        self.internal.data_slice()
166    }
167}
168
169impl<T, TAllocator: Allocator> Borrow<[T]> for CArcArray<T, TAllocator> {
170    fn borrow(&self) -> &[T] {
171        self.internal.data_slice()
172    }
173}
174
175impl<T, TAllocator: Allocator> Clone for CArcArray<T, TAllocator> {
176    fn clone(&self) -> Self {
177        self.try_clone()
178            .expect("CArcArray strong reference count is too high. Cannot exceed {MAX_REFERENCES}")
179    }
180}
181
182impl<T, TAllocator: Allocator> TryClone for CArcArray<T, TAllocator> {
183    type Error = MaxReferencesExceededError;
184
185    fn try_clone(&self) -> Result<Self, Self::Error> {
186        let internal_clone = self.internal.raw_clone();
187        let prev_value = internal_clone.strong().fetch_add(1, Ordering::Relaxed);
188        if prev_value >= MAX_REFERENCES {
189            internal_clone.strong().fetch_sub(1, Ordering::Relaxed);
190            return Err(MaxReferencesExceededError);
191        }
192        Ok(Self {
193            internal: internal_clone,
194        })
195    }
196}
197
198impl<T: PartialEq, TAllocator: Allocator> PartialEq for CArcArray<T, TAllocator> {
199    fn eq(&self, other: &Self) -> bool {
200        if self.internal.raw_equals(&other.internal) {
201            return true;
202        }
203        self.as_ref() == other.as_ref()
204    }
205}
206
207impl<T: Eq, TAllocator: Allocator> Eq for CArcArray<T, TAllocator> {}
208
209impl<T: core::hash::Hash, TAllocator: Allocator> core::hash::Hash for CArcArray<T, TAllocator> {
210    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
211        self.as_ref().hash(state);
212    }
213}
214
215impl<T: PartialOrd, TAllocator: Allocator> PartialOrd for CArcArray<T, TAllocator> {
216    fn partial_cmp(&self, other: &Self) -> Option<CmpOrdering> {
217        self.as_ref().partial_cmp(other.as_ref())
218    }
219}
220
221impl<T: Ord, TAllocator: Allocator> Ord for CArcArray<T, TAllocator> {
222    fn cmp(&self, other: &Self) -> CmpOrdering {
223        self.as_ref().cmp(other.as_ref())
224    }
225}