[][src]Crate async_injector

Asynchronous dependency injection for Rust.

Example

The following is an example application that receives configuration changes over HTTP.

This example deliberately fails to compile
use anyhow::Error;
use async_injector::{Provider, Injector, Key, async_trait};

/// Provider that describes how to construct a database.
#[derive(Provider)]
struct DatabaseProvider {
    #[dependency(tag = "\"database/url\"")]
    url: String,
    #[dependency(tag = "\"database/connection-limit\"")]
    connection_limit: u32,
}

#[async_trait]
impl Provider for DatabaseProvider {
    type Output = Database;

    /// Constructor a new database and supply it to the injector.
    async fn build(self) -> Option<Self::Output> {
        match Database::connect(&self.url, self.connection_limit).await {
            Ok(database) => Some(database),
            Err(e) => {
                log::warn!("failed to connect to database: {}: {}", self.url, e);
                None
            }
        }
    }
}

/// A fake webserver handler.
///
/// Note: there's no real HTTP framework that looks like this. This is just an
/// example.
async fn serve(injector: &Injector) -> Result<(), Error> {
    let server = Server::new()?;

    // Fake endpoint to set the database URL.
    server.on("POST", "/config/database/url", |url: String| {
        injector.update_key(Key::tagged("database/url")?, url);
    });

    // Fake endpoint to set the database connection limit.
    server.on("POST", "/config/database/connection-limit", |limit: u32| {
        injector.update_key(Key::tagged("database/connection-limit")?, limit);
    });

    // Listen for requests.
    server.await?;
    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    let injector0 = Injector::new();

    /// Setup database provider.
    let injector = injector0.clone();

    tokio::spawn(async move {
        DatabaseProvider::run(&injector0).await;
    });

    let injector = injector0.clone();

    tokio::spawn(async move {
        serve(&injector).await.expect("web server errored");
    });

    let (database_stream, database) = injector0.stream::<Database>();

    let application = Application::new(database);

    loop {
        tokio::select! {
            // receive new databases when available.
            database = database_stream.next() => {
                application.database = database;
            },
            // run the application to completion.
            _ = &mut application => {
                log::info!("application finished");
            },
        }
    }
}

Structs

Injector

Use for handling injection.

Key
RawKey
Stream

A stream of updates for values injected into this injector.

Var

Proxy accessor for an injected variable.

Enums

Error

Traits

Provider

Attribute Macros

async_trait