pub mod provider;
pub mod testing;
pub use provider::{get_registered_services, ServiceBindingType, ServiceInfo};
use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::{Arc, OnceLock, RwLock};
static APP_CONTAINER: OnceLock<RwLock<Container>> = OnceLock::new();
thread_local! {
pub(crate) static TEST_CONTAINER: RefCell<Option<Container>> = const { RefCell::new(None) };
}
#[derive(Clone)]
enum Binding {
Singleton(Arc<dyn Any + Send + Sync>),
Factory(Arc<dyn Fn() -> Arc<dyn Any + Send + Sync> + Send + Sync>),
}
pub struct Container {
bindings: HashMap<TypeId, Binding>,
}
impl Container {
pub fn new() -> Self {
Self {
bindings: HashMap::new(),
}
}
pub fn singleton<T: Any + Send + Sync + 'static>(&mut self, instance: T) {
let arc: Arc<dyn Any + Send + Sync> = Arc::new(instance);
self.bindings
.insert(TypeId::of::<T>(), Binding::Singleton(arc));
}
pub fn factory<T, F>(&mut self, factory: F)
where
T: Any + Send + Sync + 'static,
F: Fn() -> T + Send + Sync + 'static,
{
let wrapped: Arc<dyn Fn() -> Arc<dyn Any + Send + Sync> + Send + Sync> =
Arc::new(move || Arc::new(factory()) as Arc<dyn Any + Send + Sync>);
self.bindings
.insert(TypeId::of::<T>(), Binding::Factory(wrapped));
}
pub fn bind<T: ?Sized + Send + Sync + 'static>(&mut self, instance: Arc<T>) {
let type_id = TypeId::of::<Arc<T>>();
let arc: Arc<dyn Any + Send + Sync> = Arc::new(instance);
self.bindings.insert(type_id, Binding::Singleton(arc));
}
pub fn bind_factory<T: ?Sized + Send + Sync + 'static, F>(&mut self, factory: F)
where
F: Fn() -> Arc<T> + Send + Sync + 'static,
{
let type_id = TypeId::of::<Arc<T>>();
let wrapped: Arc<dyn Fn() -> Arc<dyn Any + Send + Sync> + Send + Sync> =
Arc::new(move || Arc::new(factory()) as Arc<dyn Any + Send + Sync>);
self.bindings.insert(type_id, Binding::Factory(wrapped));
}
pub fn get<T: Any + Send + Sync + Clone + 'static>(&self) -> Option<T> {
match self.bindings.get(&TypeId::of::<T>())? {
Binding::Singleton(arc) => arc.downcast_ref::<T>().cloned(),
Binding::Factory(factory) => {
let arc = factory();
arc.downcast_ref::<T>().cloned()
}
}
}
pub fn make<T: ?Sized + Send + Sync + 'static>(&self) -> Option<Arc<T>> {
let type_id = TypeId::of::<Arc<T>>();
match self.bindings.get(&type_id)? {
Binding::Singleton(arc) => {
arc.downcast_ref::<Arc<T>>().cloned()
}
Binding::Factory(factory) => {
let arc = factory();
arc.downcast_ref::<Arc<T>>().cloned()
}
}
}
pub fn has<T: Any + 'static>(&self) -> bool {
self.bindings.contains_key(&TypeId::of::<T>())
}
pub fn has_binding<T: ?Sized + 'static>(&self) -> bool {
self.bindings.contains_key(&TypeId::of::<Arc<T>>())
}
}
impl Default for Container {
fn default() -> Self {
Self::new()
}
}
pub struct App;
impl App {
pub fn init() {
APP_CONTAINER.get_or_init(|| RwLock::new(Container::new()));
}
pub fn singleton<T: Any + Send + Sync + 'static>(instance: T) {
let container = APP_CONTAINER.get_or_init(|| RwLock::new(Container::new()));
if let Ok(mut c) = container.write() {
c.singleton(instance);
}
}
pub fn factory<T, F>(factory: F)
where
T: Any + Send + Sync + 'static,
F: Fn() -> T + Send + Sync + 'static,
{
let container = APP_CONTAINER.get_or_init(|| RwLock::new(Container::new()));
if let Ok(mut c) = container.write() {
c.factory(factory);
}
}
pub fn bind<T: ?Sized + Send + Sync + 'static>(instance: Arc<T>) {
let container = APP_CONTAINER.get_or_init(|| RwLock::new(Container::new()));
if let Ok(mut c) = container.write() {
c.bind(instance);
}
}
pub fn bind_factory<T: ?Sized + Send + Sync + 'static, F>(factory: F)
where
F: Fn() -> Arc<T> + Send + Sync + 'static,
{
let container = APP_CONTAINER.get_or_init(|| RwLock::new(Container::new()));
if let Ok(mut c) = container.write() {
c.bind_factory(factory);
}
}
pub fn get<T: Any + Send + Sync + Clone + 'static>() -> Option<T> {
let test_result = TEST_CONTAINER.with(|c| {
c.borrow()
.as_ref()
.and_then(|container| container.get::<T>())
});
if test_result.is_some() {
return test_result;
}
let container = APP_CONTAINER.get()?;
container.read().ok()?.get::<T>()
}
pub fn make<T: ?Sized + Send + Sync + 'static>() -> Option<Arc<T>> {
let test_result = TEST_CONTAINER.with(|c| {
c.borrow()
.as_ref()
.and_then(|container| container.make::<T>())
});
if test_result.is_some() {
return test_result;
}
let container = APP_CONTAINER.get()?;
container.read().ok()?.make::<T>()
}
pub fn resolve<T: Any + Send + Sync + Clone + 'static>(
) -> Result<T, crate::error::FrameworkError> {
Self::get::<T>().ok_or_else(crate::error::FrameworkError::service_not_found::<T>)
}
pub fn resolve_make<T: ?Sized + Send + Sync + 'static>(
) -> Result<Arc<T>, crate::error::FrameworkError> {
Self::make::<T>().ok_or_else(crate::error::FrameworkError::service_not_found::<T>)
}
pub fn has<T: Any + 'static>() -> bool {
let in_test = TEST_CONTAINER.with(|c| {
c.borrow()
.as_ref()
.map(|container| container.has::<T>())
.unwrap_or(false)
});
if in_test {
return true;
}
APP_CONTAINER
.get()
.and_then(|c| c.read().ok())
.map(|c| c.has::<T>())
.unwrap_or(false)
}
pub fn has_binding<T: ?Sized + 'static>() -> bool {
let in_test = TEST_CONTAINER.with(|c| {
c.borrow()
.as_ref()
.map(|container| container.has_binding::<T>())
.unwrap_or(false)
});
if in_test {
return true;
}
APP_CONTAINER
.get()
.and_then(|c| c.read().ok())
.map(|c| c.has_binding::<T>())
.unwrap_or(false)
}
pub fn boot_services() {
provider::bootstrap();
}
}
#[macro_export]
macro_rules! bind {
($trait:ty, $instance:expr) => {
$crate::App::bind::<$trait>(::std::sync::Arc::new($instance) as ::std::sync::Arc<$trait>)
};
}
#[macro_export]
macro_rules! bind_factory {
($trait:ty, $factory:expr) => {{
let f = $factory;
$crate::App::bind_factory::<$trait, _>(move || {
::std::sync::Arc::new(f()) as ::std::sync::Arc<$trait>
})
}};
}
#[macro_export]
macro_rules! singleton {
($instance:expr) => {
$crate::App::singleton($instance)
};
}
#[macro_export]
macro_rules! factory {
($factory:expr) => {
$crate::App::factory($factory)
};
}