Runtime dependency injection in Rust

Overview

runtime_injector

Current version Current documentation

This library provides an easy to use dependency injection container with a focus on ergonomics and configurability at the cost of runtime performance. For a more performance-oriented container, look for a compile-time dependency injection library.

Sample code is available on the docs.

Getting started

For using the library, check out the docs.

For local development of runtime_injector, clone the repository, then build the project with cargo:

git clone https://github.com/TehPers/runtime_injector
cd runtime_injector
cargo build

If you want to build the project using the "arc" feature instead, disable default features, and enable the "arc" feature:

cargo build --no-default-features --features arc

Minimum supported Rust version

As the library is still in development, the only supported Rust version is the most recent version of Rust. The library may work on older versions, but there is no guarantee.

License

This library is licensed under your choice of either MIT or Apache 2.0.

Comments
  • Added modules and define_module macro

    Added modules and define_module macro

    • Adds modules which are just collections of providers that can be registered all at once in an InjectorBuilder
    • Adds a define_module! macro which can be used to easily create those modules

    Closes #13

    opened by TehPers 1
  • Add support for multi-injection

    Add support for multi-injection

    • [x] Allow for multiple providers or implementations to be registered for a service/interface.
    • [x] Allow each implementation/instance of a service to be requested via some kind of iterator. For instance, allow some type Services<dyn Interface> to be requested as a dependency, and have that return instances of Svc<dyn Interface> for each implementation of Interface that has been registered. This should be easier now that Injector is cloneable.
    • [x] Allow services to still be requested via Svc<dyn Interface> or Svc<Foo> without needing to use an iterator. This should cause an error to be returned if there are multiple providers available.
    enhancement 
    opened by TehPers 1
  • Add conditional providers

    Add conditional providers

    Adds conditional providers which are skipped if their condition is not met. Currently only TypedProviders can be nested in ConditionalProvider. Hopefully when GATs are eventually released WithCondition can also be implemented on Provider.

    Resolves #29

    opened by TehPers 0
  • Cleanup existing code

    Cleanup existing code

    Cleans up existing code. This includes breaking changes.

    • Reduces number of times RequestInfo is cloned by changing signatures to take &RequestInfo instead of RequestInfo
    • Made ServiceFactory<D> be a subtrait of Service since providers need to implement Service anyway
    • Fixed Clone implementation for Factory<R> requiring R: Clone (limitation of #[derive(Clone)])
    • Added additional example to Factory
    • Fixed CI not failing on clippy failures
    • Incremented version numbers for runtime_injector and runtime_injector_actix
    opened by TehPers 0
  • Add lazy request factories

    Add lazy request factories

    Adds Factory<R> which allows requests to be performed lazily. Since Factory<R> has no lifetime parameter, it can be stored in a struct and requests can be made to it later during the program's execution.

    opened by TehPers 0
  • Change 'interface!' macro to use 'dyn Trait' like the rest of library

    Change 'interface!' macro to use 'dyn Trait' like the rest of library

    Changes interface! macro to require dyn Trait = [...] instead of just Trait = [...]. This makes the macro work more similarly to other parts of the library, like define_module! which needs dyn Trait = [...] when defining providers for an interface, and Svc<dyn Trait>/Services<dyn Trait>/etc when requesting an instance of the interface.

    Also adds support for trailing commas and multiple interface definitions in the same interface! block.

    While this is technically a non-breaking change (trait objects don't currently need an explicit dyn to compile), it adds a bunch of extra warnings to existing code, so this change will wait until 0.4.

    opened by TehPers 0
  • Add support for target-specific arguments

    Add support for target-specific arguments

    Adds support for injecting target-specific arguments to configure how services are created. Also updates the define_module! macro to make it easier to specify those arguments.

    Closes #23

    opened by TehPers 0
  • Target-specific arguments

    Target-specific arguments

    Rather than relying on constant(value) to inject an argument to a service, allow services to have custom arguments set for them:

    let mut builder = Injector::builder();
    builder.provide(Foo::new.singleton());
    builder.with_arg::<Foo, i32>();
    
    opened by TehPers 0
  • Add in-depth docs about using dependency injection

    Add in-depth docs about using dependency injection

    Added docs for how dependency injection (and an IoC container) can benefit an application. These docs can be expanded later to add additional information.

    Closes #17

    opened by TehPers 0
  • Owned dependency injection

    Owned dependency injection

    Allows some services to be injected via Box<I> rather than needing to be provided via Svc<I>. This allows services to own their dependencies without needing to clone them.

    Closes #12

    opened by TehPers 0
  • Add helper library for actix-web

    Add helper library for actix-web

    Adds a helper library for working with actix-web. Specifically, refactors the repository quite a bit to allow for multi-crate workspace, and adds an Injected<R> type that can inject container requests into actix-web requests.

    #[get("/")]
    fn index(
        my_service: Injected<Svc<MyService>>, // inject some custom service
        injector: Injected<Injector>, // any request is supported, even non-service requests
        // ...
    ) -> impl Responder {
        todo!()
    }
    

    Closes #19

    opened by TehPers 0
  • No examples for interior mutability except for the constant

    No examples for interior mutability except for the constant

    Hey, I started playing around with this DI container but I'm unable to achieve interior mutability. Could you provide some examples how that could be achieved with both Svc modes (Rc/Arc) and:

    • Cell,
    • RefCell,
    • Mutex,
    • RwLock,
    • or any other wrapper of any kind?

    I've only found the example for constant with the Mutex in one of the docstrings:

    builder.provide(constant(Mutex::new(0i32)));
    

    I would like to be able to provide particular component wrapped for example by Mutex and then be able to retrieve this Mutex from the container.

    I've created small example with comments what I would like to be able to achieve:

    use runtime_injector::*;
    use std::cell::{Cell, RefCell};
    use std::error::Error;
    use std::sync::{Mutex, RwLock};
    
    pub trait Foo: Service {
        fn increase(&mut self);
    }
    
    #[derive(Default)]
    struct FooImpl(u64);
    
    impl Foo for FooImpl {
        fn increase(&mut self) {
            self.0 += 1;
        }
    }
    
    pub trait Bar: Service {
        fn increase(&mut self);
    }
    
    struct BarImpl {
        foo: Svc<dyn Foo>,
    }
    
    impl BarImpl {
        // Not possible to get Cell/RefCell/Mutex/RwLock
        pub fn new(foo: Svc<dyn Foo>) -> Self {
            Self { foo }
        }
    }
    
    impl Bar for BarImpl {
        fn increase(&mut self) {
            self.foo.increase();
        }
    }
    
    interface!(
        dyn Foo = [FooImpl],
        dyn Bar = [BarImpl]
    );
    
    fn main() -> Result<(), Box<dyn Error>> {
        let mut builder = Injector::builder();
    
        // No obvious way to allow interior mutability, like auto creation of Cell/RefCell/Mutex/RwLock
        builder.provide(FooImpl::default.singleton().with_interface::<dyn Foo>());
        builder.provide(BarImpl::new.singleton().with_interface::<dyn Bar>());
    
        // It could be available for example in such way:
        builder.provide(FooImpl::default.wrap_in_mutex().singleton().with_interface::<dyn Foo>());
        // or:
        builder.provide(FooImpl::default.wrap_using(|result| Mutex::new(result)).singleton().with_interface::<dyn Foo>());
    
        let injector = builder.build();
    
        // Not able to call these as they require &mut
        injector.get::<Svc<dyn Foo>>()?.increase();
        injector.get::<Svc<dyn Bar>>()?.increase();
    
        // No Cell/RefCell/Mutex/RwLock availability
        injector.get::<Cell<Svc<dyn Bar>>>()?.increase();
        injector.get::<RefCell<Svc<dyn Bar>>>()?.increase();
        injector.get::<Mutex<Svc<dyn Bar>>>()?.increase();
        injector.get::<RwLock<Svc<dyn Bar>>>()?.increase();
    
        Ok(())
    }
    
    enhancement 
    opened by NeveHanter 2
  • Improve ergonomics

    Improve ergonomics

    • Relaxed constraints for ServiceFactory
      • Moved Service constraint to the provider implementations
      • Result only constrained by Any rather than Service
    • ServiceFactory::invoke now takes &self, meaning it doesn't need to be locked to be used in a thread-safe manner
      • Implemented on Fn rather than FnMut now
      • Neither FallibleServiceFactory nor the Fn (previously FnMut) implementations need &mut self
    opened by TehPers 0
  • Add scoped providers

    Add scoped providers

    Add a way for providers to have a scope. For example, one way a scope might be implemented is this:

    let scope = injector.scope(); // has Drop impl
    let foo: Svc<Foo> = scope.get().unwrap();
    

    Scoped providers don't guarantee the lifetime of the values that they provide. If a scope is dropped, there's no way to know if all references to the services it provided were dropped since they use reference-counted pointers or have been moved to outside of the injector (in the case of owned injection). Instead, scopes only would guarantee that scoped providers provide the same instances from the same scope, and different instances from different scopes.

    enhancement 
    opened by TehPers 0
  • Allow injectors to have their provider map modified after being built

    Allow injectors to have their provider map modified after being built

    Suppose a config is reloaded during execution of a program. This would allow services to be reconfigured based on the changes in that config. Currently, it's somewhat possible using factories:

    struct FooFactory {
        injector: Injector,
        config: Svc<Mutex<Config>>
    }
    
    impl FooFactory {
        pub fn new(injector: Injector, config: Svc<Mutex<Config>>) -> Self {
            FooFactory {
                injector,
                config,
            }
        }
    
        pub fn get(&self) -> InjectResult<Svc<dyn Foo>> {
            match self.config.lock().unwrap().foo_impl {
                FooImpl::Bar => self.injector.get::<Svc<Bar>>().map(|bar| bar as Svc<dyn Foo>),
                // ...
            }
        }
    }
    

    This is a lot of work to reconfigure just a single service based on a config reloaded at runtime. It might be better to instead expose some functions to mutate the provider map in existing Injectors.

    enhancement 
    opened by TehPers 0
  • Enterprise FizzBuzz example

    Enterprise FizzBuzz example

    Port a slightly simplified version of the enterprise-edition FizzBuzz solution to Rust and provide it as an example. This should at least show a lot of use-cases for dependency injection and provide as a valuable test.

    documentation 
    opened by TehPers 0
Owner
TehPers
TehPers
Licensebat - 🔐⛵ Effortless dependency compliance with your license policies

Licensebat All docs here are temporary. Thougths For the moment, it seems it makes sense to have all the collectors sharing the same trait. That doesn

Licensebat 19 Dec 28, 2022
Rust Kubernetes runtime helpers. Based on kube-rs.

kubert Rust Kubernetes runtime helpers. Based on kube-rs. Features clap command-line interface support; A basic admin server with /ready and /live pro

Oliver Gould 63 Dec 17, 2022
A Rust runtime for AWS Lambda

Rust Runtime for AWS Lambda This package makes it easy to run AWS Lambda Functions written in Rust. This workspace includes multiple crates: lambda-ru

Amazon Web Services - Labs 2.4k Dec 29, 2022
Rust Lambda Extension for any Runtime to preload SSM Parameters as 🔐 Secure Environment Variables!

?? Crypteia Rust Lambda Extension for any Runtime to preload SSM Parameters as Secure Environment Variables! Super fast and only performaned once duri

Custom Ink 34 Jan 7, 2023
Graceful shutdown util for Rust projects using the Tokio Async runtime.

Shutdown management for graceful shutdown of tokio applications. Guard creating and usage is lock-free and the crate only locks when: the shutdown sig

Plabayo 54 Sep 29, 2023
Open-source Rust Runtime for the VEX V5 Platform

vexide Work in progress high level bindings for the V5 Brain VEX SDK. Unlike other libraries for the V5 Brain, vexide doesn't use an RTOS. Instead, ve

vexide 10 May 6, 2024
Develop an async runtime like thing in Rust for educational purpose.

How-not-to-async-rs Develop an async runtime like thing in Rust for educational purpose. What this is not This is not going to be a blog post explaini

Arun Muralidharan 28 May 11, 2024
microtemplate - A fast, microscopic helper crate for runtime string interpolation.

microtemplate A fast, microscopic helper crate for runtime string interpolation. Design Goals Very lightweight: I want microtemplate to do exactly one

_iPhoenix_ 13 Jan 31, 2022
ImGUI runtime inspector

igri is a runtime inspector powered by imgui-rs

toyboot4e 2 Oct 30, 2021
Minimal runtime / startup for RISC-V CPUs from Espressif

esp-riscv-rt Minimal runtime / startup for RISC-V CPUs from Espressif. Much of the code in this repository originated in the rust-embedded/riscv-rt re

esp-rs 13 Feb 2, 2023
Use winit like the async runtime you've always wanted

async-winit Use winit like the async runtime you've always wanted. winit is actually asynchronous, contrary to popular belief; it's just not async. It

John Nunley 17 Apr 23, 2023
Continuous runtime observablity SDKs to monitor WebAssembly code.

Observe Observe is an observability SDK for WebAssembly. At the moment we support wasmtime hosts and we output opentelemetry data to stdout. We plan t

Dylibso 4 Jun 8, 2023
A modular and blazing fast runtime security framework for the IoT, powered by eBPF.

Pulsar is a security tool for monitoring the activity of Linux devices at runtime, powered by eBPF. The Pulsar core modules use eBPF probes to collect

Exein.io 319 Jul 8, 2023
Asynchronous runtime abstractions for implicit function decoloring.

decolor Asynchronous runtime abstractions for implicit function decoloring. Decolor is in beta Install | User Docs | Crate Docs | Reference | Contribu

refcell.eth 11 Oct 26, 2023
A reactive runtime for embedded systems.

Actuate Examples A reactive diagram for robotics and control systems. Actuate leverages Rust's type system to create an efficient diagram that connect

null 7 Mar 4, 2024
k-mer counter in Rust using the rust-bio and rayon crates

krust is a k-mer counter written in Rust and run from the command line that will output canonical k-mers and their frequency across the records in a f

null 14 Jan 7, 2023
Experimental Rust tool for generating FFI definitions allowing many other languages to call Rust code

Diplomat is an experimental Rust tool for generating FFI definitions allowing many other languages to call Rust code. With Diplomat, you can simply define Rust APIs to be exposed over FFI and get high-level C, C++, and JavaScript bindings automatically!

null 255 Dec 30, 2022
Aws-sdk-rust - AWS SDK for the Rust Programming Language

The AWS SDK for Rust This repo contains the new AWS SDK for Rust (the SDK) and its public roadmap. Please Note: The SDK is currently released as a dev

Amazon Web Services - Labs 2k Jan 3, 2023
Rust + Yew + Axum + Tauri, full-stack Rust development for Desktop apps.

rust-yew-axum-tauri-desktop template Rust + Yew + Axum + Tauri, full-stack Rust development for Desktop apps. Crates frontend: Yew frontend app for de

Jet Li 54 Dec 23, 2022