channel.go (3521B)
1 package channel 2 3 import ( 4 "context" 5 "reflect" 6 "slices" 7 "time" 8 ) 9 10 // Drain the provided channel. 11 func Drain[T any](ch <-chan T) { 12 for range ch { 13 } 14 } 15 16 // TryReceive selects on a channel returning true if there was a value. 17 func TryReceive[T any](ch <-chan T) (t T, ok bool) { 18 select { 19 case t = <-ch: 20 ok = true 21 default: 22 } 23 return t, ok 24 } 25 26 // TrySend attempts a sends on a channel returning true if success. 27 func TrySend[T any](ch chan<- T, t T) bool { 28 select { 29 case ch <- t: 30 return true 31 default: 32 return false 33 } 34 } 35 36 // ReceiveIn selects on the provided channel up to duration `d` and returns the value. 37 // If the duration elapses, the function returns the zero value of `T` and false. 38 func ReceiveIn[T any](ch <-chan T, d time.Duration) (T, bool) { 39 timer := time.NewTimer(d) 40 select { 41 case t := <-ch: 42 return t, true 43 case <-timer.C: 44 return *new(T), false 45 } 46 } 47 48 // Collect all values from a channel into a slice. 49 func Collect[T any](in <-chan T) []T { 50 out := []T{} 51 for t := range in { 52 out = append(out, t) 53 } 54 return out 55 } 56 57 // CollectAllCtx buffers every value received value into a slice until all input channels are closed 58 // or the context is cancelled. 59 func CollectAllCtx[T any](ctx context.Context, chs ...chan T) []T { 60 out := []T{} 61 for v := range FanInCtx(ctx, chs...) { 62 out = append(out, v) 63 } 64 return out 65 } 66 67 // CollectAll buffers every value received value into a slice until all input channels are closed. 68 func CollectAll[T any](chs ...chan T) (out []T) { 69 return CollectAllCtx(context.Background(), chs...) 70 } 71 72 // BufferedSend uses slice allocation to buffer items providing a dynamically 73 // buffered channel send. This send will never block. 74 // 75 // If the channel is open, we send on it. 76 // If the channel is full, we select off the slice, append to it and send it 77 // back onto the channel. 78 // 79 // The loop will drain the channel until it becomes available to send. After 80 // the function returns, the value v is guaranteed to be sent on the channel, 81 // however it is not guaranteed that this is the only value sent. 82 // 83 // The input channel MUST have capacity of 1. 84 func BufferedSend[S ~[]E, E any](in chan S, v E) { 85 if cap(in) != 1 { 86 panic("BufferedSend is only valid for single buffered channels") 87 } 88 89 var items S = []E{v} 90 91 for { 92 select { 93 case buf := <-in: 94 items = append(buf, items...) 95 case in <- items: 96 return 97 } 98 } 99 } 100 101 // FanIn returns a channel that emits every value received from the input channel set. 102 // The output channel is closed when all input channels are closed. 103 func FanIn[T any](chs ...chan T) chan T { 104 return FanInCtx(context.Background(), chs...) 105 } 106 107 // FanInCtx returns a channel that emits every value received from the input channel set. 108 // The output channel is closed when all input channels are closed, or when the context 109 // is cancelled. 110 func FanInCtx[T any](ctx context.Context, chs ...chan T) chan T { 111 out := make(chan T) 112 113 go func() { 114 defer close(out) 115 116 cases := make([]reflect.SelectCase, 0, len(chs)+1) 117 118 cases = append(cases, reflect.SelectCase{ 119 Dir: reflect.SelectRecv, 120 Chan: reflect.ValueOf(ctx.Done()), 121 }) 122 123 for _, ch := range chs { 124 cases = append(cases, reflect.SelectCase{ 125 Dir: reflect.SelectRecv, 126 Chan: reflect.ValueOf(ch), 127 }) 128 } 129 130 for len(cases) > 1 { 131 ii, recv, ok := reflect.Select(cases) 132 if ok { 133 out <- recv.Interface().(T) 134 } else { 135 cases = slices.Delete(cases, ii, ii+1) 136 } 137 if ii == 0 { 138 // This is always the ctx.Done channel. 139 return 140 } 141 } 142 }() 143 144 return out 145 }