Expand description
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()
.
use rscontainer::ServiceContainer;
let mut container = ServiceContainer::new();
To configure the container, such as overriding the default constructors,
use the ContainerBuilder
.
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()
andShared<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()
andResolver::owned_instance()
.
To resolve instances, you first need to acquire a Resolver
.
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.
let mut owned_service = resolver.owned::<MyService>(120)?;
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.
let shared_service = resolver.shared::<MyService>()?;
§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.
let value = shared_service.access(|service| {
let service = service.assert_healthy();
service.get_value()
});
§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
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);
});
}
Modules§
- internals
- Types for extending the functionality of rscontainer.
Structs§
- Access
- Wrapper to make a type accessable through the
IAccess
trait. - Container
Builder - Create a container with the builder pattern.
- Resolver
- Used to resolve services from the service container.
- Service
Container - Container for all the services of an application.
- Shared
- A pointer to a shared instance from the service container.
Enums§
- Instance
- Some instance of a service, either a shared instance or owned instance.
- Poisoning
- Indicates whether an instance is poisoned or not.