rasi_syscall/
handle.rs

1//! opaque handle type of syscall.
2
3use std::any::TypeId;
4
5/// A transparent type pointer that represents any implementation-related asynchronous system type.
6#[derive(Debug)]
7pub struct Handle {
8    data: *const (),
9    drop: fn(*const ()),
10    type_id: TypeId,
11}
12
13/// safely: the handle wrap type `T` must implements `Send + Sync`
14unsafe 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    /// safely drop opaque data object.
30    fn handle_drop_fn<T>(data: *const ()) {
31        drop(unsafe { Box::from_raw(data as *mut T) })
32    }
33
34    /// Returns `T` reference to the inner value if it is of type `T`, or [`None`].
35    ///
36    /// As required by the `RASI`, there is no way to get a mutable reference to `T`,
37    /// so the inner type `T` should implements `Send + Sync` auto traits.
38    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}