Repository: samber/lo
File: concurrency.go (Go)

Code before:
	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, B, C, D, 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], 1)
	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, B, C, D, E, 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], 1)
	go func() {
		ch <- T6(f())
	}()
	return ch
}

// WaitFor runs periodically until a condition is validated.
func WaitFor(condition func(i int) bool, maxDuration time.Duration, tick time.Duration) (int, time.Duration, bool) {
	// the context is not used, but WaitForWithContext signature needs it
	conditionWithContext := func(_ context.Context, i int) bool {
		return condition(i)
	}
	return WaitForWithContext(context.Background(), conditionWithContext, maxDuration, tick)
}

// WaitForWithContext runs periodically until a condition is validated or context is canceled.
func WaitForWithContext(ctx context.Context, condition func(ctx context.Context, i int) bool, maxDuration time.Duration, tick time.Duration) (int, time.Duration, bool) {
	if condition(ctx, 0) {
		return 1, 0, true
	}

	start := time.Now()

	timer := time.NewTimer(maxDuration)
	ticker := time.NewTicker(tick)

	defer func() {
		timer.Stop()
		ticker.Stop()
	}()

	i := 1


Review comment (suggestion):
Also, I would like to use named variables there

These are too cryptic.


```suggestion
func WaitFor(condition func(currentIteration int) bool, maxDelay time.Duration, heartbeatDelay time.Duration) (totalIterations int, elapsed time.Duration, timeoutReached bool) {
```


Code after:
	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, B, C, D, 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], 1)
	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, B, C, D, E, 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], 1)
	go func() {
		ch <- T6(f())
	}()
	return ch
}

// WaitFor runs periodically until a condition is validated.
func WaitFor(condition func(i int) bool, timeout time.Duration, heartbeatDelay time.Duration) (totalIterations int, elapsed time.Duration, conditionFound bool) {
	conditionWithContext := func(_ context.Context, currentIteration int) bool {
		return condition(currentIteration)
	}
	return WaitForWithContext(context.Background(), conditionWithContext, timeout, heartbeatDelay)
}

// WaitForWithContext runs periodically until a condition is validated or context is canceled.
func WaitForWithContext(ctx context.Context, condition func(ctx context.Context, currentIteration int) bool, timeout time.Duration, heartbeatDelay time.Duration) (totalIterations int, elapsed time.Duration, conditionFound bool) {
	start := time.Now()

	if ctx.Err() != nil {
		return totalIterations, time.Since(start), false
	}

	ctx, cleanCtx := context.WithTimeout(ctx, timeout)
	ticker := time.NewTicker(heartbeatDelay)

	defer func() {
		cleanCtx()
		ticker.Stop()
	}()

	for {
		select {
		case <-ctx.Done():