type Value … type Result … func (r Result[T]) Get() (T, string, error) { … } // Func wraps a (thread-safe) function as a Value[T]. func Func[T any](fn func() (T, string, error)) Value[T] { … } type valueFunc … func (c valueFunc[T]) Get() (T, string, error) { … } // Static returns constant values. func Static[T any](value T, etag string) Value[T] { … } // Merge merges a of cached values. The merge function only gets called if any of // the dependency has changed. // // If any of the dependency returned an error before, or any of the // dependency returned an error this time, or if the mergeFn failed // before, then the function is run again. // // Note that this assumes there is no "partial" merge, the merge // function will remerge all the dependencies together everytime. Since // the list of dependencies is constant, there is no way to save some // partial merge information either. // // Also note that Golang map iteration is not stable. If the mergeFn // depends on the order iteration to be stable, it will need to // implement its own sorting or iteration order. func Merge[K comparable, T, V any](mergeFn func(results map[K]Result[T]) (V, string, error), caches map[K]Value[T]) Value[V] { … } // MergeList merges a list of cached values. The function only gets called if // any of the dependency has changed. // // The benefit of ListMerger over the basic Merger is that caches are // stored in an ordered list so the order of the cache will be // preserved in the order of the results passed to the mergeFn. // // If any of the dependency returned an error before, or any of the // dependency returned an error this time, or if the mergeFn failed // before, then the function is reran. // // Note that this assumes there is no "partial" merge, the merge // function will remerge all the dependencies together everytime. Since // the list of dependencies is constant, there is no way to save some // partial merge information either. func MergeList[T, V any](mergeFn func(results []Result[T]) (V, string, error), delegates []Value[T]) Value[V] { … } type listMerger … func (c *listMerger[T, V]) prepareResultsLocked() []Result[T] { … } func (c *listMerger[T, V]) needsRunningLocked(results []Result[T]) bool { … } func (c *listMerger[T, V]) Get() (V, string, error) { … } // Transform the result of another cached value. The transformFn will only be called // if the source has updated, otherwise, the result will be returned. // // If the dependency returned an error before, or it returns an error // this time, or if the transformerFn failed before, the function is // reran. func Transform[T, V any](transformerFn func(T, string, error) (V, string, error), source Value[T]) Value[V] { … } // Once calls Value[T].Get() lazily and only once, even in case of an error result. func Once[T any](d Value[T]) Value[T] { … } type once … func (c *once[T]) Get() (T, string, error) { … } type Replaceable … type Atomic … var _ … func (x *Atomic[T]) Store(val Value[T]) { … } func (x *Atomic[T]) Get() (T, string, error) { … } type LastSuccess … var _ … func (c *LastSuccess[T]) Get() (T, string, error) { … }