summaryrefslogtreecommitdiff
path: root/pkg/sync/chan.go
blob: 91501f9cb78a99c2983867c22f6832146b773964 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package sync

import "context"

func OrDone[T any](ctx context.Context, in <-chan T) <-chan T {
	if in == nil {
		// we only expect this to happen during development
		panic("in-channel is nil")
	}

	out := make(chan T)
	go func() {
		defer close(out)
		for {
			v, ok := CancelOrReceive(ctx, in)
			if !ok {
				return
			}

			if !CancelOrSend(ctx, out, v) {
				return
			}
		}
	}()
	return out
}

// CancelOrReceive is trying to solve the same problem as OrDone but does so
// without an extra goroutine.
func CancelOrReceive[T any](ctx context.Context, in <-chan T) (v T, ok bool) {
	select {
	case <-ctx.Done():
		return // <zero value of type T>, false
	case v, ok = <-in:
		return // v, ok
	}
}

// CancelOrSend is a helper function to simplify sending values to channels
// while keeping the context in mind.
func CancelOrSend[T any](ctx context.Context, out chan<- T, val T) bool {
	select {
	case <-ctx.Done():
		return false
	case out <- val:
		return true
	}
}