Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions iter/channel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package iter

import "iter"

// FromChannel yields values from a channel.
//
// In order to avoid a deadlock, the channel must be closed before attempting
// to called `stop` on a pull-style iterator.
func FromChannel[V any](channel <-chan V) iter.Seq[V] {
return func(yield func(V) bool) {
for value := range channel {
if !yield(value) {
return
}
}
}
}

// ToChannel sends yielded values to a channel.
//
// The channel is closed when the iterator is exhausted. Beware of leaked go
// routines when using this function with an infinite iterator.
func ToChannel[V any](seq iter.Seq[V]) <-chan V {
channel := make(chan V)

go func() {
defer close(channel)

for value := range seq {
channel <- value
}
}()

return channel
}

// ToChannel is a convenience method for chaining [ToChannel] on [Iterator]s.
func (iterator Iterator[V]) ToChannel() <-chan V {
return ToChannel(iter.Seq[V](iterator))
}
86 changes: 86 additions & 0 deletions iter/channel_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package iter_test

import (
"fmt"
it "iter"
"testing"

"github.com/BooleanCat/go-functional/v2/future/slices"
"github.com/BooleanCat/go-functional/v2/internal/assert"
"github.com/BooleanCat/go-functional/v2/iter"
)

func ExampleFromChannel() {
items := make(chan int)

go func() {
defer close(items)
items <- 1
items <- 2
}()

for number := range iter.FromChannel(items) {
fmt.Println(number)
}

// Output:
// 1
// 2
}

func TestFromChannelTerminateEarly(t *testing.T) {
t.Parallel()

channel := make(chan int, 1)
defer close(channel)

channel <- 1
numbers := iter.FromChannel(channel)

_, stop := it.Pull(numbers)
stop()
}

func TestFromChannelEmpty(t *testing.T) {
t.Parallel()

channel := make(chan int)
close(channel)

assert.Empty[int](t, slices.Collect(iter.FromChannel(channel)))

}

func ExampleToChannel() {
channel := iter.ToChannel(slices.Values([]int{1, 2, 3}))

for number := range channel {
fmt.Println(number)
}

// Output:
// 1
// 2
// 3
}

func ExampleToChannel_method() {
channel := iter.Iterator[int](slices.Values([]int{1, 2, 3})).ToChannel()

for number := range channel {
fmt.Println(number)
}

// Output:
// 1
// 2
// 3
}

func TestToChannelEmpty(t *testing.T) {
t.Parallel()

for range iter.ToChannel(slices.Values([]int{})) {
t.Error("unexpected")
}
}