1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
#![feature(unsize)]
#![feature(min_specialization)]
//! Runtime dependency injection.
//!
//! Documentation is under construction!
//!
//! # Examples
//!
//! ## Basic dependency resolution
//!
//! As a user of type `A` we only care about getting an instance to use - the
//! life-cycle of `A` and its dependencies remain hidden from us.
//!
//! ```
//! use dill::*;
//! use std::sync::Arc;
//!
//! #[component]
//! struct A {
//! b: Arc<B>, // An instance of `B` will be resolved and injected when requesting `A`
//! }
//!
//! impl A {
//! fn foo(&self) -> String {
//! format!("a::{}", self.b.bar())
//! }
//! }
//!
//! #[component]
//! struct B;
//!
//! impl B {
//! fn bar(&self) -> String {
//! format!("b")
//! }
//! }
//!
//! let catalog = CatalogBuilder::new()
//! .add::<A>()
//! .add::<B>()
//! .build();
//!
//! let a = catalog.get_one::<A>().unwrap();
//! assert_eq!(a.foo(), "a::b");
//! ```
//!
//! ## Using trait objects (aka Interfaces)
//!
//! Every type can be associated with multiple traits that it implements using
//! [`CatalogBuilder::bind()`] method, allowing dynamically picking best
//! implementation to use (e.g. based on config) or even using multiple
//! implementations at once (e.g. plugins).
//!
//! ```
//! use dill::*;
//! use std::sync::Arc;
//!
//! // An interface that has two implementations below
//! trait A: Send + Sync {
//! fn foo(&self) -> String;
//! }
//!
//! #[component]
//! struct AImpl1;
//! impl A for AImpl1 {
//! fn foo(&self) -> String {
//! format!("aimpl1")
//! }
//! }
//!
//! #[component]
//! struct AImpl2;
//! impl A for AImpl2 {
//! fn foo(&self) -> String {
//! format!("aimpl2")
//! }
//! }
//!
//! let catalog = CatalogBuilder::new()
//! .add::<AImpl1>()
//! .bind::<dyn A, AImpl1>()
//! .add::<AImpl2>()
//! .bind::<dyn A, AImpl2>()
//! .build();
//!
//! // AllOf<T> is a DependencySpec that returns instances of all types that implement trait T
//! let ays = catalog.get::<AllOf<dyn A>>().unwrap();
//!
//! let mut foos: Vec<_> = ays.iter().map(|a| a.foo()).collect();
//! foos.sort(); // Order is undefined
//!
//! assert_eq!(foos, vec!["aimpl1".to_owned(), "aimpl2".to_owned()]);
//! ```
//!
//! ## Controlling lifetimes with Scopes
//!
//! The life-cycle of a type is no longer controlled by the user of a type.
//! Author of type `A` below can choose whether `A` should be created per call
//! ([`Transient`]) or reused by all clients ([`Singleton`]).
//!
//! ```
//! use dill::*;
//!
//! #[component]
//! #[scope(Singleton)]
//! struct A {
//! // Needed for compiler not to optimize type out
//! name: String,
//! }
//!
//! impl A {
//! fn test(&self) -> String {
//! format!("a::{}", self.name)
//! }
//! }
//!
//! let cat = CatalogBuilder::new()
//! .add::<A>()
//! .add_value("foo".to_owned())
//! .build();
//!
//! let inst1 = cat.get::<OneOf<A>>().unwrap();
//! let inst2 = cat.get::<OneOf<A>>().unwrap();
//!
//! // Expecting Singleton scope to return same instance
//! assert_eq!(
//! inst1.as_ref() as *const A,
//! inst2.as_ref() as *const A
//! );
//! ```
//!
//! ## Parametrizing builders
//!
//! Builders can be parametrized during the registration process for convenience
//! (e.g. with values read from configuration).
//!
//! ```
//! use dill::*;
//!
//! #[component]
//! #[scope(Singleton)]
//! struct ConnectionPool {
//! host: String,
//! port: i32,
//! }
//!
//! impl ConnectionPool {
//! fn url(&self) -> String {
//! format!("http://{}:{}", self.host, self.port)
//! }
//! }
//!
//! let cat = CatalogBuilder::new()
//! .add_builder(
//! ConnectionPool::builder()
//! .with_host("foo".to_owned())
//! .with_port(8080),
//! )
//! .build();
//!
//! let inst = cat.get::<OneOf<ConnectionPool>>().unwrap();
//! assert_eq!(inst.url(), "http://foo:8080");
//! ```
pub use dill_impl::*;
mod builder;
pub use builder::*;
mod catalog_builder;
pub use catalog_builder::*;
mod catalog;
pub use catalog::*;
mod errors;
pub use errors::*;
mod specs;
pub use specs::*;
mod scopes;
pub use scopes::*;
mod typecast_builder;
pub use typecast_builder::*;