use std::{any::TypeId, borrow::Cow, collections::HashMap, rc::Rc};
use crate::{
BoxFuture, Constructor, Definition, DynProvider, DynSingle, EagerCreateFunction, Key, Provider,
ProviderRegistry, ResolveModule, Scope, Single, SingleRegistry, Type,
};
pub struct Context {
allow_override: bool,
allow_only_single_eager_create: bool,
eager_create: bool,
single_registry: SingleRegistry,
provider_registry: ProviderRegistry,
loaded_modules: Vec<Type>,
conditional_providers: Vec<(bool, DynProvider)>,
eager_create_functions: Vec<(Definition, EagerCreateFunction)>,
dependency_chain: DependencyChain,
}
impl Default for Context {
fn default() -> Self {
Self {
allow_override: true,
allow_only_single_eager_create: true,
eager_create: Default::default(),
single_registry: Default::default(),
provider_registry: Default::default(),
loaded_modules: Default::default(),
conditional_providers: Default::default(),
eager_create_functions: Default::default(),
dependency_chain: Default::default(),
}
}
}
impl Context {
#[track_caller]
pub fn create(modules: Vec<ResolveModule>) -> Context {
ContextOptions::default().create(modules)
}
#[cfg_attr(docsrs, doc(cfg(feature = "auto-register")))]
#[cfg(feature = "auto-register")]
#[track_caller]
pub fn auto_register() -> Context {
ContextOptions::default().auto_register()
}
pub async fn create_async(modules: Vec<ResolveModule>) -> Context {
ContextOptions::default().create_async(modules).await
}
#[cfg_attr(docsrs, doc(cfg(feature = "auto-register")))]
#[cfg(feature = "auto-register")]
pub async fn auto_register_async() -> Context {
ContextOptions::default().auto_register_async().await
}
pub fn options() -> ContextOptions {
ContextOptions::default()
}
pub fn allow_override(&self) -> bool {
self.allow_override
}
pub fn allow_only_single_eager_create(&self) -> bool {
self.allow_only_single_eager_create
}
pub fn eager_create(&self) -> bool {
self.eager_create
}
pub fn single_registry(&self) -> &HashMap<Key, DynSingle> {
self.single_registry.inner()
}
pub fn provider_registry(&self) -> &HashMap<Key, DynProvider> {
self.provider_registry.inner()
}
pub fn loaded_modules(&self) -> &Vec<Type> {
&self.loaded_modules
}
pub fn conditional_providers(&self) -> &Vec<(bool, DynProvider)> {
&self.conditional_providers
}
pub fn eager_create_functions(&self) -> &Vec<(Definition, EagerCreateFunction)> {
&self.eager_create_functions
}
pub fn dependency_chain(&self) -> &Vec<Key> {
&self.dependency_chain.stack
}
#[track_caller]
pub fn insert_singleton<T>(&mut self, instance: T)
where
T: 'static + Clone,
{
self.insert_singleton_with_name(instance, "");
}
#[track_caller]
pub fn insert_singleton_with_name<T, N>(&mut self, instance: T, name: N)
where
T: 'static + Clone,
N: Into<Cow<'static, str>>,
{
let provider: DynProvider =
Provider::<T>::never_construct(name.into(), Scope::Singleton).into();
let single = Single::new(instance, Some(Clone::clone)).into();
let key = provider.key().clone();
self.provider_registry.insert(provider, self.allow_override);
self.single_registry.insert(key, single);
}
#[track_caller]
pub fn insert_single_owner<T>(&mut self, instance: T)
where
T: 'static,
{
self.insert_single_owner_with_name(instance, "");
}
#[track_caller]
pub fn insert_single_owner_with_name<T, N>(&mut self, instance: T, name: N)
where
T: 'static,
N: Into<Cow<'static, str>>,
{
let provider: DynProvider =
Provider::<T>::never_construct(name.into(), Scope::SingleOwner).into();
let single = Single::new(instance, None).into();
let key = provider.key().clone();
self.provider_registry.insert(provider, self.allow_override);
self.single_registry.insert(key, single);
}
#[track_caller]
pub fn load_modules(&mut self, modules: Vec<ResolveModule>) {
if modules.is_empty() {
return;
}
let modules = flatten(modules, ResolveModule::submodules);
modules.into_iter().for_each(|module| {
self.loaded_modules.push(module.ty());
self.load_providers(module.eager_create(), module.providers());
});
}
pub fn unload_modules(&mut self, modules: Vec<ResolveModule>) {
if modules.is_empty() {
return;
}
let modules = flatten(modules, ResolveModule::submodules);
modules.into_iter().for_each(|module| {
self.loaded_modules.retain(|ty| ty != &module.ty());
self.unload_providers(module.providers());
});
}
#[track_caller]
pub fn flush(&mut self) {
self.create_eager_instances();
self.evaluate_providers();
self.create_eager_instances();
}
pub async fn flush_async(&mut self) {
self.create_eager_instances_async().await;
self.evaluate_providers();
self.create_eager_instances_async().await;
}
#[track_caller]
pub fn resolve<T: 'static>(&mut self) -> T {
self.resolve_with_name("")
}
#[track_caller]
pub fn resolve_with_name<T: 'static>(&mut self, name: impl Into<Cow<'static, str>>) -> T {
match self.inner_resolve(name.into(), Behaviour::CreateThenReturnSingletonOrTransient) {
Resolved::SingletonOrTransient(instance) => instance,
Resolved::NotFoundProvider(key) => no_provider_panic(key),
Resolved::NotSingletonOrTransient(definition) => {
not_singleton_or_transient_panic(definition)
}
Resolved::NotSingletonOrSingleOwner(_) | Resolved::NoReturn => unreachable!(),
}
}
#[track_caller]
pub fn resolve_option<T: 'static>(&mut self) -> Option<T> {
self.resolve_option_with_name("")
}
#[track_caller]
pub fn resolve_option_with_name<T: 'static>(
&mut self,
name: impl Into<Cow<'static, str>>,
) -> Option<T> {
match self.inner_resolve(name.into(), Behaviour::CreateThenReturnSingletonOrTransient) {
Resolved::SingletonOrTransient(instance) => Some(instance),
Resolved::NotFoundProvider(_) | Resolved::NotSingletonOrTransient(_) => None,
Resolved::NotSingletonOrSingleOwner(_) | Resolved::NoReturn => unreachable!(),
}
}
#[track_caller]
pub fn resolve_by_type<T: 'static>(&mut self) -> Vec<T> {
self.names::<T>()
.into_iter()
.filter_map(|name| self.resolve_option_with_name(name))
.collect()
}
#[doc(hidden)]
#[track_caller]
pub fn just_create<T: 'static>(&mut self, name: Cow<'static, str>) {
match self.inner_resolve::<T>(name, Behaviour::JustCreateAllScopeForEagerCreate) {
Resolved::NoReturn => {}
Resolved::NotFoundProvider(key) => no_provider_panic(key),
Resolved::SingletonOrTransient(_)
| Resolved::NotSingletonOrTransient(_)
| Resolved::NotSingletonOrSingleOwner(_) => {
unreachable!()
}
}
}
#[track_caller]
pub fn just_create_single<T: 'static>(&mut self) {
self.just_create_single_with_name::<T>("");
}
#[track_caller]
pub fn just_create_single_with_name<T: 'static>(&mut self, name: impl Into<Cow<'static, str>>) {
match self.inner_resolve::<T>(name.into(), Behaviour::JustCreateSingletonOrSingleOwner) {
Resolved::NoReturn => {}
Resolved::NotFoundProvider(key) => no_provider_panic(key),
Resolved::NotSingletonOrSingleOwner(definition) => {
not_singleton_or_single_owner_panic(definition)
}
Resolved::SingletonOrTransient(_) | Resolved::NotSingletonOrTransient(_) => {
unreachable!()
}
}
}
#[track_caller]
pub fn try_just_create_single<T: 'static>(&mut self) -> bool {
self.try_just_create_single_with_name::<T>("")
}
#[track_caller]
pub fn try_just_create_single_with_name<T: 'static>(
&mut self,
name: impl Into<Cow<'static, str>>,
) -> bool {
match self.inner_resolve::<T>(name.into(), Behaviour::JustCreateSingletonOrSingleOwner) {
Resolved::NoReturn => true,
Resolved::NotFoundProvider(_) | Resolved::NotSingletonOrSingleOwner(_) => false,
Resolved::SingletonOrTransient(_) | Resolved::NotSingletonOrTransient(_) => {
unreachable!()
}
}
}
#[track_caller]
pub fn try_just_create_singles_by_type<T: 'static>(&mut self) -> Vec<bool> {
self.names::<T>()
.into_iter()
.map(|name| self.try_just_create_single_with_name::<T>(name))
.collect()
}
pub async fn resolve_async<T: 'static>(&mut self) -> T {
self.resolve_with_name_async("").await
}
pub async fn resolve_with_name_async<T: 'static>(
&mut self,
name: impl Into<Cow<'static, str>>,
) -> T {
match self
.inner_resolve_async(name.into(), Behaviour::CreateThenReturnSingletonOrTransient)
.await
{
Resolved::SingletonOrTransient(instance) => instance,
Resolved::NotFoundProvider(key) => no_provider_panic(key),
Resolved::NotSingletonOrTransient(definition) => {
not_singleton_or_transient_panic(definition)
}
Resolved::NotSingletonOrSingleOwner(_) | Resolved::NoReturn => unreachable!(),
}
}
pub async fn resolve_option_async<T: 'static>(&mut self) -> Option<T> {
self.resolve_option_with_name_async("").await
}
pub async fn resolve_option_with_name_async<T: 'static>(
&mut self,
name: impl Into<Cow<'static, str>>,
) -> Option<T> {
match self
.inner_resolve_async(name.into(), Behaviour::CreateThenReturnSingletonOrTransient)
.await
{
Resolved::SingletonOrTransient(instance) => Some(instance),
Resolved::NotFoundProvider(_) | Resolved::NotSingletonOrTransient(_) => None,
Resolved::NotSingletonOrSingleOwner(_) | Resolved::NoReturn => unreachable!(),
}
}
pub async fn resolve_by_type_async<T: 'static>(&mut self) -> Vec<T> {
let names = self.names::<T>();
let mut instances = Vec::with_capacity(names.len());
for name in names {
if let Some(instance) = self.resolve_option_with_name_async(name).await {
instances.push(instance);
}
}
instances
}
#[doc(hidden)]
pub async fn just_create_async<T: 'static>(&mut self, name: Cow<'static, str>) {
match self
.inner_resolve_async::<T>(name, Behaviour::JustCreateAllScopeForEagerCreate)
.await
{
Resolved::NoReturn => {}
Resolved::NotFoundProvider(key) => no_provider_panic(key),
Resolved::SingletonOrTransient(_)
| Resolved::NotSingletonOrTransient(_)
| Resolved::NotSingletonOrSingleOwner(_) => {
unreachable!()
}
}
}
pub async fn just_create_single_async<T: 'static>(&mut self) {
self.just_create_single_with_name_async::<T>("").await;
}
pub async fn just_create_single_with_name_async<T: 'static>(
&mut self,
name: impl Into<Cow<'static, str>>,
) {
match self
.inner_resolve_async::<T>(name.into(), Behaviour::JustCreateSingletonOrSingleOwner)
.await
{
Resolved::NoReturn => {}
Resolved::NotFoundProvider(key) => no_provider_panic(key),
Resolved::NotSingletonOrSingleOwner(definition) => {
not_singleton_or_single_owner_panic(definition)
}
Resolved::SingletonOrTransient(_) | Resolved::NotSingletonOrTransient(_) => {
unreachable!()
}
}
}
pub async fn try_just_create_single_async<T: 'static>(&mut self) -> bool {
self.try_just_create_single_with_name_async::<T>("").await
}
pub async fn try_just_create_single_with_name_async<T: 'static>(
&mut self,
name: impl Into<Cow<'static, str>>,
) -> bool {
match self
.inner_resolve_async::<T>(name.into(), Behaviour::JustCreateSingletonOrSingleOwner)
.await
{
Resolved::NoReturn => true,
Resolved::NotFoundProvider(_) | Resolved::NotSingletonOrSingleOwner(_) => false,
Resolved::SingletonOrTransient(_) | Resolved::NotSingletonOrTransient(_) => {
unreachable!()
}
}
}
pub async fn try_just_create_singles_by_type_async<T: 'static>(&mut self) -> Vec<bool> {
let names = self.names::<T>();
let mut results = Vec::with_capacity(names.len());
for name in names {
let result = self.try_just_create_single_with_name_async::<T>(name).await;
results.push(result);
}
results
}
pub fn contains_provider<T: 'static>(&self) -> bool {
self.contains_provider_with_name::<T>("")
}
pub fn contains_provider_with_name<T: 'static>(
&self,
name: impl Into<Cow<'static, str>>,
) -> bool {
let key = Key::new::<T>(name.into());
self.provider_registry.contains(&key)
}
pub fn get_provider<T: 'static>(&self) -> Option<&Provider<T>> {
self.get_provider_with_name("")
}
pub fn get_provider_with_name<T: 'static>(
&self,
name: impl Into<Cow<'static, str>>,
) -> Option<&Provider<T>> {
let key = Key::new::<T>(name.into());
self.provider_registry.get(&key)
}
pub fn get_providers_by_type<T: 'static>(&self) -> Vec<&Provider<T>> {
let type_id = TypeId::of::<T>();
self.provider_registry()
.iter()
.filter(|(key, _)| key.ty.id == type_id)
.filter_map(|(_, provider)| provider.as_provider())
.collect()
}
pub fn contains_single<T: 'static>(&self) -> bool {
self.contains_single_with_name::<T>("")
}
pub fn contains_single_with_name<T: 'static>(
&self,
name: impl Into<Cow<'static, str>>,
) -> bool {
let key = Key::new::<T>(name.into());
self.single_registry.contains(&key)
}
#[track_caller]
pub fn get_single<T: 'static>(&self) -> &T {
self.get_single_with_name("")
}
#[track_caller]
pub fn get_single_with_name<T: 'static>(&self, name: impl Into<Cow<'static, str>>) -> &T {
let key = Key::new::<T>(name.into());
self.single_registry
.get_ref(&key)
.unwrap_or_else(|| panic!("no instance registered for: {:?}", key))
}
pub fn get_single_option<T: 'static>(&self) -> Option<&T> {
self.get_single_option_with_name("")
}
pub fn get_single_option_with_name<T: 'static>(
&self,
name: impl Into<Cow<'static, str>>,
) -> Option<&T> {
let key = Key::new::<T>(name.into());
self.single_registry.get_ref(&key)
}
pub fn get_singles_by_type<T: 'static>(&self) -> Vec<&T> {
let type_id = TypeId::of::<T>();
self.single_registry()
.iter()
.filter(|(key, _)| key.ty.id == type_id)
.filter_map(|(_, instance)| instance.as_single())
.map(|instance| instance.get_ref())
.collect()
}
}
impl Context {
#[track_caller]
fn load_provider(&mut self, eager_create: bool, provider: DynProvider) {
let definition = provider.definition();
let need_eager_create = self.eager_create || eager_create || provider.eager_create();
let allow_all_scope = !self.allow_only_single_eager_create;
let allow_only_single_and_it_is_single = matches!(
(self.allow_only_single_eager_create, definition.scope),
(true, Scope::Singleton) | (true, Scope::SingleOwner)
);
let allow_eager_create = allow_all_scope || allow_only_single_and_it_is_single;
if need_eager_create && allow_eager_create {
self.eager_create_functions
.push((definition.clone(), provider.eager_create_function()));
}
self.provider_registry.insert(provider, self.allow_override);
}
#[track_caller]
fn load_providers(&mut self, eager_create: bool, providers: Vec<DynProvider>) {
if providers.is_empty() {
return;
}
let providers = flatten(providers, DynProvider::binding_providers);
providers.into_iter().for_each(|provider| {
if provider.condition().is_some() {
self.conditional_providers.push((eager_create, provider));
return;
}
self.load_provider(eager_create, provider);
});
}
fn unload_providers(&mut self, providers: Vec<DynProvider>) {
if providers.is_empty() {
return;
}
let providers = flatten(providers, DynProvider::binding_providers);
providers.into_iter().for_each(|provider| {
let key = provider.key();
self.provider_registry.remove(key);
self.single_registry.remove(key);
});
}
#[track_caller]
fn create_eager_instances(&mut self) {
if self.eager_create_functions.is_empty() {
return;
}
self.eager_create_functions.reverse();
while let Some((definition, eager_create_function)) = self.eager_create_functions.pop() {
match eager_create_function {
EagerCreateFunction::Async(_) => {
panic!(
"unable to call an async eager create function in a sync context for: {:?}
please use instead:
1. Context::create_async(modules).await
2. Context::auto_register_async().await
3. ContextOptions::create_async(options, modules).await
4. ContextOptions::auto_register_async(options).await
",
definition
)
}
EagerCreateFunction::Sync(eager_create_function) => {
eager_create_function(self, definition.key.name)
}
EagerCreateFunction::None => unreachable!(),
}
}
}
async fn create_eager_instances_async(&mut self) {
if self.eager_create_functions.is_empty() {
return;
}
self.eager_create_functions.reverse();
while let Some((definition, eager_create_function)) = self.eager_create_functions.pop() {
match eager_create_function {
EagerCreateFunction::Async(eager_create_function) => {
eager_create_function(self, definition.key.name).await
}
EagerCreateFunction::Sync(eager_create_function) => {
eager_create_function(self, definition.key.name)
}
EagerCreateFunction::None => unreachable!(),
}
}
}
#[track_caller]
fn evaluate_providers(&mut self) {
if self.conditional_providers.is_empty() {
return;
}
self.conditional_providers.reverse();
while let Some((eager_create, provider)) = self.conditional_providers.pop() {
if !(provider.condition().unwrap())(self) {
#[cfg(feature = "tracing")]
tracing::warn!("(×) condition not met: {:?}", provider.definition());
continue;
}
self.load_provider(eager_create, provider);
}
}
fn before_resolve<T: 'static>(
&mut self,
name: Cow<'static, str>,
behaviour: Behaviour,
) -> Result<Resolved<T>, Holder<'_, T>> {
let key = Key::new::<T>(name);
let Some(provider) = self.provider_registry.get::<T>(&key) else {
return Ok(Resolved::NotFoundProvider(key));
};
let definition = provider.definition();
if self.single_registry.contains(&key) {
return Ok(match behaviour {
Behaviour::CreateThenReturnSingletonOrTransient => {
match self.single_registry.get_owned::<T>(&key) {
Some(instance) => Resolved::SingletonOrTransient(instance),
None => Resolved::NotSingletonOrTransient(definition.clone()),
}
}
Behaviour::JustCreateAllScopeForEagerCreate
| Behaviour::JustCreateSingletonOrSingleOwner => Resolved::NoReturn,
});
}
match (definition.scope, behaviour) {
(Scope::Transient, Behaviour::JustCreateSingletonOrSingleOwner) => {
return Ok(Resolved::NotSingletonOrSingleOwner(definition.clone()))
}
(Scope::SingleOwner, Behaviour::CreateThenReturnSingletonOrTransient) => {
return Ok(Resolved::NotSingletonOrTransient(definition.clone()))
}
_ => {}
}
let constructor = provider.constructor();
let clone_instance = provider.clone_instance();
Err(Holder {
key,
constructor,
clone_instance,
definition,
})
}
fn after_resolve<T: 'static>(
&mut self,
key: Key,
behaviour: Behaviour,
scope: Scope,
instance: T,
clone_instance: Option<fn(&T) -> T>,
) -> Resolved<T> {
match (scope, behaviour) {
(Scope::Singleton, Behaviour::CreateThenReturnSingletonOrTransient) => {
self.single_registry.insert(
key,
Single::new((clone_instance.unwrap())(&instance), clone_instance).into(),
);
Resolved::SingletonOrTransient(instance)
}
(Scope::Singleton, Behaviour::JustCreateAllScopeForEagerCreate)
| (Scope::Singleton, Behaviour::JustCreateSingletonOrSingleOwner) => {
self.single_registry
.insert(key, Single::new(instance, clone_instance).into());
Resolved::NoReturn
}
(Scope::Transient, Behaviour::CreateThenReturnSingletonOrTransient) => {
Resolved::SingletonOrTransient(instance)
}
(Scope::Transient, Behaviour::JustCreateAllScopeForEagerCreate) => Resolved::NoReturn,
(Scope::Transient, Behaviour::JustCreateSingletonOrSingleOwner) => unreachable!(),
(Scope::SingleOwner, Behaviour::CreateThenReturnSingletonOrTransient) => unreachable!(),
(Scope::SingleOwner, Behaviour::JustCreateAllScopeForEagerCreate)
| (Scope::SingleOwner, Behaviour::JustCreateSingletonOrSingleOwner) => {
self.single_registry
.insert(key, Single::new(instance, None).into());
Resolved::NoReturn
}
}
}
#[track_caller]
fn inner_resolve<T: 'static>(
&mut self,
name: Cow<'static, str>,
behaviour: Behaviour,
) -> Resolved<T> {
let Holder {
key,
constructor,
clone_instance,
definition,
} = match self.before_resolve(name, behaviour) {
Ok(o) => return o,
Err(e) => e,
};
let scope = definition.scope;
let instance = match constructor {
Constructor::Async(_) => {
panic!(
"unable to call an async constructor in a sync context for: {:?}
please check all the references to the above type, there are 3 scenarios that will be referenced:
1. use `Context::resolve_xxx::<Type>(cx)` to get instances of the type, change to `Context::resolve_xxx_async::<Type>(cx).await`.
2. use `yyy: Type` as a field of a struct, or a field of a variant of a enum, use `#[Singleton(async)]`, `#[Transient(async)]` or `#[SingleOwner(async)]` on the struct or enum.
3. use `zzz: Type` as a argument of a function, add the `async` keyword to the function.
",
definition
)
}
Constructor::Sync(constructor) => self.resolve_instance(key.clone(), constructor),
Constructor::None => unreachable!(),
};
self.after_resolve(key, behaviour, scope, instance, clone_instance)
}
async fn inner_resolve_async<T: 'static>(
&mut self,
name: Cow<'static, str>,
behaviour: Behaviour,
) -> Resolved<T> {
let Holder {
key,
constructor,
clone_instance,
definition,
} = match self.before_resolve(name, behaviour) {
Ok(o) => return o,
Err(e) => e,
};
let scope = definition.scope;
let instance = {
let key = key.clone();
match constructor {
Constructor::Async(constructor) => {
self.resolve_instance_async(key, constructor).await
}
Constructor::Sync(constructor) => self.resolve_instance(key, constructor),
Constructor::None => unreachable!(),
}
};
self.after_resolve(key, behaviour, scope, instance, clone_instance)
}
#[track_caller]
fn resolve_instance<T: 'static>(
&mut self,
key: Key,
constructor: Rc<dyn Fn(&mut Context) -> T>,
) -> T {
self.dependency_chain.push(key);
let instance = constructor(self);
self.dependency_chain.pop();
instance
}
#[allow(clippy::type_complexity)]
async fn resolve_instance_async<T: 'static>(
&mut self,
key: Key,
constructor: Rc<dyn for<'a> Fn(&'a mut Context) -> BoxFuture<'a, T>>,
) -> T {
self.dependency_chain.push(key);
let instance = constructor(self).await;
self.dependency_chain.pop();
instance
}
fn names<T: 'static>(&self) -> Vec<Cow<'static, str>> {
let type_id = TypeId::of::<T>();
self.provider_registry()
.keys()
.filter(|&key| key.ty.id == type_id)
.map(|key| key.name.clone())
.collect()
}
}
#[derive(Clone, Copy)]
enum Behaviour {
CreateThenReturnSingletonOrTransient,
JustCreateAllScopeForEagerCreate,
JustCreateSingletonOrSingleOwner,
}
enum Resolved<T> {
NotFoundProvider(Key),
SingletonOrTransient(T),
NotSingletonOrTransient(Definition),
NoReturn,
NotSingletonOrSingleOwner(Definition),
}
struct Holder<'a, T> {
key: Key,
constructor: Constructor<T>,
clone_instance: Option<fn(&T) -> T>,
definition: &'a Definition,
}
#[inline(always)]
fn no_provider_panic(key: Key) -> ! {
panic!("no provider registered for: {:?}", key)
}
#[inline(always)]
fn not_singleton_or_single_owner_panic(definition: Definition) -> ! {
panic!(
"registered provider is not `Singleton` or `SingleOwner` for: {:?}",
definition
)
}
#[inline(always)]
fn not_singleton_or_transient_panic(definition: Definition) -> ! {
panic!(
"registered provider is not `Singleton` or `Transient` for: {:?}",
definition
)
}
fn flatten<T, F>(mut unresolved: Vec<T>, get_sublist: F) -> Vec<T>
where
F: Fn(&mut T) -> Option<Vec<T>>,
{
debug_assert!(!unresolved.is_empty());
let mut resolved = Vec::with_capacity(unresolved.len());
unresolved.reverse();
while let Some(mut element) = unresolved.pop() {
match get_sublist(&mut element) {
Some(mut sublist) if !sublist.is_empty() => {
sublist.reverse();
unresolved.append(&mut sublist);
}
_ => {}
}
resolved.push(element);
}
resolved
}
pub struct ContextOptions {
allow_override: bool,
allow_only_single_eager_create: bool,
eager_create: bool,
providers: Vec<DynProvider>,
singles: Vec<DynSingle>,
}
impl Default for ContextOptions {
fn default() -> Self {
Self {
allow_override: true,
allow_only_single_eager_create: true,
eager_create: Default::default(),
providers: Default::default(),
singles: Default::default(),
}
}
}
impl ContextOptions {
pub fn allow_override(mut self, allow_override: bool) -> Self {
self.allow_override = allow_override;
self
}
pub fn allow_only_single_eager_create(mut self, allow_only_single_eager_create: bool) -> Self {
self.allow_only_single_eager_create = allow_only_single_eager_create;
self
}
pub fn eager_create(mut self, eager_create: bool) -> Self {
self.eager_create = eager_create;
self
}
pub fn singleton<T>(self, instance: T) -> Self
where
T: 'static + Clone,
{
self.singleton_with_name(instance, "")
}
pub fn singleton_with_name<T, N>(mut self, instance: T, name: N) -> Self
where
T: 'static + Clone,
N: Into<Cow<'static, str>>,
{
let provider = Provider::<T>::never_construct(name.into(), Scope::Singleton).into();
let single = Single::new(instance, Some(Clone::clone)).into();
self.providers.push(provider);
self.singles.push(single);
self
}
pub fn single_owner<T>(self, instance: T) -> Self
where
T: 'static,
{
self.single_owner_with_name(instance, "")
}
pub fn single_owner_with_name<T, N>(mut self, instance: T, name: N) -> Self
where
T: 'static,
N: Into<Cow<'static, str>>,
{
let provider = Provider::<T>::never_construct(name.into(), Scope::SingleOwner).into();
let single = Single::new(instance, None).into();
self.providers.push(provider);
self.singles.push(single);
self
}
#[track_caller]
fn inner_create<F>(self, init: F) -> Context
where
F: FnOnce(&mut Context),
{
let ContextOptions {
allow_override,
allow_only_single_eager_create,
eager_create,
providers,
singles,
} = self;
let mut cx = Context {
allow_override,
allow_only_single_eager_create,
eager_create,
..Default::default()
};
if !providers.is_empty() {
providers
.into_iter()
.zip(singles)
.for_each(|(provider, single)| {
let key = provider.key().clone();
cx.provider_registry.insert(provider, allow_override);
cx.single_registry.insert(key, single);
});
}
init(&mut cx);
cx
}
#[track_caller]
fn inner_create_with_modules(self, modules: Vec<ResolveModule>) -> Context {
self.inner_create(|cx| cx.load_modules(modules))
}
#[cfg(feature = "auto-register")]
#[track_caller]
fn inner_create_with_auto(self) -> Context {
use crate::AutoRegisterModule;
self.inner_create(|cx| {
let module = ResolveModule::new::<AutoRegisterModule>();
cx.loaded_modules.push(module.ty());
cx.load_providers(module.eager_create(), module.providers())
})
}
#[track_caller]
pub fn create(self, modules: Vec<ResolveModule>) -> Context {
let mut cx = self.inner_create_with_modules(modules);
cx.flush();
cx
}
#[cfg_attr(docsrs, doc(cfg(feature = "auto-register")))]
#[cfg(feature = "auto-register")]
#[track_caller]
pub fn auto_register(self) -> Context {
let mut cx = self.inner_create_with_auto();
cx.flush();
cx
}
pub async fn create_async(self, modules: Vec<ResolveModule>) -> Context {
let mut cx = self.inner_create_with_modules(modules);
cx.flush_async().await;
cx
}
#[cfg_attr(docsrs, doc(cfg(feature = "auto-register")))]
#[cfg(feature = "auto-register")]
pub async fn auto_register_async(self) -> Context {
let mut cx = self.inner_create_with_auto();
cx.flush_async().await;
cx
}
}
#[derive(Default)]
struct DependencyChain {
stack: Vec<Key>,
}
impl DependencyChain {
fn push(&mut self, key: Key) {
let already_contains = self.stack.contains(&key);
self.stack.push(key);
if already_contains {
let key = self.stack.last().unwrap();
let mut buf = String::with_capacity(1024);
buf.push('[');
buf.push('\n');
self.stack.iter().for_each(|k| {
if key == k {
buf.push_str(" --> ")
} else {
buf.push_str(" ")
}
buf.push_str(format!("{:?}", k).as_str());
buf.push('\n');
});
buf.push(']');
panic!("circular dependency detected: {}", buf);
}
}
fn pop(&mut self) {
self.stack.pop();
}
}