use std::any::type_name;
use std::error::Error;
use std::fmt;
use std::future::Future;
use thiserror::Error;
use crate::module::registry::ModuleDependencies;
use crate::module::registry::Registry;
pub mod registry;
pub trait Module: Sized + Send + Sync + 'static {
type Setup: fmt::Debug + Default + Sized + Send + Sync + 'static;
type PreInit: Sized + Send + Sync + 'static;
fn pre_init(
setup: Self::Setup,
) -> impl Future<Output = Result<Self::PreInit, PreInitError>> + Send;
type Dependencies: ModuleDependencies;
fn init(
pre_init: Self::PreInit,
dependencies: &mut Self::Dependencies,
) -> impl Future<Output = Result<Self, InitError>> + Send;
fn post_init(&'static self) -> impl Future<Output = Result<(), PostInitError>> + Send {
async { Ok(()) }
}
#[track_caller]
fn global() -> &'static Self {
match Self::try_global() {
Ok(x) => x,
Err(error) => panic!("{error}"),
}
}
fn try_global() -> Result<&'static Self, TryGlobalError> {
Registry::try_global()
.ok_or(TryGlobalError::Registry)?
.try_get()
.ok_or_else(|| TryGlobalError::Module {
module_type: type_name::<Self>(),
})
}
fn global_wait() -> impl Future<Output = &'static Self> + Send + 'static {
async {
match Self::try_global_wait().await {
Some(x) => x,
None => panic!(
"the module '{}' has not been registered",
type_name::<Self>()
),
}
}
}
fn try_global_wait() -> impl Future<Output = Option<&'static Self>> + Send + 'static {
async { Registry::global_wait().await.try_get() }
}
}
pub type PreInitError = Box<dyn Error + Send + Sync + 'static>;
pub type InitError = Box<dyn Error + Send + Sync + 'static>;
pub type PostInitError = Box<dyn Error + Send + Sync + 'static>;
#[derive(Error, Debug)]
pub enum TryGlobalError {
#[error("the module registry has not been initialized yet")]
Registry,
#[error("the module '{module_type}' has not been registered")]
Module {
module_type: &'static str,
},
}