lazy

package
v1.76.0 Latest Latest
Warning

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

Go to latest
Published: Oct 10, 2024 License: BSD-3-Clause Imports: 3 Imported by: 12

Documentation

Overview

Package lazy provides types for lazily initialized values.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func GFunc

func GFunc[T any](fill func() T) func() T

GFunc wraps a function to make it lazy.

The returned function calls fill the first time it's called, and returns fill's result on every subsequent call.

The returned function is not safe for concurrent use.

func GFuncErr

func GFuncErr[T any](fill func() (T, error)) func() (T, error)

SyncFuncErr wraps a function to make it lazy.

The returned function calls fill the first time it's called, and returns fill's results on every subsequent call.

The returned function is not safe for concurrent use.

func SyncFunc

func SyncFunc[T any](fill func() T) func() T

SyncFunc wraps a function to make it lazy.

The returned function calls fill the first time it's called, and returns fill's result on every subsequent call.

The returned function is safe for concurrent use.

func SyncFuncErr

func SyncFuncErr[T any](fill func() (T, error)) func() (T, error)

SyncFuncErr wraps a function to make it lazy.

The returned function calls fill the first time it's called, and returns fill's results on every subsequent call.

The returned function is safe for concurrent use.

Types

type DeferredFuncs added in v1.76.0

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

DeferredFuncs allows one or more funcs to be deferred until the owner's DeferredInit.Do method is called for the first time.

DeferredFuncs is safe for concurrent use.

func (*DeferredFuncs) Defer added in v1.76.0

func (d *DeferredFuncs) Defer(f func() error) bool

Defer adds a function to be called when DeferredInit.Do is called for the first time. It returns true on success, or false if DeferredInit.Do has already been called.

func (*DeferredFuncs) MustDefer added in v1.76.0

func (d *DeferredFuncs) MustDefer(f func() error)

MustDefer is like DeferredFuncs.Defer, but panics if DeferredInit.Do has already been called.

type DeferredInit added in v1.76.0

type DeferredInit struct {
	DeferredFuncs
}

DeferredInit allows one or more funcs to be deferred until DeferredInit.Do is called for the first time.

DeferredInit is safe for concurrent use.

Example
// DeferredInit allows both registration and invocation of the
// deferred funcs. It should remain internal to the code that "owns" it.
var di DeferredInit
// Deferred funcs will not be executed until [DeferredInit.Do] is called.
deferred := di.Defer(func() error {
	fmt.Println("Internal init")
	return nil
})
// [DeferredInit.Defer] reports whether the function was successfully deferred.
// A func can only fail to defer if [DeferredInit.Do] has already been called.
if deferred {
	fmt.Printf("Internal init has been deferred\n\n")
}

// If necessary, the value returned by [DeferredInit.Funcs]
// can be shared with external code to facilitate deferring
// funcs without allowing it to call [DeferredInit.Do].
df := di.Funcs()
// If a certain init step must be completed for the program
// to function correctly, and failure to defer it indicates
// a coding error, use [DeferredFuncs.MustDefer] instead of
// [DeferredFuncs.Defer]. It panics if Do() has already been called.
df.MustDefer(func() error {
	fmt.Println("External init - 1")
	return nil
})
// A deferred func may return an error to indicate a failed init.
// If a deferred func returns an error, execution stops
// and the error is propagated to the caller.
df.Defer(func() error {
	fmt.Println("External init - 2")
	return errors.New("bang!")
})
// The deferred function below won't be executed.
df.Defer(func() error {
	fmt.Println("Unreachable")
	return nil
})

// When [DeferredInit]'s owner needs initialization to be completed,
// it can call [DeferredInit.Do]. When called for the first time,
// it invokes the deferred funcs.
err := di.Do()
if err != nil {
	fmt.Printf("Deferred init failed: %v\n", err)
}
// [DeferredInit.Do] is safe for concurrent use and can be called
// multiple times by the same or different goroutines.
// However, the deferred functions are never invoked more than once.
// If the deferred init fails on the first attempt, all subsequent
// [DeferredInit.Do] calls will return the same error.
if err = di.Do(); err != nil {
	fmt.Printf("Deferred init failed: %v\n\n", err)
}

// Additionally, all subsequent attempts to defer a function will fail
// after [DeferredInit.Do] has been called.
deferred = di.Defer(func() error {
	fmt.Println("Unreachable")
	return nil
})
if !deferred {
	fmt.Println("Cannot defer a func once init has been completed")
}
Output:

Internal init has been deferred

Internal init
External init - 1
External init - 2
Deferred init failed: bang!
Deferred init failed: bang!

