1package chans
2
3import "runtime"
4
5// Ranger returns a Sender and a Receiver. The Receiver provides a
6// Next method to retrieve values. The Sender provides a Send method
7// to send values and a Close method to stop sending values. The Next
8// method indicates when the Sender has been closed, and the Send
9// method indicates when the Receiver has been freed.
10//
11// This is a convenient way to exit a goroutine sending values when
12// the receiver stops reading them.
13func Ranger[T any]() (*Sender[T], *Receiver[T]) {
14	c := make(chan T)
15	d := make(chan bool)
16	s := &Sender[T]{values: c, done: d}
17	r := &Receiver[T]{values: c, done: d}
18	runtime.SetFinalizer(r, r.finalize)
19	return s, r
20}
21
22// A sender is used to send values to a Receiver.
23type Sender[T any] struct {
24	values chan<- T
25	done <-chan bool
26}
27
28// Send sends a value to the receiver. It returns whether any more
29// values may be sent; if it returns false the value was not sent.
30func (s *Sender[T]) Send(v T) bool {
31	select {
32	case s.values <- v:
33		return true
34	case <-s.done:
35		return false
36	}
37}
38
39// Close tells the receiver that no more values will arrive.
40// After Close is called, the Sender may no longer be used.
41func (s *Sender[T]) Close() {
42	close(s.values)
43}
44
45// A Receiver receives values from a Sender.
46type Receiver[T any] struct {
47	values <-chan T
48	done chan<- bool
49}
50
51// Next returns the next value from the channel. The bool result
52// indicates whether the value is valid, or whether the Sender has
53// been closed and no more values will be received.
54func (r *Receiver[T]) Next() (T, bool) {
55	v, ok := <-r.values
56	return v, ok
57}
58
59// finalize is a finalizer for the receiver.
60func (r *Receiver[T]) finalize() {
61	close(r.done)
62}
63