package pipes
import (
"context"
"fmt"
"reflect"
"strings"
am "github.com/pancsta/asyncmachine-go/pkg/machine"
ss "github.com/pancsta/asyncmachine-go/pkg/states"
)
func Add (
source , target am .Api , sourceState string , targetState string ,
) am .HandlerFinal {
return add (false , source , target , sourceState , targetState )
}
func AddFlat (
source , target am .Api , sourceState string , targetState string ,
) am .HandlerFinal {
return add (true , source , target , sourceState , targetState )
}
func add(
flat bool , source , target am .Api , sourceState string , targetState string ,
) am .HandlerFinal {
if sourceState == "" {
panic (am .ErrStateMissing )
}
if targetState == "" {
targetState = sourceState
}
semLog := source .SemLogger ()
semLog .AddPipeOut (true , sourceState , target .Id ())
semLog .AddPipeIn (true , targetState , source .Id ())
source .OnDispose (gcHandler (target ))
target .OnDispose (gcHandler (source ))
names := am .S {targetState }
if strings .HasPrefix (targetState , am .PrefixErr ) {
names = am .S {am .StateException , targetState }
}
return func (e *am .Event ) {
if flat && target .Is (names ) {
return
} else if flat {
target .Add (names , nil )
} else {
target .EvAdd (e , names , e .Args )
}
}
}
func Remove (
source , target am .Api , sourceState string , targetState string ,
) am .HandlerFinal {
return remove (false , source , target , sourceState , targetState )
}
func RemoveFlat (
source , target am .Api , sourceState string , targetState string ,
) am .HandlerFinal {
return remove (true , source , target , sourceState , targetState )
}
func remove(
flat bool , source , target am .Api , sourceState string , targetState string ,
) am .HandlerFinal {
if sourceState == "" {
panic (am .ErrStateMissing )
}
if targetState == "" {
targetState = sourceState
}
semLog := source .SemLogger ()
semLog .AddPipeOut (false , sourceState , target .Id ())
semLog .AddPipeIn (false , targetState , source .Id ())
source .OnDispose (gcHandler (target ))
target .OnDispose (gcHandler (source ))
return func (e *am .Event ) {
if flat && target .Not1 (targetState ) {
return
} else if flat {
target .Remove1 (targetState , nil )
} else {
target .EvRemove1 (e , targetState , e .Args )
}
}
}
func BindAny (source , target am .Api ) error {
fn := func (e *am .Event ) {
tx := e .Transition ()
states := tx .TargetStates ()
if target .Is (states ) {
return
}
target .Set (states , e .Args )
}
h := &struct {
AnyState am .HandlerFinal
}{
AnyState : fn ,
}
semLog := source .SemLogger ()
for _ , sourceState := range source .StateNames () {
semLog .AddPipeOut (true , sourceState , target .Id ())
semLog .AddPipeIn (true , sourceState , source .Id ())
}
source .OnDispose (gcHandler (target ))
target .OnDispose (gcHandler (source ))
return source .BindHandlers (h )
}
func BindConnected (
source , target am .Api , disconnected , connecting , connected ,
disconnecting string ,
) error {
h := &struct {
DisconnectedState am .HandlerFinal
DisconnectedEnd am .HandlerFinal
ConnectingState am .HandlerFinal
ConnectingEnd am .HandlerFinal
ConnectedState am .HandlerFinal
ConnectedEnd am .HandlerFinal
DisconnectingState am .HandlerFinal
DisconnectingEnd am .HandlerFinal
}{}
s := ss .ConnectedStates
if disconnected != "" {
h .DisconnectedState = Add (source , target , s .Disconnected , disconnected )
h .DisconnectedEnd = Remove (source , target , s .Disconnected , disconnected )
}
if connecting != "" {
h .ConnectingState = Add (source , target , s .Connecting , connecting )
h .ConnectingEnd = Remove (source , target , s .Connecting , connecting )
}
if connected != "" {
h .ConnectedState = Add (source , target , s .Connected , connected )
h .ConnectedEnd = Remove (source , target , s .Connected , connected )
}
if disconnecting != "" {
h .DisconnectingState = Add (source , target , s .Disconnecting , disconnecting )
h .DisconnectingEnd = Remove (source , target , s .Disconnecting , disconnecting )
}
return source .BindHandlers (h )
}
func BindErr (source , target am .Api , targetErr string ) error {
if targetErr == "" {
targetErr = am .StateException
}
h := &struct {
ExceptionState am .HandlerFinal
}{
ExceptionState : Add (source , target , am .StateException , targetErr ),
}
return source .BindHandlers (h )
}
func BindStart (
source , target am .Api , activeState , inactiveState string ,
) error {
h := &struct {
StartState am .HandlerFinal
StartEnd am .HandlerFinal
}{
StartState : Add (source , target , ss .BasicStates .Start , activeState ),
StartEnd : Remove (source , target , ss .BasicStates .Start , inactiveState ),
}
return source .BindHandlers (h )
}
func BindReady (
source , target am .Api , activeState , inactiveState string ,
) error {
h := &struct {
ReadyState am .HandlerFinal
ReadyEnd am .HandlerFinal
}{
ReadyState : Add (source , target , ss .BasicStates .Ready , activeState ),
ReadyEnd : Remove (source , target , ss .BasicStates .Ready , inactiveState ),
}
return source .BindHandlers (h )
}
func Bind (
source , target am .Api , state string , activeState , inactiveState string ,
) error {
if activeState == "" {
activeState = state
}
if inactiveState == "" {
inactiveState = activeState
}
var fields []reflect .StructField
add := Add (source , target , state , activeState )
remove := Remove (source , target , state , inactiveState )
fields = append (fields , reflect .StructField {
Name : state + am .SuffixState ,
Type : reflect .TypeOf (add ),
})
fields = append (fields , reflect .StructField {
Name : state + am .SuffixEnd ,
Type : reflect .TypeOf (remove ),
})
structType := reflect .StructOf (fields )
val := reflect .New (structType ).Elem ()
val .Field (0 ).Set (reflect .ValueOf (add ))
val .Field (1 ).Set (reflect .ValueOf (remove ))
handlers := val .Addr ().Interface ()
return source .BindHandlers (handlers )
}
func BindMany (
source , target am .Api , states , targetStates am .S ,
) error {
if len (states ) != len (targetStates ) {
return fmt .Errorf ("%w: source and target states len mismatch" ,
am .ErrStateMissing )
}
var fields []reflect .StructField
var fns []am .HandlerFinal
for i , name := range states {
add := Add (source , target , name , targetStates [i ])
remove := Remove (source , target , name , targetStates [i ])
fields = append (fields , reflect .StructField {
Name : name + am .SuffixState ,
Type : reflect .TypeOf (add ),
})
fields = append (fields , reflect .StructField {
Name : name + am .SuffixEnd ,
Type : reflect .TypeOf (remove ),
})
fns = append (fns , add , remove )
}
structType := reflect .StructOf (fields )
val := reflect .New (structType ).Elem ()
for i , fn := range fns {
val .Field (i ).Set (reflect .ValueOf (fn ))
}
handlers := val .Addr ().Interface ()
return source .BindHandlers (handlers )
}
func gcHandler(mach am .Api ) am .HandlerDispose {
return func (id string , ctx context .Context ) {
mach .SemLogger ().RemovePipes (id )
}
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .