use std::any::{TypeId, type_name};
use std::collections::{HashMap, HashSet};
use async_trait::async_trait;
use crate::{AppContext, StdError};
pub trait Plugin: Send + Sync {
fn build(&self, ctx: &AppContext) -> impl Future<Output = Result<(), StdError>> + Send;
fn dependencies(&self) -> Dependencies {
Dependencies::new()
}
}
#[async_trait]
pub(crate) trait DynPlugin: Send + Sync {
async fn build(&self, ctx: &AppContext) -> Result<(), StdError>;
fn dependencies(&self) -> Dependencies {
Dependencies::new()
}
fn name(&self) -> &'static str;
}
#[async_trait]
impl<T> DynPlugin for T
where
T: Plugin,
{
async fn build(&self, ctx: &AppContext) -> Result<(), StdError> {
T::build(self, ctx).await
}
fn dependencies(&self) -> Dependencies {
T::dependencies(self)
}
fn name(&self) -> &'static str {
type_name::<T>()
}
}
#[derive(Clone)]
pub struct Dependencies {
pub(crate) plugins: HashSet<TypeId>,
pub(crate) names: HashMap<TypeId, &'static str>,
}
impl Dependencies {
pub fn new() -> Self {
Self {
plugins: HashSet::new(),
names: HashMap::new(),
}
}
pub fn plugin<T>(mut self) -> Self
where
T: Plugin + 'static,
{
let type_id = TypeId::of::<T>();
self.plugins.insert(type_id);
self.names.insert(type_id, type_name::<T>());
self
}
pub fn merge(mut self, other: Dependencies) -> Self {
self.plugins.extend(other.plugins);
self.names.extend(other.names);
self
}
}
impl Default for Dependencies {
fn default() -> Self {
Self::new()
}
}