Skip to content

jungnitz/dijavu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dijavu

dijavu is still very much in development. This means that the documentation is still severely lacking and there might be many breaking changes before a v0.1. I do use this library for my own projects and intend to bring it to said first stable release in due time.

dijavu is an opinionated dependency injection framework with a strict separation between application initialization and runtime. Most dependency injection frameworks operate on a single object graph. dijavu instead treats initialization and runtime as separate phases with different requirements.

Initialization focuses on mutation, configuration, and construction. Runtime focuses on stable, immutable access to application state. A build process transforms the initialization state into the runtime state.

Most types therefore exist in two forms: an initialization representation and a runtime representation. These representations are often structurally similar (hence the name), but serve different purposes.

Features and Caveats

  • Fully typed dependency injection, with support for generic types
  • Derive macros for common injection patterns, including hooks to customize initialization and build behavior
  • Support for cyclic references between injectable types, which allows elegant registration of hooks
  • Being primarily targeted at backend services, most functions and hooks provided by the framework are async
  • For ease of use, the runtime state is intentionally leaked during the build process. For most use-cases this is very convenient, but of course forbids repeatedly executing build processes within one program execution.

Example

use std::collections::HashMap;
use dijavu::{*, initializables::*};

#[derive(Injectable)]
pub struct Configuration(Value<HashMap<String, String>>);

// `ConfigurationInit` is automatically generated by the derive macro
impl ConfigurationInit<'_> { 
    pub fn put(&mut self, key: impl Into<String>, value: impl Into<String>) {
        // obtain a reference to the mutable initialization data, which is automatically
        // generated as well and similarly structured to `Configuration`
        let ConfigurationInitData(map /* &mut HashMap<String, String> */) = self.0.data_mut();
        map.insert(key.into(), value.into());
    }
}

impl Configuration {
    pub fn get(&self, key: &str) -> Option<&String> {
        self.0.get(key)
    }
}

#[derive(Injectable)]
pub struct MyService {
    config: Inject<Configuration>,
}

impl MyService {
    pub fn action(&self) {
        println!("{}", self.config.get("my_service.action").unwrap());
    }
}

pub async fn start() -> Result<()> {
    let mut init = InitInjector::default();
    init.get::<Configuration>().await?
        .put("my_service.action", "Hello World!");
    init.get::<MyService>().await?;

    let injector: Injector = init.build().await?;
    injector.get::<MyService>().action();
    // "Hello World!"
    
    Ok(())
}

About

MIRROR: Two-phased dependency injection

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages