Last active
November 14, 2019 08:30
-
-
Save xcaptain/3c4dcd31fe64a7f7f9786cc30f147ed5 to your computer and use it in GitHub Desktop.
A simple DI container
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[macro_use] | |
extern crate downcast_rs; | |
use downcast_rs::DowncastSync; | |
use std::any::{Any, TypeId}; | |
use std::collections::HashMap; | |
pub trait Resolvable { | |
fn resolve<T: Injectable>(&self) -> Option<&T>; | |
// TODO: use impl Injectable or Box<dyn Injectable>? | |
fn bind(&mut self, obj: impl Injectable); | |
} | |
#[derive(Default)] | |
pub struct Container { | |
pub svcs: HashMap<TypeId, Box<dyn Injectable>>, | |
} | |
impl Resolvable for Container { | |
fn resolve<T: Injectable>(&self) -> Option<&T> { | |
for (_key, value) in self.svcs.iter() { | |
if value.is::<T>() { | |
return value.downcast_ref::<T>(); | |
} | |
} | |
return None; | |
} | |
fn bind(&mut self, obj: impl Injectable) { | |
self.svcs.insert(obj.type_id(), Box::new(obj)); | |
} | |
} | |
impl Container { | |
pub fn run(&self) { | |
// how to run the container | |
self.resolve::<Service1>().unwrap().run_service1(); | |
self.resolve::<Service2>().unwrap().run_service2(); | |
} | |
} | |
pub trait Injectable: DowncastSync + Any { | |
fn inject(self, c: &mut Container); | |
} | |
impl_downcast!(sync Injectable); | |
pub struct Service1; | |
impl Injectable for Service1 { | |
fn inject(self, c: &mut Container) { | |
c.svcs.insert(self.type_id(), Box::new(self)); | |
} | |
} | |
impl Service1 { | |
pub fn run_service1(&self) { | |
// 6719967427312869732 | |
println!("hello from service1, {:?}", self.type_id()); | |
} | |
} | |
pub struct Service2; | |
impl Injectable for Service2 { | |
fn inject(self, c: &mut Container) { | |
c.svcs.insert(self.type_id(), Box::new(self)); | |
} | |
} | |
impl Service2 { | |
pub fn run_service2(&self) { | |
// 702520684108117355 | |
println!("hello from service2, {:?}", self.type_id()); | |
} | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn test_container() { | |
let mut c = Container::default(); | |
// use 2 ways to inject service into container | |
Service1.inject(&mut c); | |
c.bind(Service2); | |
c.run(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment