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 ¶
- type Container
- func (c *Container) Alias[I, T any]() error
- func (c *Container) BindMany[I, T any]() error
- func (c *Container) CanProvideValue[T any]() error
- func (c *Container) MustAlias[I, T any]()
- func (c *Container) MustBindMany[I, T any]()
- func (c *Container) MustProvide[T any](constructor any)
- func (c *Container) MustProvideFactory[T any](fn func() (T, error))
- func (c *Container) MustProvideValue[T any](value T)
- func (c *Container) MustReplace[T any](value T)
- func (c *Container) MustResolve[T any]() T
- func (c *Container) MustResolveAll[T any]() []T
- func (c *Container) ProtectBinding[T any](expected ...T) error
- func (c *Container) Provide[T any](constructor any) error
- func (c *Container) ProvideFactory[T any](fn func() (T, error)) error
- func (c *Container) ProvideProtectedValue[T any](value T) error
- func (c *Container) ProvideValue[T any](value T) error
- func (c *Container) Replace[T any](value T) error
- func (c *Container) Resolve[T any]() (T, error)
- func (c *Container) ResolveAll[T any]() ([]T, error)
- func (c *Container) Seal() error
- func (c *Container) SetInfraProvider(p *InfraProvider)
- func (c *Container) Shutdown(ctx context.Context) error
- type InfraProvider
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 (*Container) Alias ¶
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 ¶
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 ¶
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) MustBindMany ¶
MustBindMany is like BindMany but panics on error.
func (*Container) MustProvide ¶
MustProvide is like Provide but panics on error.
func (*Container) MustProvideFactory ¶
MustProvideFactory is like ProvideFactory but panics on error.
func (*Container) MustProvideValue ¶
MustProvideValue is like ProvideValue but panics on error.
func (*Container) MustReplace ¶
MustReplace is like Replace but panics on error.
func (*Container) MustResolve ¶
MustResolve is like Resolve but panics on error.
func (*Container) MustResolveAll ¶
MustResolveAll is like ResolveAll but panics on error.
func (*Container) ProtectBinding ¶
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 ¶
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 ¶
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 ¶
ProvideProtectedValue registers a pre-built singleton whose binding cannot later be overwritten through Container.Replace.
func (*Container) ProvideValue ¶
ProvideValue registers a pre-built value for type T as a Singleton. The value is cached immediately.
func (*Container) Replace ¶
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 ¶
Resolve retrieves an instance of type T from the container.
svc, err := c.Resolve[MyService]()
func (*Container) ResolveAll ¶
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 ¶
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).
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).