syrette 0.4.0

The convenient dependency injection framework
Documentation

Syrette

Latest Version Documentation Build

The convenient dependency injection framework for Rust.

Namesake

From the syrette Wikipedia article.

A syrette is a device for injecting liquid through a needle. It is similar to a syringe except that it has a closed flexible tube (like that typically used for toothpaste) instead of a rigid tube and piston.

Features

  • A dependency injection container
  • Autowiring dependencies
  • API inspired from the one of InversifyJS
  • Helpful error messages
  • Enforces the use of interface traits
  • Supports generic implementations & generic interface traits
  • Binding singletons
  • Injection of third-party structs & traits
  • Named bindings
  • Async factories

Optional features

  • factory. Binding factories (Rust nightly required)
  • prevent-circular. Detection and prevention of circular dependencies. (Enabled by default)
  • async. Asynchronous support

To use these features, you must enable it in Cargo.

Motivation

Other DI/IOC libraries for Rust are either unmaintained (di for example), overcomplicated and or bloated (anthill-di for example) or has a weird API (teloc for example).

The goal of Syrette is to be a simple, useful, convenient and familiar DI library.

Example usage

use std::error::Error;

use syrette::{injectable, DIContainer};
use syrette::ptr::TransientPtr;

trait IWeapon
{
	fn deal_damage(&self, damage: i32);
}

struct Sword {}

#[injectable(IWeapon)]
impl Sword
{
	fn new() -> Self
	{
		Self {}
	}
}

impl IWeapon for Sword
{
	fn deal_damage(&self, damage: i32)
	{
		println!("Sword dealt {} damage!", damage);
	}
}

trait IWarrior
{
	fn fight(&self);
}

struct Warrior
{
	weapon: TransientPtr<dyn IWeapon>,
}

#[injectable(IWarrior)]
impl Warrior
{
	fn new(weapon: TransientPtr<dyn IWeapon>) -> Self
	{
		Self { weapon }
	}
}

impl IWarrior for Warrior
{
	fn fight(&self)
	{
		self.weapon.deal_damage(30);
	}
}

fn main() -> Result<(), Box<dyn Error>>
{
	let mut di_container = DIContainer::new();

	di_container.bind::<dyn IWeapon>().to::<Sword>()?;

	di_container.bind::<dyn IWarrior>().to::<Warrior>()?;

	let warrior = di_container.get::<dyn IWarrior>()?.transient()?;

	warrior.fight();

	println!("Warrior has fighted");

	Ok(())
}

For more examples see the examples folder.

Todo

  • Add support for generic factories

Contributing

You can reach out by joining the mailing list.

This is the place to submit patches, feature requests and to report bugs.