aboutsummaryrefslogtreecommitdiff
path: root/README.md
blob: 55ff28e91953dafc4031a7d9fe2bd83272ed70b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

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

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.