11package utils
22
33import (
4+ "context"
45 "sync"
56)
67
8+ // LazyLoad lazily loads a T when Get is called.
79type 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.
1417func 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.
2022func (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