1
0
mirror of https://github.com/MontFerret/ferret.git synced 2024-12-16 11:37:36 +02:00
ferret/pkg/html/common/lazy.go
2018-10-07 21:32:30 -04:00

99 lines
1.6 KiB
Go

package common
import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"sync"
)
type (
LazyFactory func() (core.Value, error)
LazyValue struct {
sync.Mutex
factory LazyFactory
ready bool
value core.Value
err error
}
)
func NewLazyValue(factory LazyFactory) *LazyValue {
lz := new(LazyValue)
lz.ready = false
lz.factory = factory
lz.value = values.None
return lz
}
/*
* Indicates whether the value is ready.
* @returns (Boolean) - Boolean value indicating whether the value is ready.
*/
func (lv *LazyValue) Ready() bool {
lv.Lock()
defer lv.Unlock()
return lv.ready
}
/*
* Returns an underlying value.
* Not thread safe. Should not mutated.
* @returns (Value) - Underlying value if successfully loaded, otherwise error
*/
func (lv *LazyValue) Read() (core.Value, error) {
lv.Lock()
defer lv.Unlock()
if !lv.ready {
lv.load()
}
return lv.value, lv.err
}
/*
* Safely mutates an underlying value.
* Loads a value if it's not ready.
* Thread safe.
*/
func (lv *LazyValue) Write(writer func(v core.Value, err error)) {
lv.Lock()
defer lv.Unlock()
if !lv.ready {
lv.load()
}
writer(lv.value, lv.err)
}
/*
* Resets the storage.
* Next call of Read will trigger the factory function again.
*/
func (lv *LazyValue) Reset() {
lv.Lock()
defer lv.Unlock()
lv.ready = false
lv.value = values.None
lv.err = nil
}
func (lv *LazyValue) load() {
val, err := lv.factory()
if err == nil {
lv.value = val
lv.err = nil
} else {
lv.value = values.None
lv.err = err
}
lv.ready = true
}