open_coroutine_core/common/
beans.rs

1use dashmap::DashMap;
2use std::ffi::c_void;
3use std::sync::atomic::{AtomicUsize, Ordering};
4
5/// Simple bean factory.
6#[repr(C)]
7#[derive(Debug, Default)]
8pub struct BeanFactory<'b>(DashMap<&'b str, usize>);
9
10impl BeanFactory<'_> {
11    fn get_instance<'i>() -> &'i BeanFactory<'i> {
12        static INSTANCE: AtomicUsize = AtomicUsize::new(0);
13        let mut ret = INSTANCE.load(Ordering::Relaxed);
14        if ret == 0 {
15            let ptr: &'i mut BeanFactory = Box::leak(Box::default());
16            ret = std::ptr::from_mut(ptr) as usize;
17            INSTANCE.store(ret, Ordering::Relaxed);
18        }
19        unsafe { &*(ret as *mut BeanFactory) }
20    }
21
22    /// Init bean if not exists.
23    pub fn init_bean<B>(bean_name: &str, bean: B) {
24        let factory = Self::get_instance();
25        if factory.0.get(bean_name).is_none() {
26            let bean: &B = Box::leak(Box::new(bean));
27            assert!(factory
28                .0
29                .insert(
30                    Box::leak(Box::from(bean_name)),
31                    std::ptr::from_ref(bean) as usize,
32                )
33                .is_none());
34        }
35    }
36
37    /// Remove bean if exists.
38    #[must_use]
39    pub fn remove_bean<B>(bean_name: &str) -> Option<B> {
40        Self::get_instance()
41            .0
42            .remove(bean_name)
43            .map(|(_, ptr)| unsafe { *Box::from_raw((ptr as *mut c_void).cast::<B>()) })
44    }
45
46    /// Get the bean by name.
47    #[must_use]
48    pub fn get_bean<B>(bean_name: &str) -> Option<&B> {
49        Self::get_instance()
50            .0
51            .get(bean_name)
52            .map(|ptr| unsafe { &*(*ptr as *mut c_void).cast::<B>() })
53    }
54
55    /// Get the bean by name.
56    ///
57    /// # Safety
58    /// Only one mutable reference can be held for a given bean at a time.
59    #[allow(clippy::mut_from_ref)]
60    #[must_use]
61    pub unsafe fn get_mut_bean<B>(bean_name: &str) -> Option<&mut B> {
62        Self::get_instance()
63            .0
64            .get_mut(bean_name)
65            .map(|ptr| &mut *(*ptr as *mut c_void).cast::<B>())
66    }
67
68    /// Get the bean by name, create bean if not exists.
69    #[must_use]
70    pub fn get_or_default<B: Default>(bean_name: &str) -> &B {
71        let factory = Self::get_instance();
72        factory.0.get(bean_name).map_or_else(
73            || {
74                let bean: &B = Box::leak(Box::default());
75                _ = factory.0.insert(
76                    Box::leak(Box::from(bean_name)),
77                    std::ptr::from_ref(bean) as usize,
78                );
79                bean
80            },
81            |ptr| unsafe { &*(*ptr as *mut c_void).cast::<B>() },
82        )
83    }
84
85    /// Get the bean by name, create bean if not exists.
86    ///
87    /// # Safety
88    /// Only one mutable reference can be held for a given bean at a time.
89    #[must_use]
90    #[allow(clippy::mut_from_ref)]
91    pub unsafe fn get_mut_or_default<B: Default>(bean_name: &str) -> &mut B {
92        let factory = Self::get_instance();
93        factory.0.get_mut(bean_name).map_or_else(
94            || {
95                let bean: &mut B = Box::leak(Box::default());
96                _ = factory.0.insert(
97                    Box::leak(Box::from(bean_name)),
98                    std::ptr::from_ref(bean) as usize,
99                );
100                bean
101            },
102            |ptr| &mut *(*ptr as *mut c_void).cast::<B>(),
103        )
104    }
105}