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  }