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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
//! Manager for dependencies between objects for the Rust language.
//!
//! # How to use
//!
//! The main type of this crate is the [`ServiceContainer`]. There are multiple
//! ways to initialize the container. See the documentation on ServiceContainer
//! for more information. The easiest way is with `new()`.
//!
//! ```rust
//! use rscontainer::ServiceContainer;
//! let mut container = ServiceContainer::new();
//! ```
//!
//! To configure the container, such as overriding the default constructors,
//! use the [`ContainerBuilder`].
//!
//! ```rust
//! # use rscontainer::{IOwned, Resolver};
//! # struct MyService(u32);
//! # impl IOwned for MyService {
//! #   type Instance = MyService;
//! #   type Parameters = u32;
//! #   type Error = ();
//! #   fn construct(_: Resolver, val: u32) -> Result<MyService, ()> {
//! #       Ok(MyService(val))
//! #   }
//! # }
//! use rscontainer::ServiceContainer;
//! let mut container = ServiceContainer::builder()
//!     .with_owned_constructor::<MyService>(|_resolver, value| {
//!         Ok(MyService(value))
//!     })
//!     .build();
//! ```
//!
//! ## Resolving instances
//!
//! There are different kind of instances:
//!
//! * **Owned instances**: a fresh instance to be used in an owned scope. This
//!   instance will not be stored in the service container, you will get a new
//!   instance each time you resolve an owned instance. See
//!   [`Resolver::owned()`].
//! * **Shared instances**: an instance behind a smart pointer that is stored
//!   in the service container. You will get the same instance each time you
//!   resolve a shared service. See [`Resolver::shared()`] and [`Shared<T>`].
//! * **Some instances**: an enum over owned and shared instances. Use this in a
//!   type when you want the user of your type to decide what kind of instance
//!   they want to supply. See [`Instance`], [`Resolver::shared_instance()`] and
//!   [`Resolver::owned_instance()`].
//!
//! To resolve instances, you first need to acquire a [`Resolver`].
//!
//! ```rust
//! # use rscontainer::ServiceContainer;
//! # let mut container = ServiceContainer::new();
//! let mut resolver = container.resolver();
//! ```
//!
//! To get an instance, you use one of the resolver methods. To resolve an
//! **owned instance**, use the [`Resolver::owned()`] method. An owned service
//! can define parameters that need to be supplied to the `owned()` method.
//!
//! ```rust
//! # use rscontainer::{IOwned, Resolver, ServiceContainer};
//! # struct MyService(u32);
//! # impl IOwned for MyService {
//! #   type Instance = MyService;
//! #   type Parameters = u32;
//! #   type Error = ();
//! #   fn construct(_: Resolver, val: u32) -> Result<MyService, ()> {
//! #       Ok(MyService(val))
//! #   }
//! # }
//! # fn main() -> Result<(), ()> {
//! # let mut container = ServiceContainer::new();
//! # let mut resolver = container.resolver();
//! let mut owned_service = resolver.owned::<MyService>(120)?;
//! # Ok(()) }
//! ```
//!
//! To resolve a **shared instance**, use the [`Resolver::shared()`] method.
//! The first time that this service is resolved, it will be contructed, stored
//! in the container and the pointer is returned. Every other time the service
//! is resolved that same pointer will be cloned and returned. Therefore it is
//! not possible to supply parameters.
//!
//! ```rust
//! # use rscontainer::{IShared, Resolver, ServiceContainer};
//! # use std::sync::{Arc, Mutex};
//! # struct MyService(u32);
//! # impl IShared for MyService {
//! #   type Pointer = Arc<Mutex<MyService>>;
//! #   type Target = MyService;
//! #   type Error = ();
//! #   fn construct(_: Resolver) -> Result<Arc<Mutex<MyService>>, ()> {
//! #       Ok(Arc::new(Mutex::new(MyService(543))))
//! #   }
//! # }
//! # fn main() -> Result<(), ()> {
//! # let mut container = ServiceContainer::new();
//! # let mut resolver = container.resolver();
//! let shared_service = resolver.shared::<MyService>()?;
//! # Ok(()) }
//! ```
//!
//! ## Working with instances
//!
//! An owned instance is just a normal, owned instance, therefore you can do
//! with it whatever you want. But a shared instance is always behind a smart
//! pointer and a locking or borrowing mechanism. To use the instance, you need
//! to use one of the access methods: [`Shared::access()`],
//! [`Shared::access_mut()`], [`Shared::try_access()`] and
//! [`Shared::try_access_mut()`], which borrow or lock the instance for the
//! lifetime of the supplied closure. These access methods take into account
//! that the service may be poisoned. See [`Poisoning`] for more information.
//!
//! ```rust
//! # use rscontainer::{IShared, Resolver, ServiceContainer};
//! # use std::sync::{Arc, Mutex};
//! # struct MyService(u32);
//! # impl MyService { fn get_value(&self) -> u32 { self.0 } }
//! # impl IShared for MyService {
//! #   type Pointer = Arc<Mutex<MyService>>;
//! #   type Target = MyService;
//! #   type Error = ();
//! #   fn construct(_: Resolver) -> Result<Arc<Mutex<MyService>>, ()> {
//! #       Ok(Arc::new(Mutex::new(MyService(543))))
//! #   }
//! # }
//! # fn main() -> Result<(), ()> {
//! # let mut container = ServiceContainer::new();
//! # let mut resolver = container.resolver();
//! # let shared_service = resolver.shared::<MyService>()?;
//! let value = shared_service.access(|service| {
//!     let service = service.assert_healthy();
//!     service.get_value()
//! });
//! # Ok(()) }
//! ```
//!
//! ## Using a type as a service
//!
//! To be able to resolve a type through the service container, there needs to
//! be an implementation of [`IShared`] and/or [`IOwned`] for it. These traits
//! define a constructor method. For an owned service it will be called each
//! time it is resolved. For a shared service it will only be called the first
//! time.
//!
//! The constructors do not return `Self`, but rather an associated type
//! defined on the traits. This makes it possible to resolve every type through
//! the container without having to create a newtype wrapper.
//!
//! The constructors also receive a [`Resolver`], which can be used to
//! recursively construct dependencies of the service. This is rscontainer's
//! implementation of *dependency injection*.
//!
//! # Example
//!
//! ```rust
//! use std::time::Instant;
//! use std::rc::Rc;
//! use std::cell::RefCell;
//! use rscontainer::{IShared, Resolver, ServiceContainer};
//!
//! struct InstantService;
//! impl IShared for InstantService {
//!     type Pointer = Rc<RefCell<Instant>>;
//!     type Target = Instant;
//!     type Error = ();
//!
//!     fn construct(_: Resolver) -> Result<Self::Pointer, Self::Error> {
//!         Ok(Rc::new(RefCell::new(Instant::now())))
//!     }
//! }
//!
//! fn main() {
//!     let mut container = ServiceContainer::new();
//!     let instant = container.resolver().shared::<InstantService>().unwrap();
//!     instant.access(|instant| {
//!         let instant = instant.assert_healthy();
//!         println!("{:?}", instant);
//!     });
//! }
//! ```

mod access;
mod builder;
mod container;
mod getters;
mod internal_helpers;
mod pointers;
mod resolver;
mod service_traits;

pub use self::access::{Access, Poisoning};
pub use self::builder::ContainerBuilder;
pub use self::container::ServiceContainer;
pub use self::getters::{Instance, Shared};
pub use self::resolver::Resolver;
pub use self::service_traits::{IOwned, IShared};

/// Types for extending the functionality of rscontainer.
pub mod internals {
    pub use crate::access::{IAccess, IAccessMut};
    pub use crate::pointers::ISharedPointer;
}