No Description

Billy Barrow fc35082745 feat(di): add configure_with method for transient resolution 1 week ago
examples 9fcf25eaba Initial commit 3 weeks ago
plans 9fcf25eaba Initial commit 3 weeks ago
slopdocs b7903f9ce2 feat(di): add startup lifecycle and module registration support 1 week ago
src fc35082745 feat(di): add configure_with method for transient resolution 1 week ago
README.md 9fcf25eaba Initial commit 3 weeks ago
meson.build 316168e059 feat(di): add try-inject patterns, registration metadata, and build config 1 week ago

README.md

Inversion

A dependency injection (IoC) container for Vala.

Features

  • 3 Lifecycles: Transient (new instance each time), Scoped (one per scope), Singleton (one per container)
  • Field injection: Dependencies resolved via inject<T>() in field initializers
  • Multi-registration: Register multiple implementations for the same service type
  • Scope-local registrations: Add registrations that only exist within a scope
  • Fluent API: Chain methods for readable configuration

Dependencies

  • GLib 2.0
  • GObject 2.0
  • Invercargill-1

Building

meson setup builddir
meson compile -C builddir

Quick Start

using Inversion;

// Define your service
public interface Logger : Object {
    public abstract void log(string message);
}

public class ConsoleLogger : Object, Logger {
    public void log(string message) {
        stdout.printf("[LOG] %s\n", message);
    }
}

// Register and resolve
var container = new Container();
container.register_singleton<ConsoleLogger>((scope) => new ConsoleLogger())
    .as_type(typeof(Logger));

var scope = container.create_scope();
var logger = scope.resolve<Logger>();
logger.log("Hello!");

Lifecycles

Lifecycle Behavior
TRANSIENT New instance created every resolve
SCOPED One instance per scope
SINGLETON One instance per container
container.register_transient<MyService>((s) => new MyService());
container.register_scoped<MyService>((s) => new MyService());
container.register_singleton<MyService>((s) => new MyService());

Multiple Implementations

container.register_singleton<FileLogger>((s) => new FileLogger())
    .as_type(typeof(Logger));
container.register_singleton<ConsoleLogger>((s) => new ConsoleLogger())
    .as_type(typeof(Logger));

// Get all implementations
var allLoggers = scope.resolve_all<Logger>();

Field Injection

Dependencies are injected using the inject<T>() function in field initializers:

public class UserService : Object {
    private Logger logger = inject<Logger>();
    
    public void greet(string name) {
        this.logger.log(@"Hello, $name!");
    }
}

// Dependencies are resolved automatically when UserService is created
var userService = scope.resolve<UserService>();

Use inject_all<T>() to inject all implementations of a service:

public class MultiLogger : Object {
    private Lot<Logger> loggers = inject_all<Logger>();
}

Scopes

Scopes manage scoped instance lifetime and can have their own local registrations:

var scope = container.create_scope();

// Add a registration only available in this scope
scope.register_singleton<RequestContext>((s) => new RequestContext())
    .as_type(typeof(Context));

Examples

See the examples/ directory for more detailed usage:

  • BasicUsage.vala - Registration and resolution basics
  • LifecycleDemo.vala - Transient vs Scoped vs Singleton
  • InjectionDemo.vala - Field injection with inject<T>()
  • MultiRegistration.vala - Multiple implementations per service
  • ScopeRegistrationDemo.vala - Scope-local registrations