use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::sync::Mutex;
use dashmap::DashMap;
use crate::{AppBuilder, AppContext, StdError};
pub struct App {
pub(crate) components: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
}
impl App {
pub fn builder() -> AppBuilder {
AppBuilder {
context: AppContext {
components: DashMap::new(),
plugins: DashMap::new(),
pending_plugins: Mutex::new(Vec::new()),
},
}
}
pub fn get_component<T>(&self) -> Option<T>
where
T: Clone + Send + Sync + 'static,
{
self.get_component_ref().cloned()
}
pub fn has_component<T>(&self) -> bool
where
T: Send + Sync + 'static,
{
self.components.contains_key(&TypeId::of::<T>())
}
pub fn get_component_ref<T>(&self) -> Option<&T>
where
T: Send + Sync + 'static,
{
self.components
.get(&TypeId::of::<T>())
.and_then(|v| v.downcast_ref::<T>())
}
}
#[derive(Debug)]
pub enum AppError {
CircularDependency { cycle: Vec<&'static str> },
MissingDependency {
blocked: Vec<(&'static str, Vec<&'static str>)>,
},
MissingComponent(&'static str),
PluginError(StdError),
}
impl std::fmt::Display for AppError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AppError::CircularDependency { cycle } => {
write!(f, "Circular dependency: {}", cycle.join(" -> "))
}
AppError::MissingDependency { blocked } => {
write!(f, "Missing dependencies:")?;
for (plugin, deps) in blocked {
write!(f, "\n {} requires: {}", plugin, deps.join(", "))?;
}
Ok(())
}
AppError::MissingComponent(name) => {
write!(f, "Missing component: {name}")
}
AppError::PluginError(e) => write!(f, "Plugin error: {e}"),
}
}
}
impl std::error::Error for AppError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
AppError::PluginError(e) => Some(e.as_ref()),
_ => None,
}
}
}
impl From<StdError> for AppError {
fn from(value: StdError) -> Self {
Self::PluginError(value)
}
}