github.com/MontFerret/ferret@v0.18.0/pkg/drivers/common/lazy.go (about) 1 package common 2 3 import ( 4 "context" 5 "sync" 6 7 "github.com/MontFerret/ferret/pkg/runtime/core" 8 "github.com/MontFerret/ferret/pkg/runtime/values" 9 ) 10 11 type ( 12 // LazyValueFactory represents a value initializer 13 LazyValueFactory func(ctx context.Context) (core.Value, error) 14 15 // LazyValue represents a value with late initialization 16 LazyValue struct { 17 mu sync.Mutex 18 factory LazyValueFactory 19 ready bool 20 value core.Value 21 err error 22 } 23 ) 24 25 func NewLazyValue(factory LazyValueFactory) *LazyValue { 26 lz := new(LazyValue) 27 lz.ready = false 28 lz.factory = factory 29 lz.value = values.None 30 31 return lz 32 } 33 34 // Ready indicates whether the value is ready. 35 // @returns (Boolean) - Boolean value indicating whether the value is ready. 36 func (lv *LazyValue) Ready() bool { 37 lv.mu.Lock() 38 defer lv.mu.Unlock() 39 40 return lv.ready 41 } 42 43 // Read returns an underlying value. 44 // Not thread safe. Should not mutated. 45 // @returns (Value) - Underlying value if successfully loaded, otherwise error 46 func (lv *LazyValue) Read(ctx context.Context) (core.Value, error) { 47 lv.mu.Lock() 48 defer lv.mu.Unlock() 49 50 if !lv.ready { 51 lv.load(ctx) 52 } 53 54 return lv.value, lv.err 55 } 56 57 // Mutate safely mutates an underlying value. 58 // Loads a value if it's not ready. 59 // Thread safe. 60 func (lv *LazyValue) Mutate(ctx context.Context, mutator func(v core.Value, err error)) { 61 lv.mu.Lock() 62 defer lv.mu.Unlock() 63 64 if !lv.ready { 65 lv.load(ctx) 66 } 67 68 mutator(lv.value, lv.err) 69 } 70 71 // MutateIfReady safely mutates an underlying value only if it's ready. 72 func (lv *LazyValue) MutateIfReady(mutator func(v core.Value, err error)) { 73 lv.mu.Lock() 74 defer lv.mu.Unlock() 75 76 if lv.ready { 77 mutator(lv.value, lv.err) 78 } 79 } 80 81 // Reload resets the storage and loads data. 82 func (lv *LazyValue) Reload(ctx context.Context) { 83 lv.mu.Lock() 84 defer lv.mu.Unlock() 85 86 lv.resetInternal() 87 lv.load(ctx) 88 } 89 90 // Reset resets the storage. 91 // Next call of Read will trigger the factory function again. 92 func (lv *LazyValue) Reset() { 93 lv.mu.Lock() 94 defer lv.mu.Unlock() 95 96 lv.resetInternal() 97 } 98 99 func (lv *LazyValue) resetInternal() { 100 lv.ready = false 101 lv.value = values.None 102 lv.err = nil 103 } 104 105 func (lv *LazyValue) load(ctx context.Context) { 106 val, err := lv.factory(ctx) 107 108 if err == nil { 109 lv.value = val 110 lv.err = nil 111 } else { 112 lv.value = values.None 113 lv.err = err 114 } 115 116 lv.ready = true 117 }