67 lines
1.3 KiB
Go
67 lines
1.3 KiB
Go
package shadow
|
|
|
|
import (
|
|
"container/list"
|
|
"sync"
|
|
)
|
|
|
|
// OrderedValue is a struct that keeps track of a value in the order
|
|
// it is set. Each time Value() is called, it will return the most recent
|
|
// calls value then discard it.
|
|
//
|
|
// This is unlike Value that returns the same value once it is set.
|
|
type OrderedValue struct {
|
|
lock sync.Mutex
|
|
values *list.List
|
|
waiters *list.List
|
|
}
|
|
|
|
// Value returns the last value that was set, or blocks until one
|
|
// is received.
|
|
func (w *OrderedValue) Value() interface{} {
|
|
w.lock.Lock()
|
|
|
|
// If we have a pending value already, use it
|
|
if w.values != nil && w.values.Len() > 0 {
|
|
front := w.values.Front()
|
|
w.values.Remove(front)
|
|
w.lock.Unlock()
|
|
return front.Value
|
|
}
|
|
|
|
// No pending value, create a waiter
|
|
if w.waiters == nil {
|
|
w.waiters = list.New()
|
|
}
|
|
|
|
var val Value
|
|
w.waiters.PushBack(&val)
|
|
w.lock.Unlock()
|
|
|
|
// Return the value once we have it
|
|
return val.Value()
|
|
}
|
|
|
|
// SetValue sets the latest value.
|
|
func (w *OrderedValue) SetValue(v interface{}) {
|
|
w.lock.Lock()
|
|
defer w.lock.Unlock()
|
|
|
|
// If we have a waiter, notify it
|
|
if w.waiters != nil && w.waiters.Len() > 0 {
|
|
front := w.waiters.Front()
|
|
w.waiters.Remove(front)
|
|
|
|
val := front.Value.(*Value)
|
|
val.SetValue(v)
|
|
return
|
|
}
|
|
|
|
// Add it to the list of values
|
|
if w.values == nil {
|
|
w.values = list.New()
|
|
}
|
|
|
|
w.values.PushBack(v)
|
|
}
|