Skip to main content

refs/
weak.rs

1use core::ptr::from_mut;
2use std::{
3    fmt::{Debug, Formatter},
4    hash::{Hash, Hasher},
5    intrinsics::transmute_unchecked,
6    marker::Unsize,
7    ops::{CoerceUnsized, Deref, DerefMut},
8    ptr::{from_ref, null, null_mut},
9};
10
11use crate::{AsAny, Erased, RawPointer, Rglica, ToRglica, ref_counter::RefCounter, weak_from_ref};
12
13pub(crate) const PTR_SIZE: usize = size_of::<usize>();
14
15/// Weak reference. Doesn't affect reference counting.
16pub struct Weak<T: ?Sized = Erased> {
17    pub(crate) ptr:   *mut T,
18    pub(crate) stamp: u64,
19    pub type_name:    &'static str,
20}
21
22unsafe impl<T: ?Sized> Send for Weak<T> {}
23unsafe impl<T: ?Sized> Sync for Weak<T> {}
24
25impl<T: ?Sized> Copy for Weak<T> {}
26
27impl<T: ?Sized> Clone for Weak<T> {
28    fn clone(&self) -> Self {
29        *self
30    }
31}
32
33impl<T> Weak<T> {
34    pub const fn const_default() -> Self {
35        Self {
36            ptr:       null_mut(),
37            stamp:     0,
38            type_name: std::any::type_name::<T>(),
39        }
40    }
41}
42
43impl<T: ?Sized> Weak<T> {
44    pub fn sized(&self) -> bool {
45        let ptr_size = size_of_val(&self.ptr);
46
47        if ptr_size == PTR_SIZE {
48            true
49        } else if ptr_size == PTR_SIZE * 2 {
50            false
51        } else {
52            unreachable!("Invalid ptr size: {ptr_size}")
53        }
54    }
55
56    pub(crate) fn addr(&self) -> usize {
57        if self.sized() {
58            self.ptr as *const u8 as usize
59        } else {
60            // Return only data address
61            let ptr_bytes: [usize; 2] = unsafe { transmute_unchecked(self.ptr) };
62            ptr_bytes[0]
63        }
64    }
65
66    pub fn raw(&self) -> RawPointer {
67        RawPointer::new(self.addr(), self.stamp, self.type_name)
68    }
69
70    pub unsafe fn from_raw(ptr: RawPointer) -> Self {
71        let mut new = Weak::<T> {
72            stamp: ptr.stamp(),
73            type_name: ptr.type_name(),
74            ..Default::default()
75        };
76
77        let ptr = if new.sized() {
78            unsafe { transmute_unchecked(ptr.addr()) }
79        } else {
80            trait Trait {}
81            struct Struct;
82            impl Trait for Struct {}
83
84            let sized: *const Struct = null();
85            let un_sized: *const dyn Trait = sized;
86
87            let mut ptr_bytes: [usize; 2] = unsafe { transmute_unchecked(un_sized) };
88            ptr_bytes[0] = ptr.addr();
89            unsafe { transmute_unchecked(ptr_bytes) }
90        };
91
92        new.ptr = ptr;
93
94        new
95    }
96
97    pub fn was_initialized(&self) -> bool {
98        !self.ptr.is_null()
99    }
100
101    pub fn is_ok(&self) -> bool {
102        if self.ptr.is_null() {
103            return false;
104        }
105        let Some(stamp) = RefCounter::stamp_for_address(self.addr()) else {
106            return false;
107        };
108        if stamp != self.stamp {
109            return false;
110        }
111        true
112    }
113
114    pub fn is_null(&self) -> bool {
115        !self.is_ok()
116    }
117
118    pub fn get(&self) -> Option<&T> {
119        if self.is_ok() {
120            unsafe { self.deref_unchecked().into() }
121        } else {
122            None
123        }
124    }
125
126    pub fn get_mut(&mut self) -> Option<&mut T> {
127        if self.is_ok() {
128            unsafe { self.deref_unchecked_mut().into() }
129        } else {
130            None
131        }
132    }
133
134    /// # Safety
135    /// Check state before usage
136    pub unsafe fn deref_unchecked(&self) -> &T {
137        unsafe { self.ptr.as_ref().unwrap_unchecked() }
138    }
139
140    /// # Safety
141    /// Check state before usage
142    pub unsafe fn deref_unchecked_mut(&mut self) -> &mut T {
143        unsafe { self.ptr.as_mut().unwrap_unchecked() }
144    }
145
146    /// # Safety
147    /// unsafe
148    pub unsafe fn to_rglica(&self) -> Rglica<T> {
149        self.deref().to_rglica()
150    }
151
152    #[cfg(feature = "checks")]
153    fn check(&self, check_main: bool) {
154        use log::error;
155
156        assert!(
157            !check_main || hreads::is_main_thread(),
158            "Unsafe Weak pointer deref: {}. Thread is not Main. Thread id: {}",
159            self.type_name,
160            hreads::current_thread_id()
161        );
162
163        if self.ptr.is_null() {
164            error!("Defererencing never initialized weak pointer: {}", self.type_name,);
165            // backtrace();
166            panic!("Defererencing never initialized weak pointer: {}", self.type_name,);
167        }
168
169        if self.is_null() {
170            #[cfg(feature = "pointers_info")]
171            let message = format!(
172                "Defererencing already freed weak pointer: {}. \nInfo: {}",
173                self.type_name,
174                crate::pointers_info::PointerInfo::get_info(self.addr())
175            );
176
177            #[cfg(not(feature = "pointers_info"))]
178            let message = format!("Defererencing already freed weak pointer: {}", self.type_name,);
179
180            error!("{message}");
181            panic!("{message}");
182        }
183    }
184
185    pub fn erase(&self) -> Weak {
186        Weak {
187            ptr:       self.ptr.cast(),
188            stamp:     self.stamp,
189            type_name: self.type_name,
190        }
191    }
192}
193
194impl<T> Weak<T> {
195    /// # Safety
196    ///
197    /// Create `Weak` without `Own` and leak memory.
198    /// Use only for test purposes.
199    #[track_caller]
200    pub unsafe fn leak(val: T) -> Self {
201        let val = Box::new(val);
202        let address = from_ref::<T>(&val).cast::<u8>() as usize;
203        let ptr = from_mut::<T>(Box::leak(val));
204
205        assert_ne!(
206            address, 1,
207            "Invalid address. In could be a closure or empty type."
208        );
209
210        #[cfg(feature = "pointers_info")]
211        let stamp = RefCounter::add(address, std::panic::Location::caller());
212        #[cfg(not(feature = "pointers_info"))]
213        let stamp = RefCounter::add(address);
214
215        Self {
216            ptr,
217            stamp,
218            type_name: std::any::type_name::<T>(),
219        }
220    }
221}
222
223impl<T: ?Sized + AsAny> Weak<T> {
224    pub fn downcast<U: 'static>(&self) -> Option<Weak<U>> {
225        let rf = self.as_any().downcast_ref::<U>()?;
226        Some(weak_from_ref(rf))
227    }
228}
229
230impl<T: ?Sized> Deref for Weak<T> {
231    type Target = T;
232    fn deref(&self) -> &T {
233        #[cfg(feature = "checks")]
234        self.check(false);
235        unsafe { self.deref_unchecked() }
236    }
237}
238
239impl<T: ?Sized> DerefMut for Weak<T> {
240    fn deref_mut(&mut self) -> &mut T {
241        #[cfg(feature = "checks")]
242        self.check(true);
243        unsafe { self.deref_unchecked_mut() }
244    }
245}
246
247impl<T: ?Sized> Default for Weak<T> {
248    default fn default() -> Self {
249        trait Trait {}
250        struct Struct;
251        impl Trait for Struct {}
252
253        let sized: *const Struct = null();
254        let un_sized: *const dyn Trait = sized;
255
256        Self {
257            ptr:       unsafe { transmute_unchecked(un_sized) },
258            stamp:     0,
259            type_name: "unsized null",
260        }
261    }
262}
263
264impl<T> Default for Weak<T> {
265    fn default() -> Self {
266        Self {
267            ptr:       null_mut(),
268            stamp:     0,
269            type_name: std::any::type_name::<T>(),
270        }
271    }
272}
273
274impl<T> Eq for Weak<T> {}
275
276impl<T> PartialEq<Self> for Weak<T> {
277    fn eq(&self, other: &Self) -> bool {
278        self.ptr == other.ptr && self.stamp == other.stamp
279    }
280}
281
282impl<T> Hash for Weak<T> {
283    fn hash<H: Hasher>(&self, state: &mut H) {
284        self.ptr.hash(state);
285        self.stamp.hash(state);
286    }
287}
288
289impl<T: ?Sized + Debug> Debug for Weak<T> {
290    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
291        self.deref().fmt(f)
292    }
293}
294
295impl<T, U> CoerceUnsized<Weak<U>> for Weak<T>
296where
297    T: Unsize<U> + ?Sized,
298    U: ?Sized,
299{
300}