Cannot defer a func once init has been completed

func (*DeferredInit) Do added in v1.76.0

func (d *DeferredInit) Do() error

Do calls previously deferred init functions if it is being called for the first time on this instance of DeferredInit. It stops and returns an error if any init function returns an error.

It is safe for concurrent use, and the deferred init is guaranteed to have been completed, either successfully or with an error, when Do() returns.

func (*DeferredInit) Funcs added in v1.76.0

func (d *DeferredInit) Funcs() *DeferredFuncs

Funcs is a shorthand for &d.DeferredFuncs. The returned value can safely be passed to external code, allowing to defer init funcs without also exposing DeferredInit.Do.

type GValue

type GValue[T any] struct {
	V T
	// contains filtered or unexported fields
}

GValue is a lazily computed value.

Use either Get or GetErr, depending on whether your fill function returns an error.

Recursive use of a GValue from its own fill function will panic.

GValue is not safe for concurrent use. (Mnemonic: G is for one Goroutine, which isn't strictly true if you provide your own synchronization between goroutines, but in practice most of our callers have been using it within a single goroutine.)

func (*GValue[T]) Get

func (z *GValue[T]) Get(fill func() T) T

Get returns z's value, calling fill to compute it if necessary. f is called at most once.

func (*GValue[T]) GetErr

func (z *GValue[T]) GetErr(fill func() (T, error)) (T, error)

GetErr returns z's value, calling fill to compute it if necessary. f is called at most once, and z remembers both of fill's outputs.

func (*GValue[T]) MustSet

func (z *GValue[T]) MustSet(val T)

MustSet sets z's value to val, or panics if z already has a value.

func (*GValue[T]) Set

func (z *GValue[T]) Set(v T) bool

Set attempts to set z's value to val, and reports whether it succeeded. Set only succeeds if none of Get/GetErr/Set have been called before.

type SyncValue

type SyncValue[T any] struct {
	// contains filtered or unexported fields
}

SyncValue is a lazily computed value.

Use either Get or GetErr, depending on whether your fill function returns an error.

Recursive use of a SyncValue from its own fill function will deadlock.

SyncValue is safe for concurrent use.

func (*SyncValue[T]) Get

func (z *SyncValue[T]) Get(fill func() T) T

Get returns z's value, calling fill to compute it if necessary. f is called at most once.

func (*SyncValue[T]) GetErr

func (z *SyncValue[T]) GetErr(fill func() (T, error)) (T, error)

GetErr returns z's value, calling fill to compute it if necessary. f is called at most once, and z remembers both of fill's outputs.

func (*SyncValue[T]) MustSet

func (z *SyncValue[T]) MustSet(val T)

MustSet sets z's value to val, or panics if z already has a value.

func (*SyncValue[T]) Peek added in v1.70.0

func (z *SyncValue[T]) Peek() (v T, ok bool)

Peek returns z's value and a boolean indicating whether the value has been set successfully. If a value has not been set, the zero value of T is returned.

This function is safe to call concurrently with Get/GetErr/Set, but it's undefined whether a value set by a concurrent call will be visible to Peek.

To get any error that's been set, use PeekErr.

If GetErr's fill function returned a valid T and an non-nil error, Peek discards that valid T value. PeekErr returns both.

func (*SyncValue[T]) PeekErr added in v1.70.0

func (z *SyncValue[T]) PeekErr() (v T, err error, ok bool)

PeekErr returns z's value and error and a boolean indicating whether the value or error has been set. If ok is false, T and err are the zero value.

This function is safe to call concurrently with Get/GetErr/Set, but it's undefined whether a value set by a concurrent call will be visible to Peek.

Unlike Peek, PeekErr reports ok if either v or err has been set, not just v, and returns both the T and err returned by GetErr's fill function.

func (*SyncValue[T]) Set

func (z *SyncValue[T]) Set(val T) bool

Set attempts to set z's value to val, and reports whether it succeeded. Set only succeeds if none of Get/GetErr/Set have been called before.

func (*SyncValue[T]) SetForTest added in v1.72.0

func (z *SyncValue[T]) SetForTest(tb TB, val T, err error)

SetForTest sets z's value and error. It's used in tests only and reverts z's state back when tb and all its subtests complete. It is not safe for concurrent use and must not be called concurrently with any SyncValue methods, including another call to itself.

type TB added in v1.72.0

type TB interface {
	Helper()
	Cleanup(func())
}

TB is a subset of testing.TB that we use to set up test helpers. It's defined here to avoid pulling in the testing package.

Jump to

Keyboard shortcuts

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