NOEMA
Noema is a Rust toolkit for Dependency Injection (DI) and Inversion of Control (IoC) built around a single, extensible container.
It helps you go from simple service resolution to higher-level patterns like Mediator (Sender), Event Dispatching (Dispatcher), Keyed services, and more—mostly through compile-time wiring powered by macros and trait-based registries.
Noema is designed for concurrent (multi-threaded) applications. In most cases you will resolve dependencies as Arc<T> to keep everything thread-safe and shareable. Some APIs may also allow &T (e.g. reference resolving), but Arc<T> is the default and recommended approach.
Core idea: one container
Noema uses one dependency container that can grow with your project—even across multiple crates—while still enabling different lifecycles depending on the feature/pattern you’re using.
3 lifecycles (“times”)
-
Runtime
- Registries can grow and be configured during runtime.
-
Once Runtime
- One-time initialization during runtime (register once, then use).
-
Compile-time
- Wiring is done through traits + static registries (fast resolution, predictable setup).
In practice, some features are purely compile-time, while others require runtime initialization (for example, the dispatcher).
Features
Noema is feature-flag driven. Enable only what you need.
Services (services)
Classic DI building blocks: register and resolve services.
Two dependency styles:
- Components: singleton-style dependencies (the same instance is reused)
- Factories / Providers: create a new instance per resolution
This is primarily compile-time oriented via trait-based resolvers and macros.
Sender / Mediator (sender)
A Mediator-style workflow similar to MediatR:
- Define an Input (command/query)
- Implement an InputHandler
send(input)returns the handler output
This is designed to be compile-time wired and integrates naturally with DI.
Dispatcher / Events (dispatcher)
A runtime event dispatcher with multiple listeners per event:
- Define events (with metadata like
nameanddescription) - Register multiple EventHandler implementations
- Dispatch events to listeners
Because it uses background tasks and internal setup, it requires an initialization step (e.g. dispatcher_init) and is runtime focused.
Configurations (configurations)
A simple way to manage user-defined mutable configuration, configured once and then injected like any other dependency.
- Define a config type implementing
Configurable - Noema configures it once during initialization
- Then you can resolve it through the container
This is typically compile-time oriented.
Items Collections (items_collections)
Extensible “enum-like” collections that scale beyond typical enums:
- Define a collection type
- Register multiple items (via structs/macros)
- Resolve/consume the collection as a dependency
This feature is powerful but requires modeling the collection carefully.
Lifecycle: Once Runtime.
Keyed Services (keyed_services)
Strategy-like extensibility:
- Multiple implementations of a service trait
- Select an implementation using a key
- Typically factory-based (not singleton-oriented)
Lifecycle: Once Runtime.
Status / Notes
- Rust-first, macro-assisted ergonomics
- Concurrency-oriented (
Arc<T>-based dependency sharing) - Feature-flag driven: enable only what your project needs
License
(Add your license here)