orengine_utils/
light_arc.rs

1//! This module provides [`LightArc`].
2use crate::hints::unlikely;
3use alloc::alloc::{dealloc, Layout};
4use alloc::boxed::Box;
5use core::ptr;
6use core::ptr::NonNull;
7use core::sync::atomic::{AtomicUsize, Ordering};
8
9/// An inner type for [`LightArc`].
10#[repr(C)]
11struct LightArcInner<T> {
12    ref_count: AtomicUsize,
13    value: T,
14}
15
16/// A light-weight reference-counted pointer to a value.
17///
18/// This is similar to [`Arc`](std::sync::Arc), but is more lightweight because it contains only a strong count.
19/// Therefore, it can't provide weak references.
20#[repr(C)]
21pub struct LightArc<T> {
22    inner: NonNull<LightArcInner<T>>,
23}
24
25impl<T> LightArc<T> {
26    /// Creates a new [`LightArc`] from the given value.
27    pub fn new(value: T) -> Self {
28        let inner = Box::new(LightArcInner {
29            ref_count: AtomicUsize::new(1),
30            value,
31        });
32
33        Self {
34            inner: NonNull::from(Box::leak(inner)),
35        }
36    }
37
38    /// Returns a reference to the inner value.
39    fn inner(&self) -> &LightArcInner<T> {
40        unsafe { self.inner.as_ref() }
41    }
42
43    /// Drops and deallocates the inner value.
44    ///
45    /// # Safety
46    ///
47    /// This function must only be called when the reference count is 0.
48    #[inline(never)]
49    unsafe fn drop_slow(&mut self) {
50        core::sync::atomic::fence(Ordering::Acquire);
51
52        unsafe {
53            ptr::drop_in_place(&mut self.inner.as_mut().value);
54
55            dealloc(
56                self.inner.as_ptr().cast(),
57                Layout::new::<LightArcInner<T>>(),
58            );
59        }
60    }
61}
62
63impl<T> Clone for LightArc<T> {
64    fn clone(&self) -> Self {
65        let count = self.inner().ref_count.fetch_add(1, Ordering::Relaxed);
66
67        debug_assert!(count > 0, "use after free");
68
69        Self { inner: self.inner }
70    }
71}
72
73impl<T> Drop for LightArc<T> {
74    fn drop(&mut self) {
75        if unlikely(self.inner().ref_count.fetch_sub(1, Ordering::Release) == 1) {
76            unsafe { self.drop_slow() };
77        }
78    }
79}
80
81impl<T> core::ops::Deref for LightArc<T> {
82    type Target = T;
83
84    fn deref(&self) -> &Self::Target {
85        &self.inner().value
86    }
87}
88
89unsafe impl<T: Send + Sync> Send for LightArc<T> {}
90unsafe impl<T: Send + Sync> Sync for LightArc<T> {}