1use std::any::TypeId;
4
5#[derive(Debug)]
7pub struct Handle {
8 data: *const (),
9 drop: fn(*const ()),
10 type_id: TypeId,
11}
12
13unsafe impl Send for Handle {}
15unsafe impl Sync for Handle {}
16
17impl Handle {
18 pub fn new<T>(value: T) -> Self
19 where
20 T: Send + Sync + 'static,
21 {
22 Self {
23 data: Box::into_raw(Box::new(value)) as *const (),
24 drop: Self::handle_drop_fn::<T>,
25 type_id: TypeId::of::<T>(),
26 }
27 }
28
29 fn handle_drop_fn<T>(data: *const ()) {
31 drop(unsafe { Box::from_raw(data as *mut T) })
32 }
33
34 pub fn downcast<T>(&self) -> Option<&T>
39 where
40 T: Send + Sync + 'static,
41 {
42 let type_id = TypeId::of::<T>();
43 if self.type_id == type_id {
44 Some(unsafe { &*(self.data as *const T) })
45 } else {
46 None
47 }
48 }
49}
50
51impl Drop for Handle {
52 fn drop(&mut self) {
53 (self.drop)(self.data);
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use std::sync::{
60 atomic::{AtomicUsize, Ordering},
61 Arc,
62 };
63
64 use crate::Handle;
65
66 struct Mock(Arc<AtomicUsize>);
67
68 impl Drop for Mock {
69 fn drop(&mut self) {
70 self.0.fetch_sub(1, Ordering::Relaxed);
71 }
72 }
73
74 #[test]
75 fn test_handle() {
76 let counter: Arc<AtomicUsize> = Default::default();
77
78 let mock = Mock(counter.clone());
79
80 counter.fetch_add(1, Ordering::Relaxed);
81
82 let handle = Handle::new(mock);
83
84 assert_eq!(handle.downcast::<u32>(), None);
85
86 assert!(handle.downcast::<Mock>().is_some());
87
88 assert_eq!(counter.load(Ordering::Relaxed), 1);
89
90 drop(handle);
91
92 assert_eq!(counter.load(Ordering::Relaxed), 0);
93 }
94}