From ca86952c1486b7f2313fef62e6cacf36e248efd2 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sat, 13 Jul 2024 16:26:28 +0200 Subject: refactor: move & rename all mod.rs files --- examples/async/animals.rs | 3 + examples/async/animals/mod.rs | 3 - examples/async/interfaces.rs | 4 + examples/async/interfaces/mod.rs | 4 - examples/basic/animals.rs | 3 + examples/basic/animals/mod.rs | 3 - examples/basic/interfaces.rs | 3 + examples/basic/interfaces/mod.rs | 3 - examples/factory/interfaces.rs | 2 + examples/factory/interfaces/mod.rs | 2 - examples/generics/interfaces.rs | 1 + examples/generics/interfaces/mod.rs | 1 - examples/named/interfaces.rs | 2 + examples/named/interfaces/mod.rs | 2 - examples/with-3rd-party/interfaces.rs | 1 + examples/with-3rd-party/interfaces/mod.rs | 1 - macros/src/injectable.rs | 5 + macros/src/injectable/mod.rs | 5 - macros/src/util.rs | 67 +++ macros/src/util/mod.rs | 67 --- src/castable_function.rs | 93 +++ src/castable_function/mod.rs | 93 --- src/di_container.rs | 43 ++ src/di_container/asynchronous.rs | 839 +++++++++++++++++++++++++++ src/di_container/asynchronous/binding.rs | 5 + src/di_container/asynchronous/binding/mod.rs | 5 - src/di_container/asynchronous/mod.rs | 839 --------------------------- src/di_container/blocking.rs | 722 +++++++++++++++++++++++ src/di_container/blocking/binding.rs | 5 + src/di_container/blocking/binding/mod.rs | 5 - src/di_container/blocking/mod.rs | 722 ----------------------- src/di_container/mod.rs | 43 -- src/errors.rs | 9 + src/errors/mod.rs | 9 - src/interfaces.rs | 7 + src/interfaces/mod.rs | 7 - src/private.rs | 6 + src/private/cast.rs | 273 +++++++++ src/private/cast/mod.rs | 273 --------- src/private/mod.rs | 6 - src/provider.rs | 4 + src/provider/mod.rs | 4 - 42 files changed, 2097 insertions(+), 2097 deletions(-) create mode 100644 examples/async/animals.rs delete mode 100644 examples/async/animals/mod.rs create mode 100644 examples/async/interfaces.rs delete mode 100644 examples/async/interfaces/mod.rs create mode 100644 examples/basic/animals.rs delete mode 100644 examples/basic/animals/mod.rs create mode 100644 examples/basic/interfaces.rs delete mode 100644 examples/basic/interfaces/mod.rs create mode 100644 examples/factory/interfaces.rs delete mode 100644 examples/factory/interfaces/mod.rs create mode 100644 examples/generics/interfaces.rs delete mode 100644 examples/generics/interfaces/mod.rs create mode 100644 examples/named/interfaces.rs delete mode 100644 examples/named/interfaces/mod.rs create mode 100644 examples/with-3rd-party/interfaces.rs delete mode 100644 examples/with-3rd-party/interfaces/mod.rs create mode 100644 macros/src/injectable.rs delete mode 100644 macros/src/injectable/mod.rs create mode 100644 macros/src/util.rs delete mode 100644 macros/src/util/mod.rs create mode 100644 src/castable_function.rs delete mode 100644 src/castable_function/mod.rs create mode 100644 src/di_container.rs create mode 100644 src/di_container/asynchronous.rs create mode 100644 src/di_container/asynchronous/binding.rs delete mode 100644 src/di_container/asynchronous/binding/mod.rs delete mode 100644 src/di_container/asynchronous/mod.rs create mode 100644 src/di_container/blocking.rs create mode 100644 src/di_container/blocking/binding.rs delete mode 100644 src/di_container/blocking/binding/mod.rs delete mode 100644 src/di_container/blocking/mod.rs delete mode 100644 src/di_container/mod.rs create mode 100644 src/errors.rs delete mode 100644 src/errors/mod.rs create mode 100644 src/interfaces.rs delete mode 100644 src/interfaces/mod.rs create mode 100644 src/private.rs create mode 100644 src/private/cast.rs delete mode 100644 src/private/cast/mod.rs delete mode 100644 src/private/mod.rs create mode 100644 src/provider.rs delete mode 100644 src/provider/mod.rs diff --git a/examples/async/animals.rs b/examples/async/animals.rs new file mode 100644 index 0000000..5444978 --- /dev/null +++ b/examples/async/animals.rs @@ -0,0 +1,3 @@ +pub mod cat; +pub mod dog; +pub mod human; diff --git a/examples/async/animals/mod.rs b/examples/async/animals/mod.rs deleted file mode 100644 index 5444978..0000000 --- a/examples/async/animals/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod cat; -pub mod dog; -pub mod human; diff --git a/examples/async/interfaces.rs b/examples/async/interfaces.rs new file mode 100644 index 0000000..ea0a26d --- /dev/null +++ b/examples/async/interfaces.rs @@ -0,0 +1,4 @@ +pub mod cat; +pub mod dog; +pub mod food; +pub mod human; diff --git a/examples/async/interfaces/mod.rs b/examples/async/interfaces/mod.rs deleted file mode 100644 index ea0a26d..0000000 --- a/examples/async/interfaces/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod cat; -pub mod dog; -pub mod food; -pub mod human; diff --git a/examples/basic/animals.rs b/examples/basic/animals.rs new file mode 100644 index 0000000..5444978 --- /dev/null +++ b/examples/basic/animals.rs @@ -0,0 +1,3 @@ +pub mod cat; +pub mod dog; +pub mod human; diff --git a/examples/basic/animals/mod.rs b/examples/basic/animals/mod.rs deleted file mode 100644 index 5444978..0000000 --- a/examples/basic/animals/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod cat; -pub mod dog; -pub mod human; diff --git a/examples/basic/interfaces.rs b/examples/basic/interfaces.rs new file mode 100644 index 0000000..5444978 --- /dev/null +++ b/examples/basic/interfaces.rs @@ -0,0 +1,3 @@ +pub mod cat; +pub mod dog; +pub mod human; diff --git a/examples/basic/interfaces/mod.rs b/examples/basic/interfaces/mod.rs deleted file mode 100644 index 5444978..0000000 --- a/examples/basic/interfaces/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod cat; -pub mod dog; -pub mod human; diff --git a/examples/factory/interfaces.rs b/examples/factory/interfaces.rs new file mode 100644 index 0000000..2342750 --- /dev/null +++ b/examples/factory/interfaces.rs @@ -0,0 +1,2 @@ +pub mod user; +pub mod user_manager; diff --git a/examples/factory/interfaces/mod.rs b/examples/factory/interfaces/mod.rs deleted file mode 100644 index 2342750..0000000 --- a/examples/factory/interfaces/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod user; -pub mod user_manager; diff --git a/examples/generics/interfaces.rs b/examples/generics/interfaces.rs new file mode 100644 index 0000000..3f31bdf --- /dev/null +++ b/examples/generics/interfaces.rs @@ -0,0 +1 @@ +pub mod printer; diff --git a/examples/generics/interfaces/mod.rs b/examples/generics/interfaces/mod.rs deleted file mode 100644 index 3f31bdf..0000000 --- a/examples/generics/interfaces/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod printer; diff --git a/examples/named/interfaces.rs b/examples/named/interfaces.rs new file mode 100644 index 0000000..6a0108d --- /dev/null +++ b/examples/named/interfaces.rs @@ -0,0 +1,2 @@ +pub mod ninja; +pub mod weapon; diff --git a/examples/named/interfaces/mod.rs b/examples/named/interfaces/mod.rs deleted file mode 100644 index 6a0108d..0000000 --- a/examples/named/interfaces/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod ninja; -pub mod weapon; diff --git a/examples/with-3rd-party/interfaces.rs b/examples/with-3rd-party/interfaces.rs new file mode 100644 index 0000000..c060c34 --- /dev/null +++ b/examples/with-3rd-party/interfaces.rs @@ -0,0 +1 @@ +pub mod ninja; diff --git a/examples/with-3rd-party/interfaces/mod.rs b/examples/with-3rd-party/interfaces/mod.rs deleted file mode 100644 index c060c34..0000000 --- a/examples/with-3rd-party/interfaces/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod ninja; diff --git a/macros/src/injectable.rs b/macros/src/injectable.rs new file mode 100644 index 0000000..0e6ddfd --- /dev/null +++ b/macros/src/injectable.rs @@ -0,0 +1,5 @@ +pub mod dependency; +pub mod dummy; +pub mod implementation; +pub mod macro_args; +pub mod named_attr_input; diff --git a/macros/src/injectable/mod.rs b/macros/src/injectable/mod.rs deleted file mode 100644 index 0e6ddfd..0000000 --- a/macros/src/injectable/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod dependency; -pub mod dummy; -pub mod implementation; -pub mod macro_args; -pub mod named_attr_input; diff --git a/macros/src/util.rs b/macros/src/util.rs new file mode 100644 index 0000000..3557896 --- /dev/null +++ b/macros/src/util.rs @@ -0,0 +1,67 @@ +pub mod error; +pub mod item_impl; +pub mod iterator_ext; +pub mod string; +pub mod syn_ext; +pub mod syn_path; +pub mod tokens; + +macro_rules! to_option { + ($($tokens: tt)+) => { + Some($($tokens)+) + }; + + () => { + None + }; +} + +macro_rules! or { + (($($tokens: tt)+) else ($($default: tt)*)) => { + $($tokens)* + }; + + (() else ($($default: tt)*)) => { + $($default)* + }; +} + +/// Imports the specified item, prepending 'Mock' to the item identifier if the `test` +/// configuration option is set. +/// +/// # Examples +/// ```ignore +/// use_double!(crate::dependency_history::DependencyHistory); +/// ``` +///
+/// +/// Expands to the following when `cfg(not(test))` +/// ```ignore +/// use crate::dependency_history::DependencyHistory; +/// ``` +///
+/// +/// Expands to the following when `cfg(test)` +/// ```ignore +/// use crate::dependency_history::MockDependencyHistory as DependencyHistory; +/// ``` +macro_rules! use_double { + ($([$($part: ident),*])? $item_path_part: ident :: $($next_part: tt)+) => { + use_double!( + [$($($part,)*)? $item_path_part] + $($next_part)+ + ); + }; + + ([$($part: ident),*] $item_path_part: ident) => { + #[cfg(not(test))] + use $($part::)* $item_path_part; + + ::paste::paste! { + #[cfg(test)] + use $($part::)* [] as $item_path_part; + } + }; +} + +pub(crate) use {or, to_option, use_double}; diff --git a/macros/src/util/mod.rs b/macros/src/util/mod.rs deleted file mode 100644 index 3557896..0000000 --- a/macros/src/util/mod.rs +++ /dev/null @@ -1,67 +0,0 @@ -pub mod error; -pub mod item_impl; -pub mod iterator_ext; -pub mod string; -pub mod syn_ext; -pub mod syn_path; -pub mod tokens; - -macro_rules! to_option { - ($($tokens: tt)+) => { - Some($($tokens)+) - }; - - () => { - None - }; -} - -macro_rules! or { - (($($tokens: tt)+) else ($($default: tt)*)) => { - $($tokens)* - }; - - (() else ($($default: tt)*)) => { - $($default)* - }; -} - -/// Imports the specified item, prepending 'Mock' to the item identifier if the `test` -/// configuration option is set. -/// -/// # Examples -/// ```ignore -/// use_double!(crate::dependency_history::DependencyHistory); -/// ``` -///
-/// -/// Expands to the following when `cfg(not(test))` -/// ```ignore -/// use crate::dependency_history::DependencyHistory; -/// ``` -///
-/// -/// Expands to the following when `cfg(test)` -/// ```ignore -/// use crate::dependency_history::MockDependencyHistory as DependencyHistory; -/// ``` -macro_rules! use_double { - ($([$($part: ident),*])? $item_path_part: ident :: $($next_part: tt)+) => { - use_double!( - [$($($part,)*)? $item_path_part] - $($next_part)+ - ); - }; - - ([$($part: ident),*] $item_path_part: ident) => { - #[cfg(not(test))] - use $($part::)* $item_path_part; - - ::paste::paste! { - #[cfg(test)] - use $($part::)* [] as $item_path_part; - } - }; -} - -pub(crate) use {or, to_option, use_double}; diff --git a/src/castable_function.rs b/src/castable_function.rs new file mode 100644 index 0000000..4c2f0db --- /dev/null +++ b/src/castable_function.rs @@ -0,0 +1,93 @@ +use std::any::{type_name, Any}; +use std::fmt::Debug; + +use crate::ptr::TransientPtr; + +#[cfg(feature = "async")] +pub mod threadsafe; + +/// Interface for any castable function. +pub trait AnyCastableFunction: Any + Debug +{ + fn as_any(&self) -> &dyn Any; +} + +pub struct CastableFunction +where + ReturnInterface: 'static + ?Sized, + DIContainerT: 'static, +{ + func: &'static dyn Fn(&DIContainerT) -> TransientPtr, +} + +impl CastableFunction +where + ReturnInterface: 'static + ?Sized, +{ + pub fn new( + func: &'static dyn Fn(&DIContainerT) -> TransientPtr, + ) -> Self + { + Self { func } + } + + pub fn call(&self, di_container: &DIContainerT) -> TransientPtr + { + (self.func)(di_container) + } +} + +impl AnyCastableFunction + for CastableFunction +where + ReturnInterface: 'static + ?Sized, + DIContainerT: 'static, +{ + fn as_any(&self) -> &dyn Any + { + self + } +} + +impl Debug + for CastableFunction +where + ReturnInterface: 'static + ?Sized, +{ + #[cfg(not(tarpaulin_include))] + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result + { + let ret = type_name::>(); + + formatter.write_fmt(format_args!( + "CastableFunction (&DIContainer) -> {ret} {{ ... }}" + )) + } +} + +#[cfg(test)] +mod tests +{ + use super::*; + use crate::di_container::blocking::MockDIContainer; + + #[derive(Debug, PartialEq, Eq)] + struct Bacon + { + heal_amount: u32, + } + + #[test] + fn can_call() + { + let castable_func = CastableFunction::new(&|_: &MockDIContainer| { + TransientPtr::new(Bacon { heal_amount: 27 }) + }); + + let mock_di_container = MockDIContainer::new(); + + let output = castable_func.call(&mock_di_container); + + assert_eq!(output, TransientPtr::new(Bacon { heal_amount: 27 })); + } +} diff --git a/src/castable_function/mod.rs b/src/castable_function/mod.rs deleted file mode 100644 index 4c2f0db..0000000 --- a/src/castable_function/mod.rs +++ /dev/null @@ -1,93 +0,0 @@ -use std::any::{type_name, Any}; -use std::fmt::Debug; - -use crate::ptr::TransientPtr; - -#[cfg(feature = "async")] -pub mod threadsafe; - -/// Interface for any castable function. -pub trait AnyCastableFunction: Any + Debug -{ - fn as_any(&self) -> &dyn Any; -} - -pub struct CastableFunction -where - ReturnInterface: 'static + ?Sized, - DIContainerT: 'static, -{ - func: &'static dyn Fn(&DIContainerT) -> TransientPtr, -} - -impl CastableFunction -where - ReturnInterface: 'static + ?Sized, -{ - pub fn new( - func: &'static dyn Fn(&DIContainerT) -> TransientPtr, - ) -> Self - { - Self { func } - } - - pub fn call(&self, di_container: &DIContainerT) -> TransientPtr - { - (self.func)(di_container) - } -} - -impl AnyCastableFunction - for CastableFunction -where - ReturnInterface: 'static + ?Sized, - DIContainerT: 'static, -{ - fn as_any(&self) -> &dyn Any - { - self - } -} - -impl Debug - for CastableFunction -where - ReturnInterface: 'static + ?Sized, -{ - #[cfg(not(tarpaulin_include))] - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result - { - let ret = type_name::>(); - - formatter.write_fmt(format_args!( - "CastableFunction (&DIContainer) -> {ret} {{ ... }}" - )) - } -} - -#[cfg(test)] -mod tests -{ - use super::*; - use crate::di_container::blocking::MockDIContainer; - - #[derive(Debug, PartialEq, Eq)] - struct Bacon - { - heal_amount: u32, - } - - #[test] - fn can_call() - { - let castable_func = CastableFunction::new(&|_: &MockDIContainer| { - TransientPtr::new(Bacon { heal_amount: 27 }) - }); - - let mock_di_container = MockDIContainer::new(); - - let output = castable_func.call(&mock_di_container); - - assert_eq!(output, TransientPtr::new(Bacon { heal_amount: 27 })); - } -} diff --git a/src/di_container.rs b/src/di_container.rs new file mode 100644 index 0000000..4e60505 --- /dev/null +++ b/src/di_container.rs @@ -0,0 +1,43 @@ +//! Dependency injection container types. + +#[cfg(feature = "async")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "async")))] +pub mod asynchronous; + +pub mod blocking; + +/// DI container binding options. +/// +/// # Examples +/// ``` +/// # use syrette::di_container::BindingOptions; +/// # +/// BindingOptions::new().name("foo"); +/// ``` +#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)] +pub struct BindingOptions<'a> +{ + name: Option<&'a str>, +} + +impl<'a> BindingOptions<'a> +{ + /// Returns a new `BindingOptions`. + #[must_use] + pub const fn new() -> Self + { + Self { name: None } + } + + /// Returns `Self` with the specified name set. + #[must_use] + pub const fn name(mut self, name: &'a str) -> Self + { + self.name = Some(name); + + self + } +} + +// Private. +pub(crate) mod binding_storage; diff --git a/src/di_container/asynchronous.rs b/src/di_container/asynchronous.rs new file mode 100644 index 0000000..c993b8b --- /dev/null +++ b/src/di_container/asynchronous.rs @@ -0,0 +1,839 @@ +//! Asynchronous dependency injection container. +//! +//! # Examples +//! ``` +//! use std::collections::HashMap; +//! use std::error::Error; +//! +//! use syrette::{injectable, AsyncDIContainer}; +//! +//! trait IDatabaseService: Send + Sync +//! { +//! fn get_all_records(&self, table_name: String) -> HashMap; +//! } +//! +//! struct DatabaseService {} +//! +//! #[injectable(IDatabaseService, async = true)] +//! impl DatabaseService +//! { +//! fn new() -> Self +//! { +//! Self {} +//! } +//! } +//! +//! impl IDatabaseService for DatabaseService +//! { +//! fn get_all_records(&self, table_name: String) -> HashMap +//! { +//! // Do stuff here +//! HashMap::::new() +//! } +//! } +//! +//! #[tokio::main] +//! async fn main() -> Result<(), Box> +//! { +//! let mut di_container = AsyncDIContainer::new(); +//! +//! di_container +//! .bind::() +//! .to::()?; +//! +//! let database_service = di_container +//! .get::() +//! .await? +//! .transient()?; +//! +//! Ok(()) +//! } +//! ``` +use std::any::type_name; + +use crate::di_container::asynchronous::binding::builder::AsyncBindingBuilder; +use crate::di_container::binding_storage::DIContainerBindingStorage; +use crate::di_container::BindingOptions; +use crate::errors::async_di_container::AsyncDIContainerError; +use crate::private::cast::arc::CastArc; +use crate::private::cast::boxed::CastBox; +use crate::private::cast::error::CastError; +use crate::provider::r#async::{AsyncProvidable, IAsyncProvider}; +use crate::ptr::SomePtr; +use crate::util::use_double; + +use_double!(crate::dependency_history::DependencyHistory); + +pub mod binding; + +/// Async dependency injection container. +#[derive(Default)] +pub struct AsyncDIContainer +{ + binding_storage: DIContainerBindingStorage>, +} + +impl AsyncDIContainer +{ + /// Returns a new `AsyncDIContainer`. + #[must_use] + pub fn new() -> Self + { + Self { + binding_storage: DIContainerBindingStorage::new(), + } + } +} + +#[cfg_attr(test, mockall::automock)] +impl AsyncDIContainer +{ + /// Returns a new [`AsyncBindingBuilder`] for the given interface. + /// + /// # Examples + /// ``` + /// # use syrette::{AsyncDIContainer, injectable}; + /// # + /// # struct DiskWriter {} + /// # + /// # #[injectable(async = true)] + /// # impl DiskWriter + /// # { + /// # fn new() -> Self + /// # { + /// # Self {} + /// # } + /// # } + /// # + /// # #[tokio::main] + /// # async fn main() -> Result<(), Box> { + /// let mut di_container = AsyncDIContainer::new(); + /// + /// di_container.bind::().to::()?; + /// # + /// # Ok(()) + /// # } + /// ``` + #[allow(clippy::missing_panics_doc)] + pub fn bind(&mut self) -> AsyncBindingBuilder<'_, Interface> + where + Interface: 'static + ?Sized + Send + Sync, + { + #[cfg(test)] + panic!("Bind function is unusable when testing"); + + #[cfg(not(test))] + AsyncBindingBuilder::new(self, DependencyHistory::new) + } + + /// Returns the type bound with `Interface`. + /// + /// # Errors + /// Will return `Err` if: + /// - No binding for `Interface` exists + /// - Resolving the binding for `Interface` fails + /// - Casting the binding for `Interface` fails + /// + /// # Examples + /// ``` + /// # use syrette::{AsyncDIContainer, injectable}; + /// # + /// # struct DeviceManager {} + /// # + /// # #[injectable(async = true)] + /// # impl DeviceManager + /// # { + /// # fn new() -> Self + /// # { + /// # Self {} + /// # } + /// # } + /// # + /// # #[tokio::main] + /// # async fn main() -> Result<(), Box> { + /// let mut di_container = AsyncDIContainer::new(); + /// + /// di_container.bind::().to::()?; + /// + /// let device_manager = di_container.get::().await?.transient(); + /// # + /// # Ok(()) + /// # } + /// ``` + pub async fn get( + &self, + ) -> Result, AsyncDIContainerError> + where + Interface: 'static + ?Sized + Send + Sync, + { + self.get_bound::(DependencyHistory::new(), BindingOptions::new()) + .await + } + + /// Returns the type bound with `Interface` and the specified name. + /// + /// # Errors + /// Will return `Err` if: + /// - No binding for `Interface` with name `name` exists + /// - Resolving the binding for `Interface` fails + /// - Casting the binding for `Interface` fails + /// + /// # Examples + /// ``` + /// # use syrette::{AsyncDIContainer, injectable}; + /// # + /// # struct DeviceManager {} + /// # + /// # #[injectable(async = true)] + /// # impl DeviceManager + /// # { + /// # fn new() -> Self + /// # { + /// # Self {} + /// # } + /// # } + /// # + /// # #[tokio::main] + /// # async fn main() -> Result<(), Box> { + /// let mut di_container = AsyncDIContainer::new(); + /// + /// di_container + /// .bind::() + /// .to::()? + /// .in_transient_scope() + /// .when_named("usb"); + /// + /// let device_manager = di_container + /// .get_named::("usb") + /// .await? + /// .transient(); + /// # + /// # Ok(()) + /// # } + /// ``` + pub async fn get_named( + &self, + name: &'static str, + ) -> Result, AsyncDIContainerError> + where + Interface: 'static + ?Sized + Send + Sync, + { + self.get_bound::( + DependencyHistory::new(), + BindingOptions::new().name(name), + ) + .await + } + + /// Returns the type bound with `Interface` where the binding has the specified + /// options. + /// + /// `dependency_history` is passed to the bound type when it is being resolved. + /// + /// # Errors + /// Will return `Err` if: + /// - No binding for `Interface` exists + /// - Resolving the binding for `Interface` fails + /// - Casting the binding for `Interface` fails + /// + /// # Examples + /// ``` + /// # use syrette::di_container::asynchronous::AsyncDIContainer; + /// # use syrette::dependency_history::DependencyHistory; + /// # use syrette::di_container::BindingOptions; + /// # + /// # struct EventHandler {} + /// # struct Button {} + /// # + /// # Box::pin(async { + /// # let di_container = AsyncDIContainer::new(); + /// # + /// let mut dependency_history = DependencyHistory::new(); + /// + /// dependency_history.push::(); + /// + /// di_container + /// .get_bound::