Vec<T> multibindings

A #[provides] or #[binds] binding can also be marked with the #[into_vec] attribute, which means instead of directly binding to T, the binding should be collected into a Vec<T>.

With the bindings:

    #[provides]
    #[into_vec]
    pub fn provide_string1() -> String {
        "string1".to_owned()
    }

    #[provides]
    #[into_vec]
    pub fn provide_string2() -> String {
        "string2".to_owned()
    }

Vec<String> can be injected with the values ["string1", "string2"]. This works across all modules that are installed.

#[into_vec] can also be #[qualified]

    #[provides]
    #[qualified(Q)]
    #[into_vec]
    pub fn provide_q_string1() -> String {
        "q_string1".to_owned()
    }

Which result in #[qualified(Q)] Vec<String>. Note that the container is qualified instead of the content.

#[into_vec] also works with #[binds]

    #[binds]
    #[into_vec]
    pub fn bind_bar(impl_: crate::Bar) -> Cl<dyn crate::Foo> {}

    #[binds]
    #[into_vec]
    pub fn bind_baz(impl_: crate::Baz) -> Cl<dyn crate::Foo> {}

Which allows Vec<Cl<dyn Foo>> to be injected. This is a common way to implement event callbacks.

Providing multiple items

A method marked with #[elements_into_vec] can return Vec<T>, which will get merged with other #[into_vec] and #[elements_into_vec].

    #[provides]
    #[elements_into_vec]
    pub fn provide_strings() -> Vec<String> {
        vec!["string3".to_owned(), "string4".to_owned()]
    }

This allows multiple bindings to be provided at once. It also allows a binding method to decide not to provide anything at runtime, by returning an empty Vec.

Duplication behaviors

Lockjaw's #[into_vec] strays from Dagger's @IntoSet, as Hash and Eq are not universally implemented in Rust. This mean the Vec may contain duplicated values.

However, duplicated modules are not allowed by Lockjaw, so each binding method will be called at most once when generating the Vec.

If deduplication is needed, you can add another provider that does the conversion:

#[provides]
pub fn vec_string_to_set_string(v: Vec<String>) -> HashSet<String> {
    HashSet::from_iter(v)
}

Examples

https://github.com/azureblaze/lockjaw/blob/main/tests/module_provides_into_vec.rs