Skip to content

Commit

Permalink
Merge branch 'master' of github.com:samber/lo
Browse files Browse the repository at this point in the history
  • Loading branch information
samber committed Apr 27, 2022
2 parents 2775943 + 86d0e89 commit 0b4da1e
Show file tree
Hide file tree
Showing 3 changed files with 210 additions and 5 deletions.
23 changes: 20 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1278,12 +1278,29 @@ Executes a function in a goroutine and returns the result in a channel.
```go
ch := lo.Async(func() error { time.Sleep(10 * time.Second); return nil })
// chan error (nil)
```

### Async{0->6}

Executes a function in a goroutine and returns the result in a channel.
For function with multiple return values, the results will be returned as a tuple inside the channel.
For function without return, struct{} will be returned in the channel.

```go
ch := lo.Async0(func() { time.Sleep(10 * time.Second) })
// chan struct{}

ch := lo.Async1(func() int {
time.Sleep(10 * time.Second);
return 42
})
// chan int (42)

ch := lo.Async(func() lo.Tuple2[int, error] {
ch := lo.Async2(func() (int, string) {
time.Sleep(10 * time.Second);
return lo.Tuple2[int, error]{42, nil}
return 42, "Hello"
})
// chan lo.Tuple2[int, error] ({42, nil})
// chan lo.Tuple2[int, string] ({42, "Hello"})
```

### Must
Expand Down
64 changes: 62 additions & 2 deletions concurrency.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,70 @@
package lo

// Async executes a function in a goroutine and returns the result in a channel.
func Async[T any](f func() T) chan T {
ch := make(chan T)
func Async[A any](f func() A) chan A {
ch := make(chan A)
go func() {
ch <- f()
}()
return ch
}

// Async0 executes a function in a goroutine and returns a channel set once the function finishes.
func Async0(f func()) chan struct{} {
ch := make(chan struct{})
go func() {
f()
ch <- struct{}{}
}()
return ch
}

// Async1 is an alias to Async.
func Async1[A any](f func() A) chan A {
return Async(f)
}

// Async2 has the same behavior as Async, but returns the 2 results as a tuple inside the channel.
func Async2[A any, B any](f func() (A, B)) chan Tuple2[A, B] {
ch := make(chan Tuple2[A, B])
go func() {
ch <- T2(f())
}()
return ch
}

// Async3 has the same behavior as Async, but returns the 3 results as a tuple inside the channel.
func Async3[A any, B any, C any](f func() (A, B, C)) chan Tuple3[A, B, C] {
ch := make(chan Tuple3[A, B, C])
go func() {
ch <- T3(f())
}()
return ch
}

// Async4 has the same behavior as Async, but returns the 4 results as a tuple inside the channel.
func Async4[A any, B any, C any, D any](f func() (A, B, C, D)) chan Tuple4[A, B, C, D] {
ch := make(chan Tuple4[A, B, C, D])
go func() {
ch <- T4(f())
}()
return ch
}

// Async5 has the same behavior as Async, but returns the 5 results as a tuple inside the channel.
func Async5[A any, B any, C any, D any, E any](f func() (A, B, C, D, E)) chan Tuple5[A, B, C, D, E] {
ch := make(chan Tuple5[A, B, C, D, E])
go func() {
ch <- T5(f())
}()
return ch
}

// Async6 has the same behavior as Async, but returns the 6 results as a tuple inside the channel.
func Async6[A any, B any, C any, D any, E any, F any](f func() (A, B, C, D, E, F)) chan Tuple6[A, B, C, D, E, F] {
ch := make(chan Tuple6[A, B, C, D, E, F])
go func() {
ch <- T6(f())
}()
return ch
}
128 changes: 128 additions & 0 deletions concurrency_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,131 @@ func TestAsync(t *testing.T) {
is.Fail("Async should not block")
}
}

func TestAsyncX(t *testing.T) {
is := assert.New(t)

{
sync := make(chan struct{})

ch := Async0(func() {
<-sync
})

sync <- struct{}{}

select {
case <-ch:
case <-time.After(time.Millisecond):
is.Fail("Async0 should not block")
}
}

{
sync := make(chan struct{})

ch := Async1(func() int {
<-sync
return 10
})

sync <- struct{}{}

select {
case result := <-ch:
is.Equal(result, 10)
case <-time.After(time.Millisecond):
is.Fail("Async1 should not block")
}
}

{
sync := make(chan struct{})

ch := Async2(func() (int, string) {
<-sync
return 10, "Hello"
})

sync <- struct{}{}

select {
case result := <-ch:
is.Equal(result, Tuple2[int, string]{10, "Hello"})
case <-time.After(time.Millisecond):
is.Fail("Async2 should not block")
}
}

{
sync := make(chan struct{})

ch := Async3(func() (int, string, bool) {
<-sync
return 10, "Hello", true
})

sync <- struct{}{}

select {
case result := <-ch:
is.Equal(result, Tuple3[int, string, bool]{10, "Hello", true})
case <-time.After(time.Millisecond):
is.Fail("Async3 should not block")
}
}

{
sync := make(chan struct{})

ch := Async4(func() (int, string, bool, float64) {
<-sync
return 10, "Hello", true, 3.14
})

sync <- struct{}{}

select {
case result := <-ch:
is.Equal(result, Tuple4[int, string, bool, float64]{10, "Hello", true, 3.14})
case <-time.After(time.Millisecond):
is.Fail("Async4 should not block")
}
}

{
sync := make(chan struct{})

ch := Async5(func() (int, string, bool, float64, string) {
<-sync
return 10, "Hello", true, 3.14, "World"
})

sync <- struct{}{}

select {
case result := <-ch:
is.Equal(result, Tuple5[int, string, bool, float64, string]{10, "Hello", true, 3.14, "World"})
case <-time.After(time.Millisecond):
is.Fail("Async5 should not block")
}
}

{
sync := make(chan struct{})

ch := Async6(func() (int, string, bool, float64, string, int) {
<-sync
return 10, "Hello", true, 3.14, "World", 100
})

sync <- struct{}{}

select {
case result := <-ch:
is.Equal(result, Tuple6[int, string, bool, float64, string, int]{10, "Hello", true, 3.14, "World", 100})
case <-time.After(time.Millisecond):
is.Fail("Async6 should not block")
}
}
}

0 comments on commit 0b4da1e

Please sign in to comment.