Skip to content

Commit 49b2298

Browse files
authored
pkg/utils: add LazyLoadCtx variant (#1496)
* pkg/utils: add LazyLoadCtx variant * add docs
1 parent cbb8fcc commit 49b2298

File tree

1 file changed

+43
-3
lines changed

1 file changed

+43
-3
lines changed

pkg/utils/lazy.go

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
package utils
22

33
import (
4+
"context"
45
"sync"
56
)
67

8+
// LazyLoad lazily loads a T when Get is called.
79
type LazyLoad[T any] struct {
810
f func() (T, error)
911
state T
1012
ok bool
1113
lock sync.Mutex
1214
}
1315

16+
// NewLazyLoad returns a new LazyLoad.
1417
func NewLazyLoad[T any](f func() (T, error)) *LazyLoad[T] {
15-
return &LazyLoad[T]{
16-
f: f,
17-
}
18+
return &LazyLoad[T]{f: f}
1819
}
1920

21+
// Get returns the cached value, or loads it lazily if necessary.
2022
func (l *LazyLoad[T]) Get() (out T, err error) {
2123
l.lock.Lock()
2224
defer l.lock.Unlock()
@@ -34,3 +36,41 @@ func (l *LazyLoad[T]) Reset() {
3436
defer l.lock.Unlock()
3537
l.ok = false
3638
}
39+
40+
// LazyLoadCtx is like LazyLoad, but supports [context.Context]
41+
type LazyLoadCtx[T any] struct {
42+
f func(context.Context) (T, error)
43+
state T
44+
ok bool
45+
mu chan struct{}
46+
}
47+
48+
// NewLazyLoadCtx returns a new LazyLoadCtx.
49+
func NewLazyLoadCtx[T any](f func(context.Context) (T, error)) *LazyLoadCtx[T] {
50+
return &LazyLoadCtx[T]{f: f, mu: make(chan struct{}, 1)}
51+
}
52+
53+
// Get returns the cached value, or loads it lazily if necessary.
54+
func (l *LazyLoadCtx[T]) Get(ctx context.Context) (out T, err error) {
55+
select {
56+
case <-ctx.Done():
57+
return out, ctx.Err()
58+
case l.mu <- struct{}{}: // lock
59+
}
60+
defer func() { <-l.mu }() // unlock
61+
62+
if l.ok {
63+
return l.state, nil
64+
}
65+
l.state, err = l.f(ctx)
66+
l.ok = err == nil
67+
return l.state, err
68+
}
69+
70+
func (l *LazyLoadCtx[T]) Reset() {
71+
select {
72+
case l.mu <- struct{}{}: // lock
73+
}
74+
defer func() { <-l.mu }() // unlock
75+
l.ok = false
76+
}

0 commit comments

Comments
 (0)