vine_core/core/
ty.rs

1use std::any::{Any, type_name, TypeId};
2use std::fmt::{Debug, Display, Formatter};
3use std::sync::Arc;
4
5
6use dashmap::DashMap;
7use lazy_static::lazy_static;
8use log::{trace, warn};
9
10
11use crate::core::{DynBean, Error};
12
13/// A runtime type descriptor that enables dynamic type operations and trait object downcasting.
14/// 
15/// The Type system provides:
16/// - Runtime type identification and registration
17/// - Dynamic downcasting to concrete types and trait objects
18/// - Thread-safe type operations through DashMap
19/// 
20/// Types are registered automatically when first accessed via `Type::of::<T>()`.
21pub struct Type {
22    /// Unique identifier for this type
23    id: TypeId,
24    /// Human-readable type name
25    name: &'static str,
26    /// Registry of downcast functions for converting to different types/traits
27    downcast_fns: Arc<DashMap<TypeId, Arc<dyn Any + Send + Sync>>>
28}
29
30// Global registry of all registered types, indexed by TypeId for fast lookup
31lazy_static!(
32    static ref TYPES: Arc<DashMap<TypeId, Arc<Type>>> = Arc::new(DashMap::new());
33);
34
35impl Type {
36    /// Gets or creates a Type descriptor for the given type T.
37    /// 
38    /// This method is thread-safe and will only create one Type instance per type.
39    /// The type is automatically registered in the global TYPES registry.
40    ///
41    /// # Examples
42    /// ```
43    /// use vine_core::core::ty::Type;
44    ///
45    /// let string_type = Type::of::<String>();
46    /// let int_type = Type::of::<i32>();
47    /// ```
48    pub fn of<T: 'static>() -> Arc<Type> {
49        let type_id = TypeId::of::<T>();
50        let ref_mut = TYPES.entry(type_id).or_insert_with(|| {
51            let name = type_name::<T>();
52
53            trace!("register Type({})", name);
54            Arc::new(Type {
55                id: TypeId::of::<T>(),
56                name,
57                downcast_fns: Default::default(),
58            })
59        });
60
61        ref_mut.clone()
62    }
63
64    /// Returns the human-readable name of this type.
65    pub fn name(&self) -> &str {
66        self.name
67    }
68
69    /// Returns the unique TypeId for this type.
70    pub fn id(&self) -> &TypeId {
71        &self.id
72    }
73
74    /// Checks if this type can be downcast to the type identified by the given TypeId.
75    /// 
76    /// Returns true if a downcast function has been registered for the target type.
77    /// This is used to determine type compatibility at runtime.
78    pub fn assignable(&self, type_id: &TypeId) -> bool {
79        self.downcast_fns.contains_key(type_id)
80    }
81
82
83    /// Registers a downcast function for converting DynBean instances to type T.
84    /// 
85    /// This enables runtime conversion from the current type to trait objects or other types.
86    /// If a downcast function already exists for type T, it will be replaced with a warning.
87    /// 
88    /// # Arguments
89    /// * `downcast_fn` - Function that attempts to downcast a DynBean to Arc<T>
90    ///
91    /// # Examples
92    /// ```ignore
93    /// use vine_core::core::ty::Type;
94    /// use std::sync::Arc;
95    ///
96    /// let ty = Type::of::<MyStruct>();
97    /// ty.add_downcast::<dyn MyTrait>(|bean| Ok(Arc::downcast::<MyStruct>(bean)?));
98    /// ```
99    pub fn add_downcast<T: ?Sized + 'static>(&self, downcast_fn: fn(DynBean) -> Result<Arc<T>, DynBean>) {
100        let alias_id = TypeId::of::<T>();
101        trace!("register {} downcast fn for {}", self, type_name::<T>());
102        if let Some(_) = self.downcast_fns.insert(alias_id, Arc::new(downcast_fn)) {
103            warn!("override {} downcast fn for {}", self, type_name::<T>());
104        }
105    }
106
107    /// Attempts to downcast a DynBean to the specified type T.
108    /// 
109    /// This method looks up the appropriate downcast function and applies it to convert
110    /// the DynBean to the requested type. The target type must have been registered
111    /// via `add_downcast` on the source type.
112    /// 
113    /// # Arguments
114    /// * `dyn_bean` - The dynamic bean to downcast
115    ///
116    /// # Returns
117    /// * `Ok(Arc<T>)` - Successfully downcast bean
118    /// * `Err(Error)` - If the type is not registered or downcast fails
119    ///
120    /// # Examples
121    /// ```ignore
122    /// use vine_core::core::ty::Type;
123    /// use vine_core::core::bean_def::DynBean;
124    /// use std::sync::Arc;
125    ///
126    /// let bean: DynBean = Arc::new(MyStruct::new());
127    /// let result: Arc<MyStruct> = Type::downcast(bean)?;
128    /// ```
129    pub fn downcast<T: ?Sized + 'static>(dyn_bean: DynBean) -> Result<Arc<T>, Error> {
130        let type_id = dyn_bean.as_ref().type_id();
131        let Some(type_ref) = TYPES.get(&type_id) else {
132            return Err(Error::from(format!("Type {:?} is not registered in vine Type System", type_id)))
133        };
134
135        let alias_id = TypeId::of::<T>();
136        let Some(downcast_fn) = type_ref.value().downcast_fns.get(&alias_id) else {
137            return Err(Error::from(format!("No downcast function registered for {} -> {}", type_ref.value().name(), type_name::<T>())))
138        };
139
140        let arc = downcast_fn.clone()
141            .downcast::<fn(DynBean) -> Result<Arc<T>, DynBean>>()
142            .unwrap();
143
144        let Ok(bean) = (arc.as_ref())(dyn_bean) else {
145            return Err(Error::from(format!("Failed to downcast {} to {}", type_ref.value().name(), type_name::<T>())))
146        };
147
148        Ok(bean)
149    }
150}
151
152impl Display for Type {
153    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
154        write!(f, "Type({})", self.name)
155    }
156}
157
158
159impl Debug for Type {
160    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
161        write!(f, "Type(id={:?}, name={:?}, downcast_fns.len()={})", &self.id, self.name, self.downcast_fns.len())
162    }
163}
164
165#[cfg(test)]
166mod tests {
167    use std::sync::Arc;
168
169    use crate::core::DynBean;
170    use crate::core::ty::Type;
171
172    struct TestBean { name: &'static str, }
173    trait TestTrait { fn name(&self) -> &'static str; }
174    impl TestTrait for TestBean {
175        fn name(&self) -> &'static str { self.name }
176    }
177
178    #[test]
179    fn should_be_thread_safe() {
180        let ty = Type::of::<TestBean>();
181        ty.add_downcast::<TestBean>(|b| { Ok(Arc::downcast::<TestBean>(b)?)});
182        ty.add_downcast::<dyn TestTrait + Sync + Send>(|b| { Ok(Arc::downcast::<TestBean>(b)?)});
183
184        let given_dyn_bean: DynBean = Arc::new(TestBean { name: "test_bean" });
185
186        let test_bean = Type::downcast::<TestBean>(given_dyn_bean.clone()).unwrap();
187        let test_trait = Type::downcast::<dyn TestTrait + Send + Sync>(given_dyn_bean.clone()).unwrap();
188
189        assert_eq!(test_trait.name(), test_bean.name);
190    }
191}