ruice 0.2.0

Runtime based dependency injection for Rust.
Documentation
use std::sync::Arc;

use crate::Services;

#[derive(Debug)]
pub struct Tagged<Tag>
where
    Tag: ?Sized,
{
    services: Vec<Arc<Tag>>,
}

impl<Tag> Clone for Tagged<Tag>
where
    Tag: ?Sized,
{
    fn clone(&self) -> Self {
        Self {
            services: self.services.to_vec(),
        }
    }
}

impl<Tag> Default for Tagged<Tag>
where
    Tag: ?Sized,
{
    fn default() -> Self {
        Self { services: vec![] }
    }
}

unsafe impl<Tag> Send for Tagged<Tag> where Tag: ?Sized {}
unsafe impl<Tag> Sync for Tagged<Tag> where Tag: ?Sized {}

pub trait TaggedServices: Services {
    fn get_tagged<Tag>(&self) -> Vec<Arc<Tag>>
    where
        Tag: ?Sized + 'static,
    {
        self.get::<Tagged<Tag>>()
            .map(|t| t.services.iter().map(Arc::clone).collect())
            .unwrap_or_default()
    }

    fn put_tagged<Tag>(&mut self, service: Arc<Tag>)
    where
        Tag: ?Sized + 'static,
    {
        self.replace::<Tagged<Tag>, _>(|tagged| {
            let mut tagged = tagged.map(Tagged::<_>::clone).unwrap_or_default();
            tagged.services.push(service);
            tagged
        });
    }
}

impl<C> TaggedServices for C where C: Services {}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::ServiceContainer;

    trait Greet: Send + Sync {
        fn greet(&self) -> String;
    }

    type GreeterTag = dyn Greet;

    struct FooGreeter;

    impl Greet for FooGreeter {
        fn greet(&self) -> String {
            "Hello from Foo!".to_string()
        }
    }

    struct BarGreeter;

    impl Greet for BarGreeter {
        fn greet(&self) -> String {
            "Hello from Bar!".to_string()
        }
    }

    #[test]
    fn tag() {
        let mut container = ServiceContainer::default();

        container.put_tagged::<GreeterTag>(Arc::new(FooGreeter));
        container.put_tagged::<GreeterTag>(Arc::new(BarGreeter));

        let greetings = container
            .get_tagged::<GreeterTag>()
            .into_iter()
            .map(|g| g.greet())
            .collect::<Vec<_>>();

        assert_eq!(
            vec!["Hello from Foo!".to_string(), "Hello from Bar!".to_string()],
            greetings,
        )
    }
}