once.gno

2.15 Kb ยท 100 lines
  1// Package once provides utilities for one-time execution patterns.
  2// It extends the concept of sync.Once with error handling and panic options.
  3package once
  4
  5import (
  6	"errors"
  7)
  8
  9// Once represents a one-time execution guard
 10type Once struct {
 11	done    bool
 12	err     error
 13	paniced bool
 14	value   any // stores the result of the execution
 15}
 16
 17// New creates a new Once instance
 18func New() *Once {
 19	return &Once{}
 20}
 21
 22// Do executes fn only once and returns nil on subsequent calls
 23func (o *Once) Do(fn func()) {
 24	if o.done {
 25		return
 26	}
 27	defer func() { o.done = true }()
 28	fn()
 29}
 30
 31// DoErr executes fn only once and returns the same error on subsequent calls
 32func (o *Once) DoErr(fn func() error) error {
 33	if o.done {
 34		return o.err
 35	}
 36	defer func() { o.done = true }()
 37	o.err = fn()
 38	return o.err
 39}
 40
 41// DoOrPanic executes fn only once and panics on subsequent calls
 42func (o *Once) DoOrPanic(fn func()) {
 43	if o.done {
 44		panic("once: multiple execution attempted")
 45	}
 46	defer func() { o.done = true }()
 47	fn()
 48}
 49
 50// DoValue executes fn only once and returns its value, subsequent calls return the cached value
 51func (o *Once) DoValue(fn func() any) any {
 52	if o.done {
 53		return o.value
 54	}
 55	defer func() { o.done = true }()
 56	o.value = fn()
 57	return o.value
 58}
 59
 60// DoValueErr executes fn only once and returns its value and error
 61// Subsequent calls return the cached value and error
 62func (o *Once) DoValueErr(fn func() (any, error)) (any, error) {
 63	if o.done {
 64		return o.value, o.err
 65	}
 66	defer func() { o.done = true }()
 67	o.value, o.err = fn()
 68	return o.value, o.err
 69}
 70
 71// Reset resets the Once instance to its initial state
 72// This is mainly useful for testing purposes
 73func (o *Once) Reset() {
 74	o.done = false
 75	o.err = nil
 76	o.paniced = false
 77	o.value = nil
 78}
 79
 80// IsDone returns whether the Once has been executed
 81func (o *Once) IsDone() bool {
 82	return o.done
 83}
 84
 85// Error returns the error from the last execution if any
 86func (o *Once) Error() error {
 87	return o.err
 88}
 89
 90var (
 91	ErrNotExecuted = errors.New("once: not executed yet")
 92)
 93
 94// Value returns the stored value and an error if not executed yet
 95func (o *Once) Value() (any, error) {
 96	if !o.done {
 97		return nil, ErrNotExecuted
 98	}
 99	return o.value, nil
100}