mod container;
mod inject;
mod provider;
mod types;
use cfg_block::cfg_block;
pub use container::{Container, ContainerBuilder};
pub use inject::Injectable;
pub use provider::{CloneProvider, CopyProvider, Provider, cloned, copied};
pub use types::SyncBounds;
#[macro_export]
macro_rules! container {
(@replace_expr $_expr:expr, $sub:expr) => {
$sub
};
(@count_exprs $( $expr:expr ),* $(,)?) => {
<[()]>::len(&[$($crate::container!(@replace_expr $expr, ())),*])
};
(providers: [$( $provider:expr ),* $(,)?] $(,)?) => {{
$crate::Container::builder_with_capacity(
$crate::container!(@count_exprs $($provider),*),
)
$(.provider($provider))*
.build()
}};
}
cfg_block! {
if #[cfg(feature = "validation")] {
pub use container::DeclaredDependency;
pub use inventory;
#[macro_export]
macro_rules! declare_dependency {
($ty:ty) => {
$crate::inventory::submit! {
$crate::DeclaredDependency {
type_id: ::std::any::TypeId::of::<$ty>,
type_name: ::std::stringify!($ty),
}
}
};
}
} else {
#[macro_export]
macro_rules! declare_dependency {
($ty:ty) => {};
}
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use crate::{Container, cloned, copied};
#[test]
fn empty_providers() {
let c = container! {
providers: []
};
assert_eq!(c.provider_count(), 0);
}
#[test]
fn only_closure_providers() {
let c = container! {
providers: [|_c: &Container| 1_u32, |_c: &Container| 2_u64]
};
assert_eq!(c.provider_count(), 2);
}
#[test]
fn cloned_and_closure_providers() {
let c = container! {
providers: [
cloned(41_u16),
|_c: &Container| 42_u32,
|_c: &Container| "hello",
]
};
assert_eq!(c.provider_count(), 3);
}
#[test]
fn providers_with_trailing_comma() {
let c = container! {
providers: [Arc::new(1_u32), |_c: &Container| 2_u64,]
};
assert_eq!(c.provider_count(), 2);
}
#[test]
fn only_providers_empty() {
let c = container! {
providers: []
};
assert_eq!(c.provider_count(), 0);
}
#[test]
fn get_from_arc_and_closure_providers() {
let c = container! {
providers: [Arc::new(1_u32), |_c: &Container| 99_u64]
};
assert_eq!(c.provider_count(), 2);
assert_eq!(*c.get::<Arc<u32>>(), 1);
assert_eq!(c.get::<u64>(), 99);
}
#[test]
fn with_capacity_builder() {
let c = Container::builder_with_capacity(3)
.provider(Arc::new(1_u32))
.provider(|_c: &Container| 2_u64)
.provider(|_c: &Container| 3_u8)
.build();
assert_eq!(c.provider_count(), 3);
assert_eq!(c.get::<u8>(), 3);
}
#[test]
fn get_clones_explicit_clone_providers() {
let c = container! { providers: [cloned(String::from("shared"))] };
assert_eq!(c.get::<String>(), "shared");
}
#[test]
fn get_copies_explicit_copy_providers() {
let c = container! { providers: [copied(7_u32)] };
assert_eq!(c.get::<u32>(), 7);
}
#[test]
fn get_executes_closure_providers() {
let c = container! {
providers: [|_c: &Container| String::from("factory")]
};
assert_eq!(c.get::<String>(), "factory");
}
#[test]
fn builder_contains_registered_output_type() {
let builder = Container::builder().provider(Arc::new(String::from("shared")));
assert!(builder.contains::<Arc<String>>());
assert!(builder.contains_provider::<Arc<String>>());
assert!(!builder.contains::<u32>());
}
#[test]
#[should_panic(
expected = "provider already registered for `alloc::sync::Arc<alloc::string::String>`"
)]
fn duplicate_arc_provider_panics() {
let _ = Container::builder()
.provider(Arc::new(String::from("first")))
.provider(Arc::new(String::from("second")));
}
#[test]
#[should_panic(
expected = "provider already registered for `alloc::sync::Arc<alloc::string::String>`"
)]
fn closure_and_arc_provider_conflict_panics() {
let _ = Container::builder()
.provider(Arc::new(String::from("shared")))
.provider(|_c: &Container| Arc::new(String::from("factory")));
}
#[test]
#[should_panic(expected = "provider already registered for `alloc::string::String`")]
fn duplicate_closure_provider_panics() {
let _ = Container::builder()
.provider(|_c: &Container| String::from("first"))
.provider(|_c: &Container| String::from("second"));
}
}