contract

package
v2.13.0 Latest Latest
Warning

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

Go to latest
Published: Aug 18, 2026 License: MIT Imports: 1 Imported by: 2

Documentation

Index

Constants

View Source
const (
	ServiceLifetimeContainer = "container"
	ServiceLifetimeScoped    = "scoped"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Container

type Container interface {
	Registrar

	Resolver

	OverrideService

	ScopeManager

	Names() []string

	Close() error
}

type ContainerCarrier added in v2.13.0

type ContainerCarrier interface {
	Container() Container
}

ContainerCarrier is implemented by resolvers that can name the container behind them. A process-lifetime service that defers work past the resolution that built it — a lazily-dialed pool, a registry that opens on first use — replays that work through the container, not through the resolution context it was constructed with: a resolution context is single-threaded and dies with its scope, while the container is the process-lifetime, lock-guarded half the deferred work actually needs. The container itself satisfies the shape by answering itself.

type OverrideOption added in v2.13.0

type OverrideOption func(option *OverrideOptions)

type OverrideOptions added in v2.13.0

type OverrideOptions struct {
	/* ClosedWithScope hands the installed value to the scope's teardown. An override belongs by default to whoever installed it and outlives the scope — the http kernel installs the request logger and goes on using it to report the scope's own close failure — so a caller that built the value FOR this scope and has nowhere else to close it says so here. */
	ClosedWithScope bool
}

OverrideOptions carries what an override declares beyond the value itself.

type OverrideService

type OverrideService interface {
	OverrideInstance(serviceName string, value any) error

	MustOverrideInstance(serviceName string, value any)

	OverrideProtectedInstance(serviceName string, value any) error

	MustOverrideProtectedInstance(serviceName string, value any)
}

type OverrideServiceWithOptions added in v2.13.0

type OverrideServiceWithOptions interface {
	OverrideInstanceWithOptions(serviceName string, value any, options ...OverrideOption) error

	MustOverrideInstanceWithOptions(serviceName string, value any, options ...OverrideOption)

	OverrideProtectedInstanceWithOptions(serviceName string, value any, options ...OverrideOption) error

	MustOverrideProtectedInstanceWithOptions(serviceName string, value any, options ...OverrideOption)
}

OverrideServiceWithOptions is the optional companion of OverrideService. It is a separate interface so the four signatures of OverrideService never move: an installed override is the oldest thing in this package and every framework caller of it predates options.

type Provider

type Provider[T any] func(resolver Resolver) (T, error)

type RegisterOption

type RegisterOption func(option *RegisterOptions)

type RegisterOptions

type RegisterOptions struct {
	AlsoRegisterType         bool
	TypeRegistrationIsStrict bool
	/* ReplacesContainerService admits a SCOPED registration whose name — or whose registered type — the container already claims; the container-level registration paths do not read it. Without it the collision is refused at the point it is made: a scoped service silently shadowing a container singleton is a wiring mistake whose symptom appears one lifetime away from its cause. With it, the scoped registration answers inside a scope and the container's keeps its own lifetime outside one. Declared where nothing collides yet, the waiver stands: a container registration of the same name arriving later is admitted without declaring anything itself.

	   It admits substitution, not decoration. A scoped provider that resolves the name it is replacing re-enters itself, and the resolution is reported as the circular dependency it is; a decorator has to take the decorated service under its own name. */
	ReplacesContainerService bool
}

type Registrar

type Registrar interface {
	Register(serviceName string, provider any, options ...RegisterOption) error

	MustRegister(serviceName string, provider any, options ...RegisterOption)
}

type Resolver

type Resolver interface {
	Get(serviceName string) (any, error)

	MustGet(serviceName string) any

	GetByType(targetType reflect.Type) (any, error)

	MustGetByType(targetType reflect.Type) any

	Has(serviceName string) bool

	HasType(targetType reflect.Type) bool
}

type Scope

type Scope interface {
	Resolver

	ScopedRegistrar

	OverrideService

	Close() error
}

type ScopeManager

type ScopeManager interface {
	NewScope() Scope

	RegisterScoped(serviceName string, provider any, options ...RegisterOption) error

	MustRegisterScoped(serviceName string, provider any, options ...RegisterOption)
}
ScopeManager makes scopes and declares what they will hold. The two belong together: a scope does not exist until a request arrives, and the framework is what creates one, so the services a scope owns have to be declared at boot by whatever will be making the scopes rather than on a scope that is not there yet.

A registration made here reaches every scope created afterwards; the ones already running keep the plan they were created with. Scope carries the same verbs for the rare case of adding a service to one live scope.

type ScopedRegistrar added in v2.13.0

type ScopedRegistrar interface {
	RegisterScoped(serviceName string, provider any, options ...RegisterOption) error

	MustRegisterScoped(serviceName string, provider any, options ...RegisterOption)
}
ScopedRegistrar registers services whose lifetime is one scope: built lazily on the first Get through that scope, held for as long as it lives, closed when it closes. The root container never sees them, and two scopes resolving the same name never meet.

It is deliberately not a Registrar, and it does not embed one. The two registrations differ only in lifetime, and a provider handed to the wrong one is a mistake the compiler cannot see when both spell the same verb: a container provider registered as scoped is rebuilt and torn down once per request without ever failing. Go interfaces are structural, so a marker type carrying Registrar's own method set would be satisfied by a container registrar and would catch nothing in either direction. The verb at the call site is therefore the declaration, and the two method sets are kept disjoint so a registrar handed to the wrong hook is a compile error rather than a convention.

type ServiceDescription added in v2.13.0

type ServiceDescription struct {
	Name     string
	Lifetime string
	IsBuilt  bool
	TypeName string
}

ServiceDescription is what a container can say about a registration without running its provider: the name, which lifetime owns it, whether an instance already exists, and the type — read from the built instance when there is one, from the provider's declared return type otherwise. It exists so an introspection command can list a container without building it.

Jump to

Keyboard shortcuts

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