orengine_utils/
light_arc.rs1use 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#[repr(C)]
11struct LightArcInner<T> {
12 ref_count: AtomicUsize,
13 value: T,
14}
15
16#[repr(C)]
21pub struct LightArc<T> {
22 inner: NonNull<LightArcInner<T>>,
23}
24
25impl<T> LightArc<T> {
26 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 fn inner(&self) -> &LightArcInner<T> {
40 unsafe { self.inner.as_ref() }
41 }
42
43 #[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> {}