helper/shadow: Value.Close

This commit is contained in:
Mitchell Hashimoto 2016-10-04 20:14:45 -07:00
parent 3e7665db09
commit d2fb630df8
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
2 changed files with 57 additions and 0 deletions

View File

@ -1,12 +1,24 @@
package shadow package shadow
import ( import (
"errors"
"sync" "sync"
) )
// ErrClosed is returned by any closed values.
//
// A "closed value" is when the shadow has been notified that the real
// side is complete and any blocking values will _never_ be satisfied
// in the future. In this case, this error is returned. If a value is already
// available, that is still returned.
var ErrClosed = errors.New("shadow closed")
// Value is a struct that coordinates a value between two // Value is a struct that coordinates a value between two
// parallel routines. It is similar to atomic.Value except that when // parallel routines. It is similar to atomic.Value except that when
// Value is called if it isn't set it will wait for it. // Value is called if it isn't set it will wait for it.
//
// The Value can be closed with Close, which will cause any future
// blocking operations to return immediately with ErrClosed.
type Value struct { type Value struct {
lock sync.Mutex lock sync.Mutex
cond *sync.Cond cond *sync.Cond
@ -14,6 +26,22 @@ type Value struct {
valueSet bool valueSet bool
} }
// Close closes the value. This can never fail. For a definition of
// "close" see the struct docs.
func (w *Value) Close() error {
w.lock.Lock()
set := w.valueSet
w.lock.Unlock()
// If we haven't set the value, set it
if !set {
w.SetValue(ErrClosed)
}
// Done
return nil
}
// Value returns the value that was set. // Value returns the value that was set.
func (w *Value) Value() interface{} { func (w *Value) Value() interface{} {
w.lock.Lock() w.lock.Lock()

View File

@ -41,3 +41,32 @@ func TestValue(t *testing.T) {
t.Fatalf("bad: %#v", val) t.Fatalf("bad: %#v", val)
} }
} }
func TestValueClose(t *testing.T) {
var v Value
// Close
v.Close()
// Verify
val := v.Value()
if val != ErrClosed {
t.Fatalf("bad: %#v", val)
}
}
func TestValueClose_existing(t *testing.T) {
var v Value
// Set the value
v.SetValue(42)
// Close
v.Close()
// Verify
val := v.Value()
if val != 42 {
t.Fatalf("bad: %#v", val)
}
}