Created
November 21, 2024 02:13
-
-
Save ValentaTomas/8def5acc9e0794218cdd99402653bcaa to your computer and use it in GitHub Desktop.
Thread-safe way to wait and propagate result/error to multiple places.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package utils | |
import ( | |
"fmt" | |
"sync" | |
) | |
type result[T any] struct { | |
value T | |
err error | |
} | |
type SetOnce[T any] struct { | |
wait func() (T, error) | |
done chan result[T] | |
} | |
func NewSetOnce[T any]() *SetOnce[T] { | |
done := make(chan result[T], 1) | |
return &SetOnce[T]{ | |
done: done, | |
wait: sync.OnceValues(func() (T, error) { | |
result, ok := <-done | |
if !ok { | |
return *new(T), fmt.Errorf("init channel was closed") | |
} | |
return result.value, result.err | |
}), | |
} | |
} | |
// Wait returns the value or error set by SetValue or SetError. | |
// It can be called multiple times, returning the same value or error. | |
func (o *SetOnce[T]) Wait() (T, error) { | |
return o.wait() | |
} | |
func (o *SetOnce[T]) SetValue(value T) error { | |
select { | |
case o.done <- result[T]{value: value}: | |
return nil | |
default: | |
return fmt.Errorf("error setting value: init channel was closed") | |
} | |
} | |
func (o *SetOnce[T]) SetError(err error) error { | |
select { | |
case o.done <- result[T]{err: err}: | |
return nil | |
default: | |
return fmt.Errorf("error setting error: init channel was closed") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment