orengine_utils/
light_arc.rs1use crate::hints::unlikely;
3use std::alloc::{dealloc, Layout};
4use std::ptr;
5use std::ptr::NonNull;
6use std::sync::atomic::{AtomicUsize, Ordering};
7
8#[repr(C)]
10struct LightArcInner<T> {
11 ref_count: AtomicUsize,
12 value: T,
13}
14
15#[repr(C)]
20pub struct LightArc<T> {
21 inner: NonNull<LightArcInner<T>>,
22}
23
24impl<T> LightArc<T> {
25 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 fn inner(&self) -> &LightArcInner<T> {
39 unsafe { self.inner.as_ref() }
40 }
41
42 #[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> {}