di

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 13, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Adapted from github.com/samber/do (MIT License). Original copyright (c) 2022 Samuel Berthe.

Package di provides a type-safe dependency injection container using Go generics. All services use the Singleton lifecycle. It supports single resolution, interface aliases, and ordered interface collections.

This package is internal to the Credo module. Use the public API in the root package: [credo.App.Provide], [credo.App.Resolve], etc.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Container

type Container struct {
	// contains filtered or unexported fields
}

Container is a type-safe dependency injection container using Go generics. Services are registered with Provide[T] and resolved with Resolve[T]. All services use the Singleton lifecycle.

func New

func New() *Container

New creates a new Container.

func (*Container) Alias

func (c *Container) Alias[I, T any]() error

Alias creates a type alias so that Resolve[I] returns the singleton registered for concrete type T. Contract rules:

  • T must already be registered via Provide or ProvideValue
  • I must be an interface type
  • T must implement I
  • I must not already have a registration or alias
  • Container must not be frozen (container is sealed)

func (*Container) BindMany

func (c *Container) BindMany[I, T any]() error

BindMany adds concrete type T to the ordered collection for interface I. Contract rules:

  • T must already be registered via Provide or ProvideValue
  • I must be an interface type
  • T must be a concrete type (not an interface)
  • T must implement I
  • The same (I, T) pair must not already exist
  • Container must not be frozen (container is sealed)

func (*Container) CanProvideValue

func (c *Container) CanProvideValue[T any]() error

CanProvideValue reports whether Container.ProvideValue could currently register type T. It performs only the frozen-container and direct duplicate-T checks, without registering or reserving the type.

The result is a point-in-time preflight. A later ProvideValue call can still fail if another registration or container sealing occurs in between.

func (*Container) MustAlias

func (c *Container) MustAlias[I, T any]()

MustAlias is like Alias but panics on error.

func (*Container) MustBindMany

func (c *Container) MustBindMany[I, T any]()

MustBindMany is like BindMany but panics on error.

func (*Container) MustProvide

func (c *Container) MustProvide[T any](constructor any)

MustProvide is like Provide but panics on error.

func (*Container) MustProvideFactory

func (c *Container) MustProvideFactory[T any](fn func() (T, error))

MustProvideFactory is like ProvideFactory but panics on error.

func (*Container) MustProvideValue

func (c *Container) MustProvideValue[T any](value T)

MustProvideValue is like ProvideValue but panics on error.

func (*Container) MustReplace

func (c *Container) MustReplace[T any](value T)

MustReplace is like Replace but panics on error.

func (*Container) MustResolve

func (c *Container) MustResolve[T any]() T

MustResolve is like Resolve but panics on error.

func (*Container) MustResolveAll

func (c *Container) MustResolveAll[T any]() []T

MustResolveAll is like ResolveAll but panics on error.

func (*Container) ProtectBinding

func (c *Container) ProtectBinding[T any](expected ...T) error

ProtectBinding prevents Replace from overwriting the existing direct registration for T. Calling it repeatedly is safe. When one expected value is supplied, protection succeeds only if the currently resolved singleton is the same comparable value. A mismatch adds no protection; protection already present on the binding remains in effect.

func (*Container) Provide

func (c *Container) Provide[T any](constructor any) error

Provide registers a constructor for type T. The constructor can accept any number of parameters that are themselves registered in the container, and must return T or (T, error).

c.Provide[MyService](NewMyService)

func (*Container) ProvideFactory

func (c *Container) ProvideFactory[T any](fn func() (T, error)) error

ProvideFactory registers a compile-time-checked factory for type T. Unlike Provide, whose constructor is typed any and inspected via reflection at registration time, fn's signature is enforced by the compiler. fn runs lazily on first resolution, exactly once.

fn is opaque to the container: dependencies it resolves internally are not visible to Seal's graph validation or to resolve-time cycle detection.

func (*Container) ProvideProtectedValue

func (c *Container) ProvideProtectedValue[T any](value T) error

ProvideProtectedValue registers a pre-built singleton whose binding cannot later be overwritten through Container.Replace.

func (*Container) ProvideValue

func (c *Container) ProvideValue[T any](value T) error

ProvideValue registers a pre-built value for type T as a Singleton. The value is cached immediately.

func (*Container) Replace

func (c *Container) Replace[T any](value T) error

Replace registers a pre-built value for type T as a Singleton, overwriting any existing unprotected registration. Bindings created by Container.ProvideProtectedValue or locked by Container.ProtectBinding reject replacement so external lifecycle state cannot diverge from DI.

Replace is intended for composition-root overrides and testing, where a real or default binding must be swapped for a stub or fake. The replacement is a value (no constructor), so it has no dependencies and is always valid during Seal. Replace is rejected once the container is sealed.

func (*Container) Resolve

func (c *Container) Resolve[T any]() (T, error)

Resolve retrieves an instance of type T from the container.

svc, err := c.Resolve[MyService]()

func (*Container) ResolveAll

func (c *Container) ResolveAll[T any]() ([]T, error)

ResolveAll retrieves all singleton instances bound to interface type T via BindMany, preserving binding order. When no bindings exist, it returns an empty slice and nil error.

func (*Container) Seal

func (c *Container) Seal() error

Seal freezes the container and validates the dependency graph. After Seal, no more Provide, ProvideFactory, ProvideValue, ProvideProtectedValue, ProtectBinding, Replace, Alias, or BindMany calls are allowed. Seal is idempotent — subsequent calls return the same result.

Seal is side-effect-free: it does not instantiate any singletons or perform I/O. It only freezes the container and runs validation.

Resolve is allowed both before and after Seal. Before Seal, Resolve works during bootstrap (e.g. ensureRegistry pattern). After a failed Seal, Resolve returns the seal error. app.Run() calls Seal implicitly via credo.App.Finalize.

func (*Container) SetInfraProvider

func (c *Container) SetInfraProvider(p *InfraProvider)

SetInfraProvider configures infra auto-injection for constructors. Must be called before any Resolve calls (typically in credo.New).

func (*Container) Shutdown

func (c *Container) Shutdown(ctx context.Context) error

Shutdown gracefully shuts down all cached singletons that implement Shutdowner, in reverse registration order. The context carries the shutdown deadline — services should respect ctx.Done() for timely cleanup.

type InfraProvider

type InfraProvider struct {
	// InfraType is the reflect.Type of the Infra struct (e.g., credo.Infra).
	InfraType reflect.Type

	// Factory creates an Infra value with the logger scoped to serviceName.
	// Returns the Infra struct value (not a pointer).
	Factory func(serviceName string) any
}

InfraProvider configures automatic Infra injection for constructors. The root package sets this on the container so the DI system can produce infrastructure infra without importing the root package (avoiding cycles).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL