I created the next code to assist take away some boilerplate round go routines/channels and in addition make it considerably extra much like how different languages use async/await
just a few questions:
- is that this a nasty follow in go? why?
- if its okay, is there something I ought to do totally different?
- is there a extra full resolution out there for this (I checked pkgs however I’m unsure if my pkg search foo is there but)
bundle process
import (
"context"
"fmt"
)
sort TaskStatus int
const (
New TaskStatus = iota
Operating
Accomplished
)
var taskStatus = [3]string{"New", "Operating", "Accomplished"}
sort taskFunc[T interface{}] func(ctx context.Context) (T, error)
sort voidTaskFunc func(ctx context.Context) error
sort Activity[T interface{}] interface {
Standing() TaskStatus
Outcome() (T, error)
Await(ctx ...context.Context) (T, error)
}
sort process[T interface{}] struct {
outcome T
err error
c chan struct{}
standing TaskStatus
fn taskFunc[T]
}
sort TaskPanicError struct {
purpose interface{}
}
func (e TaskPanicError) Error() string {
return fmt.Sprintf("Activity panicked: %v", e.purpose)
}
func NewTask[T interface{}](fn taskFunc[T]) *process[T] {
t := new(process[T])
t.c = make(chan struct{})
t.fn = fn
return t
}
func (t *process[T]) Standing() TaskStatus {
return t.standing
}
func (t *process[T]) Outcome() (T, error) {
swap t.standing {
case Accomplished:
return t.outcome, t.err
default:
return t.outcome, fmt.Errorf("Activity standing is %s", taskStatus[t.status])
}
}
func (t *process[T]) Await(ctx ...context.Context) (T, error) {
swap t.standing {
case Accomplished:
return t.outcome, t.err
case Operating:
return t.outcome, fmt.Errorf("Activity already operating, can solely be began as soon as")
}
defer func() {
t.standing = Accomplished
}()
var _ctx context.Context
if len(ctx) == 0 {
_ctx = context.Background()
} else {
_ctx = ctx[0]
}
go t.begin(_ctx)
choose {
case <-_ctx.Accomplished():
return t.outcome, _ctx.Err()
case <-t.c:
return t.outcome, t.err
}
}
func (t *process[T]) begin(ctx context.Context) {
defer func() {
if r := recuperate(); r != nil {
t.err = TaskPanicError{purpose: r}
}
t.standing = Accomplished
t.c <- struct{}{}
shut(t.c)
}()
if ctx.Err() != nil {
t.err = ctx.Err()
t.c <- struct{}{}
return
}
t.standing = Operating
t.outcome, t.err = t.fn(ctx)
}