orengine_utils/
light_arc.rs

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