disl

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 23, 2024 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package disl is the dependency injection simple library.

Overview

A Locator object registers constructors of singleton values that could be usefull in your program. Such constructors are called "factories". The locator ensures that factories are called at most once, when needed. If a factory has arguments, they are provided by the Locator, recursively calling other factories if needed.

As a convenience, Locator registers themselves as singleton, hence a factory may have an argument of type *Locator.

Limitations

Cyclic dependencies are currently not detected by the package, silently resulting in deadlocks.

The package uses reflection, hence it is not lightning fast. You should use it when the application starts, to initialise long lasting objects.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	NotFactory  = errors.New("Wrong type for a factory")  // Factory's type is not handled.
	NotReceptor = errors.New("Wrong type for a receptor") // Receptor's type is not handled.
	NotFound    = errors.New("No binding")                // No factory for the requested type.
)

Functions

func Get

func Get[T any](loc *Locator) (singleton T, err error)

Get retrieves a singleton from the locator. It is a convenient function.

s := disl.Get[Service](loc)

is equivalent to

var s Service
loc.Inject(&s)

func GetFresh

func GetFresh[T any](loc *Locator) (value T, err error)

GetFresh returns a new value using a registered factory. It is a convenient function.

s := disl.GetFresh[Service](loc)

is equivalent to

var s Service
loc.Fresh(&s)

func SetSingleton

func SetSingleton[T any](loc *Locator, singleton T) error

SetSingleton registers a singleton service. It is roughly equivalent to

loc.Bind(func () T { return singleton })

except that since no factory has been bound to T, calls to *Locator.Fresh will result in NotFound errors.

Types

type Locator

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

func New

func New() *Locator

New constructs a brand new Locator. The new Locator has bindings only of type *Locator, providing itself for singleton values, and calling Sub() for fresh values.

func (*Locator) Bind

func (self *Locator) Bind(factory interface{}) error

Bind registers a factory for a type. The factory must be a function, and the type of its first returned value is the type it is associated to. If the factory has a second returned value, it must be of type error. The factory cannot have a third returned value.

The factory is called at most once to construct a singleton, when a call to Inject() (or Fresh()) depends on the associated type. The Locator provides singletons for all the arguments of the factory. This often results in other registered factories to be called. Cyclic dependencies are currently not detected and result in infinite loops.

func (*Locator) Fresh

func (self *Locator) Fresh(receptor interface{}) error

Fresh constructs a new value using a registered factory. The receptor must be a pointer the new value is assigned to. The receptor of this method cannot be a function.

Beware that the arguments given to the factory are still singleton values. If you want the factory to use fresh values, make it depend on *Locator and call Fresh() directly from the factory.

func (*Locator) Inject

func (self *Locator) Inject(chain ...interface{}) error

Inject retrieves singletons values from the locator.

Its arguments are receptors that are considered in the order they are provided. Each receptor may be either a pointer or a function. Pointer receptors get their pointed value assigned to the deduced value. For function receptors, each of their arguments is set to a deduced value and the function is executed. If a function receptor returns values, these values are stored to be used as deduced value for subsequent receptors. If the last returned value has type error, this value is not stored and Inject fails with the returned error if it is not nil.

The deduced value is the last stored value assignable to the requested type if there is one, or the singleton value registered for the requested type otherwise.

Example
loc := New()
var v int
loc.Inject(func() int { return 1 }, func() int { return 2 }, func() interface{} { return 3 }, &v)
fmt.Println(v)
Output:

2

func (*Locator) Sub

func (self *Locator) Sub() *Locator

Sub constructs a sub-locator of the current one. The sublocator initially has the same bindings as its parent, except for type *Locator for which the singleton value is the sublocator itself, and fresh values are sublocator of the sublocator. Calls to Bind on the sublocator does not change the bindings on the parent.

Jump to

Keyboard shortcuts

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