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}