mirror of
https://github.com/tursom/GoCollections.git
synced 2024-12-25 23:40:12 +08:00
add future
This commit is contained in:
parent
d3b71a7eeb
commit
6da2986c48
132
concurrent/future/Future.go
Executable file
132
concurrent/future/Future.go
Executable file
@ -0,0 +1,132 @@
|
||||
package future
|
||||
|
||||
import (
|
||||
"github.com/tursom/GoCollections/exceptions"
|
||||
"github.com/tursom/GoCollections/lang"
|
||||
"github.com/tursom/GoCollections/util/time"
|
||||
)
|
||||
|
||||
type (
|
||||
Future[T any] interface {
|
||||
Get() (T, exceptions.Exception)
|
||||
GetT(timeout time.Duration) (T, exceptions.Exception)
|
||||
IsDone() bool
|
||||
IsCancelled() bool
|
||||
Cancel() bool
|
||||
}
|
||||
|
||||
Task[T any] interface {
|
||||
Future[T]
|
||||
Done(value T)
|
||||
Fail(e exceptions.Exception)
|
||||
}
|
||||
|
||||
futureState uint8
|
||||
|
||||
impl[T any] struct {
|
||||
state futureState
|
||||
value T
|
||||
e exceptions.Exception
|
||||
done chan futureState
|
||||
canceller func() bool
|
||||
}
|
||||
)
|
||||
|
||||
//goland:noinspection GoSnakeCaseUsage
|
||||
const (
|
||||
futureState_start futureState = iota
|
||||
futureState_done futureState = iota
|
||||
futureState_canceled futureState = iota
|
||||
)
|
||||
|
||||
func Get[T any](future Future[T]) T {
|
||||
get, e := future.Get()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
|
||||
return get
|
||||
}
|
||||
|
||||
func GetT[T any](future Future[T], timeout time.Duration) T {
|
||||
get, e := future.GetT(timeout)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
|
||||
return get
|
||||
}
|
||||
|
||||
func New[T any](canceller func() bool) Task[T] {
|
||||
return &impl[T]{
|
||||
done: make(chan futureState, 1),
|
||||
canceller: canceller,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *impl[T]) Done(value T) {
|
||||
if i.IsDone() {
|
||||
return
|
||||
}
|
||||
|
||||
i.value = value
|
||||
i.state = futureState_done
|
||||
i.done <- futureState_done
|
||||
}
|
||||
|
||||
func (i *impl[T]) Fail(e exceptions.Exception) {
|
||||
if i.IsDone() {
|
||||
return
|
||||
}
|
||||
|
||||
i.e = e
|
||||
i.state = futureState_done
|
||||
i.done <- futureState_done
|
||||
}
|
||||
|
||||
func (i *impl[T]) Get() (T, exceptions.Exception) {
|
||||
if i.IsDone() {
|
||||
return i.value, i.e
|
||||
}
|
||||
|
||||
<-i.done
|
||||
|
||||
return i.value, i.e
|
||||
}
|
||||
|
||||
func (i *impl[T]) GetT(timeout time.Duration) (T, exceptions.Exception) {
|
||||
if i.IsDone() {
|
||||
return i.value, i.e
|
||||
}
|
||||
|
||||
select {
|
||||
case i.state = <-i.done:
|
||||
case <-time.After(timeout):
|
||||
return lang.Nil[T](), exceptions.NewTimeoutException(
|
||||
"Future.GetT timeout", nil)
|
||||
}
|
||||
|
||||
return i.value, i.e
|
||||
}
|
||||
|
||||
func (i *impl[T]) IsDone() bool {
|
||||
return i.state != futureState_start
|
||||
}
|
||||
|
||||
func (i *impl[T]) IsCancelled() bool {
|
||||
return i.state == futureState_canceled
|
||||
}
|
||||
|
||||
func (i *impl[T]) Cancel() bool {
|
||||
if i.IsDone() {
|
||||
return false
|
||||
}
|
||||
|
||||
if !i.canceller() {
|
||||
return false
|
||||
}
|
||||
|
||||
i.state = futureState_canceled
|
||||
i.done <- futureState_canceled
|
||||
return true
|
||||
}
|
91
concurrent/future/mapper.go
Executable file
91
concurrent/future/mapper.go
Executable file
@ -0,0 +1,91 @@
|
||||
package future
|
||||
|
||||
import (
|
||||
"github.com/tursom/GoCollections/exceptions"
|
||||
"github.com/tursom/GoCollections/lang"
|
||||
"github.com/tursom/GoCollections/util/time"
|
||||
)
|
||||
|
||||
type (
|
||||
mapperFuture[V1, V2 any] struct {
|
||||
future Future[V1]
|
||||
mapper func(v1 V1) (V2, exceptions.Exception)
|
||||
v V2
|
||||
e exceptions.Exception
|
||||
done bool
|
||||
}
|
||||
)
|
||||
|
||||
func Map[V1, V2 any](
|
||||
future Future[V1],
|
||||
mapper func(v1 V1) (V2, exceptions.Exception),
|
||||
) Future[V2] {
|
||||
return &mapperFuture[V1, V2]{
|
||||
future: future,
|
||||
mapper: mapper,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mapperFuture[V1, V2]) Get() (V2, exceptions.Exception) {
|
||||
if m.done {
|
||||
return m.v, m.e
|
||||
}
|
||||
|
||||
defer func() {
|
||||
m.done = true
|
||||
}()
|
||||
|
||||
v1, e := m.future.Get()
|
||||
if e != nil {
|
||||
m.e = e
|
||||
return lang.Nil[V2](), e
|
||||
}
|
||||
|
||||
v2, e := m.mapper(v1)
|
||||
if e != nil {
|
||||
m.e = e
|
||||
return lang.Nil[V2](), e
|
||||
}
|
||||
|
||||
m.v = v2
|
||||
return v2, nil
|
||||
}
|
||||
|
||||
func (m *mapperFuture[V1, V2]) GetT(timeout time.Duration) (V2, exceptions.Exception) {
|
||||
if m.done {
|
||||
return m.v, m.e
|
||||
}
|
||||
|
||||
v1, e := m.future.GetT(timeout)
|
||||
if e != nil {
|
||||
return m.processException(e)
|
||||
}
|
||||
|
||||
v2, e := m.mapper(v1)
|
||||
if e != nil {
|
||||
return m.processException(e)
|
||||
}
|
||||
|
||||
m.v = v2
|
||||
return v2, nil
|
||||
}
|
||||
|
||||
func (m *mapperFuture[V1, V2]) processException(e exceptions.Exception) (V2, exceptions.Exception) {
|
||||
if _, ok := e.(*exceptions.TimeoutException); !ok {
|
||||
m.done = true
|
||||
m.e = e
|
||||
}
|
||||
return lang.Nil[V2](), e
|
||||
}
|
||||
|
||||
func (m *mapperFuture[V1, V2]) IsDone() bool {
|
||||
return m.future.IsDone()
|
||||
}
|
||||
|
||||
func (m *mapperFuture[V1, V2]) IsCancelled() bool {
|
||||
return m.future.IsCancelled()
|
||||
}
|
||||
|
||||
func (m *mapperFuture[V1, V2]) Cancel() bool {
|
||||
return m.future.Cancel()
|
||||
}
|
18
exceptions/TimeoutException.go
Executable file
18
exceptions/TimeoutException.go
Executable file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2022 tursom. All rights reserved.
|
||||
* Use of this source code is governed by a GPL-3
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package exceptions
|
||||
|
||||
type TimeoutException struct {
|
||||
RuntimeException
|
||||
}
|
||||
|
||||
func NewTimeoutException(message string, config *ExceptionConfig) *TimeoutException {
|
||||
return &TimeoutException{
|
||||
*NewRuntimeException(message, config.AddSkipStack(1).
|
||||
SetExceptionName("github.com.tursom.GoCollections.exceptions.TimeoutException")),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user