plumbing

package
v2.2.0 Latest Latest
Warning

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

Go to latest
Published: Sep 9, 2026 License: Apache-2.0 Imports: 2 Imported by: 0

Documentation

Overview

Package plumbing defines generic types for the dependency injection mechanisms in rig.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Factory

type Factory[R any, T any] func(R) (T, bool)

Factory is a function that takes a parameter of type R and returns a value of type T along with a boolean reporting whether it could handle R.

A Factory may be called concurrently with itself, for the same input as well as for different ones, so it must not depend on being called one at a time.

type LazyService

type LazyService[S any, T any] struct {
	// contains filtered or unexported fields
}

LazyService is a generic lazy-initializer that calls a provider function once and memoizes the result.

func NewLazyService

func NewLazyService[S any, T any](get func(S) (T, error), source S) *LazyService[S, T]

NewLazyService creates a new instance of LazyService with the given provider function.

func (*LazyService[S, T]) Get

func (s *LazyService[S, T]) Get() (T, error)

Get retrieves the service value, initializing it if necessary.

type Provider

type Provider[R any, T any] struct {
	// contains filtered or unexported fields
}

Provider is a generic provider of values of type T that can be initialized with a value of type R.

func NewProvider

func NewProvider[R any, T any](err error) *Provider[R, T]

NewProvider creates a new instance of Provider. The error is returned if no factory can produce a value of type T.

func (*Provider[R, T]) Get

func (p *Provider[R, T]) Get(input R) (T, error)

Get returns the value from the first factory that reports a match, in registration order with any RegisterFirst factories ahead of the rest. If none of them match, the error supplied at creation time is returned.

A lookup never reorders the factories, so the result for a given input does not depend on what was looked up before it.

func (*Provider[R, T]) GetAll

func (p *Provider[R, T]) GetAll(input R) ([]T, error)

GetAll returns the values from every factory that reports a match, in registration order with any RegisterFirst factories ahead of the rest. If none of them match, the error supplied at creation time is returned.

func (*Provider[R, T]) Register

func (p *Provider[R, T]) Register(f Factory[R, T])

Register adds a new factory to the provider.

Factories are consulted in registration order and the first one to match wins, after any added with RegisterFirst.

Prefer factories that decide for themselves whether they apply to an input over relying on that order: a factory matching a superset of another's inputs should exclude the cases the more specific one handles, the way os.ResolveLinuxCompat stands down for any host os-release can identify. A registry a package exports stays open for registration, so it cannot know where a caller's factory will land, and a broad factory registered early otherwise keeps winning over a more specific one added later.

func (*Provider[R, T]) RegisterFirst added in v2.2.0

func (p *Provider[R, T]) RegisterFirst(f Factory[R, T])

RegisterFirst adds a factory at the front of the list, ahead of every factory already registered and every factory registered afterwards with Register. Where it is called more than once the most recent call is the one consulted first, so the last caller to ask for precedence gets it.

It is for a caller that has to take precedence over a factory the registry already holds: one matching a superset of the inputs their own factory handles, where self-exclusion is not available to them because the factory that would have to stand down is not theirs to change. A package registering factories into its own registry should use Register and have them decide from the input whether they apply.

The result of a lookup may be memoized by the caller of Get, so register before the first lookup rather than after.

Example

ExampleProvider_RegisterFirst shows a caller taking precedence over a factory the registry already holds. Registering their own would leave it behind the catch-all, which matches every input and is consulted first.

package main

import (
	"errors"
	"fmt"

	"github.com/k0sproject/rig/v2/plumbing"
)

func main() {
	registry := plumbing.NewProvider[string, string](errors.New("no factory available"))

	// Already in the registry, standing in for one of rig's built-ins.
	registry.Register(func(string) (string, bool) {
		return "builtin", true
	})

	registry.RegisterFirst(func(input string) (string, bool) {
		if input == "myhost" {
			return "mine", true
		}

		return "", false
	})

	mine, err := registry.Get("myhost")
	if err != nil {
		fmt.Println(err)

		return
	}
	other, err := registry.Get("otherhost")
	if err != nil {
		fmt.Println(err)

		return
	}
	fmt.Println(mine, other)
}
Output:
mine builtin

type Service

type Service[T any] interface {
	Get() (T, error)
}

Service is anything that can be retrieved via Get and that can fail and return an error.

Jump to

Keyboard shortcuts

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