func (t *task) run(ctx context.Context) {
	if !t.changeState(IsCreated, IsRunning) {
		return  
	}
	defer close(t.done)
	startedAt := now().UnixNano()
	outcomeCh := make(chan outcome, 1)
	go func() {
		r, e := t.action(ctx)
		outcomeCh <- outcome{result: r, err: e}
	}()
	select {
	case <-t.cancel:
		t.duration = time.Nanosecond * time.Duration(now().UnixNano()-startedAt)
		t.outcome = outcome{err: errCancelled}
		t.changeState(IsRunning, IsCancelled)
		return
	case <-ctx.Done():
		t.duration = time.Nanosecond * time.Duration(now().UnixNano()-startedAt)
		t.outcome = outcome{err: ctx.Err()}
		t.changeState(IsRunning, IsCancelled)
		return
	case o := <-outcomeCh:
		t.duration = time.Nanosecond * time.Duration(now().UnixNano()-startedAt)
		t.outcome = o
		t.changeState(IsRunning, IsCompleted)
		return
	}
}
run starts the task synchronously.
package async
import (
	"context"
	"errors"
	"sync/atomic"
	"time"
)
var errCancelled = errors.New("context canceled")
var now = time.Now
type Work func(context.Context) (interface{}, error)
type State byte
const (
	IsCreated   State = iota  
	IsRunning                 
	IsCompleted               
	IsCancelled               
)
type signal chan struct{}
type outcome struct {
	result interface{}  
	err    error        
}
type task struct {
	state    int32          
	cancel   signal         
	done     signal         
	action   Work           
	outcome  outcome        
	duration time.Duration  
}
type Task interface {
	Run(ctx context.Context) Task
	Cancel()
	State() State
	Outcome() (interface{}, error)
	ContinueWith(ctx context.Context, nextAction func(interface{}, error) (interface{}, error)) Task
}
func NewTask(action Work) Task {
	return &task{
		action: action,
		done:   make(signal, 1),
		cancel: make(signal, 1),
	}
}
func NewTasks(actions ...Work) []Task {
	tasks := make([]Task, 0, len(actions))
	for _, action := range actions {
		tasks = append(tasks, NewTask(action))
	}
	return tasks
}
func Invoke(ctx context.Context, action Work) Task {
	return NewTask(action).Run(ctx)
}
func (t *task) Outcome() (interface{}, error) {
	<-t.done
	return t.outcome.result, t.outcome.err
}
func (t *task) State() State {
	v := atomic.LoadInt32(&t.state)
	return State(v)
}
func (t *task) Duration() time.Duration {
	return t.duration
}
func (t *task) Run(ctx context.Context) Task {
	go t.run(ctx)
	return t
}
func (t *task) Cancel() {
	if t.changeState(IsCreated, IsCancelled) {
		t.outcome = outcome{err: errCancelled}
		close(t.done)
		return
	}
	if t.cancel != nil {
		select {
		case <-t.cancel:
			return
		default:
			close(t.cancel)
		}
	}
}