Commit 7602542c authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 00a3c085
......@@ -178,6 +178,53 @@ func (mc *mergeCtx) Value(key interface{}) interface{} {
return mc.ctx2.Value(key)
}
// ----------------------------------------
// chanCtx wraps channel into context.Context interface.
type chanCtx struct {
done <-chan struct{}
}
// MergeChan merges context and channel into 1 context.
//
// MergeChan, similarly to Merge, provides resulting context which:
//
// - is done when ctx1 is done or done2 is closed, or cancel called, whichever happens first,
// - has the same deadline as ctx1,
// - has the same associated values as ctx1.
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete.
func MergeChan(ctx1 context.Context, done2 <-chan struct{}) (context.Context, context.CancelFunc) {
return Merge(ctx1, chanCtx{done2})
}
// Done implements context.Context .
func (c chanCtx) Done() <-chan struct{} {
return c.done
}
// Err implements context.Context .
func (c chanCtx) Err() error {
select {
case <-c.done:
return context.Canceled
default:
return nil
}
}
// Deadline implements context.Context .
func (c chanCtx) Deadline() (time.Time, bool) {
return time.Time{}, false
}
// Value implements context.Context .
func (c chanCtx) Value(key interface{}) interface{} {
return nil
}
// Cancelled reports whether an error is due to a canceled context.
//
......
......@@ -34,7 +34,7 @@ func TestMerge(t *testing.T) {
ctx1 = context.WithValue(ctx1, 1, "hello")
ctx2 = context.WithValue(ctx2, 2, "world")
mc, _ := Merge(ctx1, ctx2)
mc, __ := Merge(ctx1, ctx2); defer __()
assertEq := func(a, b interface{}) {
t.Helper()
......@@ -67,7 +67,7 @@ func TestMerge(t *testing.T) {
assertEq(mc.Err(), context.Canceled)
////////
mc, _ = Merge(ctx1, bg)
mc, __ = Merge(ctx1, bg); defer __()
assertEq(mc.Value(1), "hello")
assertEq(mc.Value(2), nil)
assertEq(mc.Value(3), nil)
......@@ -89,15 +89,55 @@ func TestMerge(t *testing.T) {
<-mc.Done()
assertEq(mc.Err(), context.Canceled)
////////
ctx1, cancel1 = context.WithCancel(bg)
ctx1 = context.WithValue(ctx1, 3, "zzz")
done2 := make(chan struct{})
mc, __ = MergeChan(ctx1, done2); defer __()
assertEq(mc.Value(1), nil)
assertEq(mc.Value(2), nil)
assertEq(mc.Value(3), "zzz")
d, ok = mc.Deadline()
if !(d == t0 && ok == false) {
t.Fatal("deadline must be unset")
}
assertEq(mc.Err(), nil)
select {
case <-mc.Done():
t.Fatal("done before any parent done")
default:
}
close(done2)
<-mc.Done()
assertEq(mc.Err(), context.Canceled)
done2 = make(chan struct{})
mc, __ = MergeChan(ctx1, done2); defer __()
select {
case <-mc.Done():
t.Fatal("done before any parent done")
default:
}
cancel1()
<-mc.Done()
assertEq(mc.Err(), context.Canceled)
////////
t1 := t0.AddDate(7777, 1, 1)
t2 := t0.AddDate(9999, 1, 1)
ctx1, _ = context.WithDeadline(bg, t1)
ctx2, _ = context.WithDeadline(bg, t2)
ctx1, __ = context.WithDeadline(bg, t1); defer __()
ctx2, __ = context.WithDeadline(bg, t2); defer __()
checkDeadline := func(a, b context.Context, tt time.Time) {
t.Helper()
m, _ := Merge(a, b)
m, __ := Merge(a, b); defer __()
d, ok := m.Deadline()
if !ok {
t.Fatal("no deadline returned")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment