|
package concurrency |
|
|
|
import ( |
|
"context" |
|
"sync" |
|
) |
|
|
|
|
|
type JobResult[RequestType any, ResultType any] struct { |
|
request *RequestType |
|
result *ResultType |
|
err error |
|
once sync.Once |
|
done *chan struct{} |
|
} |
|
|
|
|
|
type WritableJobResult[RequestType any, ResultType any] struct { |
|
*JobResult[RequestType, ResultType] |
|
} |
|
|
|
|
|
|
|
|
|
func (jr *JobResult[RequestType, ResultType]) Wait(ctx context.Context) (*ResultType, error) { |
|
if jr.done == nil { |
|
return jr.result, jr.err |
|
} |
|
select { |
|
case <-*jr.done: |
|
jr.done = nil |
|
if jr.err != nil { |
|
return nil, jr.err |
|
} |
|
return jr.result, nil |
|
case <-ctx.Done(): |
|
return nil, ctx.Err() |
|
} |
|
} |
|
|
|
|
|
func (jr *JobResult[RequestType, ResultType]) Request() *RequestType { |
|
return jr.request |
|
} |
|
|
|
|
|
func (jr *JobResult[RequestType, ResultType]) setResult(result ResultType, err error) { |
|
jr.once.Do(func() { |
|
jr.result = &result |
|
jr.err = err |
|
close(*jr.done) |
|
}) |
|
} |
|
|
|
|
|
func (wjr *WritableJobResult[RequestType, ResultType]) SetResult(result ResultType, err error) { |
|
wjr.JobResult.setResult(result, err) |
|
} |
|
|
|
|
|
func NewJobResult[RequestType any, ResultType any](request RequestType) (*JobResult[RequestType, ResultType], *WritableJobResult[RequestType, ResultType]) { |
|
done := make(chan struct{}) |
|
jr := &JobResult[RequestType, ResultType]{ |
|
once: sync.Once{}, |
|
request: &request, |
|
done: &done, |
|
} |
|
return jr, &WritableJobResult[RequestType, ResultType]{JobResult: jr} |
|
} |
|
|