Browse Source

wait: init

Blake Mizerany 11 years ago
parent
commit
f9c4ba3ea3
2 changed files with 85 additions and 0 deletions
  1. 34 0
      wait/wait.go
  2. 51 0
      wait/wait_test.go

+ 34 - 0
wait/wait.go

@@ -0,0 +1,34 @@
+package wait
+
+import "sync"
+
+type Waiter struct {
+	l sync.Mutex
+	m map[int64]chan interface{}
+}
+
+func New() Waiter {
+	return Waiter{m: make(map[int64]chan interface{})}
+}
+
+func (w Waiter) Register(id int64) <-chan interface{} {
+	w.l.Lock()
+	defer w.l.Unlock()
+	ch := w.m[id]
+	if ch == nil {
+		ch = make(chan interface{}, 1)
+		w.m[id] = ch
+	}
+	return ch
+}
+
+func (w Waiter) Trigger(id int64, x interface{}) {
+	w.l.Lock()
+	ch := w.m[id]
+	delete(w.m, id)
+	w.l.Unlock()
+	if ch != nil {
+		ch <- x
+		close(ch)
+	}
+}

+ 51 - 0
wait/wait_test.go

@@ -0,0 +1,51 @@
+package wait
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestWait(t *testing.T) {
+	const eid = 1
+	wt := New()
+	ch := wt.Register(eid)
+	wt.Trigger(eid, "foo")
+	v := <-ch
+	if g, w := fmt.Sprintf("%v (%T)", v, v), "foo (string)"; g != w {
+		t.Errorf("<-ch = %v, want %v", g, w)
+	}
+
+	if g := <-ch; g != nil {
+		t.Errorf("unexpected non-nil value: %v (%T)", g, g)
+	}
+}
+
+func TestRegisterDupSuppression(t *testing.T) {
+	const eid = 1
+	wt := New()
+	ch1 := wt.Register(eid)
+	ch2 := wt.Register(eid)
+	wt.Trigger(eid, "foo")
+	<-ch1
+	g := <-ch2
+	if g != nil {
+		t.Errorf("unexpected non-nil value: %v (%T)", g, g)
+	}
+}
+
+func TestTriggerDupSuppression(t *testing.T) {
+	const eid = 1
+	wt := New()
+	ch := wt.Register(eid)
+	wt.Trigger(eid, "foo")
+	wt.Trigger(eid, "bar")
+
+	v := <-ch
+	if g, w := fmt.Sprintf("%v (%T)", v, v), "foo (string)"; g != w {
+		t.Errorf("<-ch = %v, want %v", g, w)
+	}
+
+	if g := <-ch; g != nil {
+		t.Errorf("unexpected non-nil value: %v (%T)", g, g)
+	}
+}