Skip to main content

fusion_core/component/
mod.rs

1#![doc = include_str!("../../DI.md")]
2mod error;
3
4pub use fusion_core_macros::Component;
5pub use inventory::submit;
6use log::debug;
7use std::{any::Any, collections::HashSet, ops::Deref, sync::Arc};
8
9use crate::application::ApplicationBuilder;
10
11pub use error::{ComponentError, ComponentResult};
12
13/// Component's dyn trait reference
14#[derive(Debug, Clone)]
15pub struct DynComponentArc(Arc<dyn Any + Send + Sync>);
16
17impl DynComponentArc {
18  /// constructor
19  pub fn new<T>(component: T) -> Self
20  where
21    T: Any + Send + Sync,
22  {
23    Self(Arc::new(component))
24  }
25
26  /// Downcast to the specified type
27  pub fn downcast<T>(self) -> ComponentResult<ComponentArc<T>>
28  where
29    T: Any + Send + Sync,
30  {
31    match self.0.downcast::<T>() {
32      Ok(item) => Ok(ComponentArc::new(item)),
33      Err(_) => Err(ComponentError::ComponentTypeMismatch(std::any::type_name::<T>())),
34    }
35  }
36}
37
38/// A component reference of a specified type
39#[derive(Debug, Clone)]
40pub struct ComponentArc<T>(Arc<T>);
41
42impl<T> ComponentArc<T> {
43  fn new(target_ref: Arc<T>) -> Self {
44    Self(target_ref)
45  }
46
47  /// Get the raw pointer of the component
48  #[inline]
49  pub fn into_raw(self) -> *const T {
50    Arc::into_raw(self.0)
51  }
52}
53
54impl<T> Deref for ComponentArc<T> {
55  type Target = T;
56
57  fn deref(&self) -> &Self::Target {
58    &self.0
59  }
60}
61
62pub trait Component: Clone + Sized + 'static {
63  /// Construct the Component
64  fn build(app: &ApplicationBuilder) -> crate::Result<Self>;
65}
66
67pub trait ComponentInstaller: Send + Sync + 'static {
68  /// Get the dependencies of the Component
69  fn dependencies(&self) -> Vec<&str>;
70
71  /// Install the Component into the Application
72  fn install_component(&self, app: &mut ApplicationBuilder) -> crate::Result<()>;
73}
74
75inventory::collect!(&'static dyn ComponentInstaller);
76
77/// auto_config
78#[macro_export]
79macro_rules! submit_component {
80  ($ty:tt) => {
81    ::fusion_core::component::submit! {
82      &($ty) as &dyn ::fusion_core::component::ComponentInstaller
83    }
84  };
85}
86
87/// Find all ComponentInstaller and install them into the application
88pub fn auto_inject_component(app_builder: &mut ApplicationBuilder) -> crate::Result<()> {
89  let mut registrars: Vec<(&&dyn ComponentInstaller, Vec<&str>)> =
90    inventory::iter::<&dyn ComponentInstaller>.into_iter().map(|cr| (cr, cr.dependencies())).collect();
91
92  // TODO 当存在未注册的组件时,限制循环次数
93  let mut epoch = 0;
94  let mut last_pending_len = 0;
95
96  while !registrars.is_empty() && epoch < 10 {
97    let mut pending_registrars = vec![];
98    for (registrar, deps) in registrars {
99      let deps: Vec<&str> = deps.into_iter().filter(|d| !app_builder.components.contains_key(*d)).collect();
100      if deps.is_empty() {
101        registrar.install_component(app_builder)?;
102      } else {
103        debug!("Dependency does not exist, waiting for the next round: [{:?}]", deps);
104        pending_registrars.push((registrar, deps));
105      }
106    }
107    registrars = pending_registrars;
108
109    let pending_len = registrars.len();
110    if pending_len == 0 || last_pending_len != pending_len {
111      epoch = 0;
112      last_pending_len = pending_len;
113    } else {
114      epoch += 1;
115    }
116  }
117  if epoch != 0 {
118    let deps: HashSet<&str> = registrars.iter().flat_map(|(_, deps)| deps).copied().collect();
119    panic!(
120      "Component registration failed, please check the component dependency relationship. Unregistered Components: {:?}, epoch: {}",
121      deps, epoch
122    );
123  }
124  Ok(())
125}