dynamic: add CallStructFieldsMethod for map struct field call

Signed-off-by: c9s <yoanlin93@gmail.com>
This commit is contained in:
c9s 2022-06-30 14:32:33 +08:00
parent 527070d13d
commit e2ab363e64
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
4 changed files with 85 additions and 26 deletions

View File

@ -1,10 +1,9 @@
package bbgo package bbgo
import ( import (
"reflect" "github.com/pkg/errors"
"github.com/c9s/bbgo/pkg/dynamic" "github.com/c9s/bbgo/pkg/dynamic"
"github.com/c9s/bbgo/pkg/types"
) )
type ExitMethod struct { type ExitMethod struct {
@ -16,34 +15,29 @@ type ExitMethod struct {
} }
func (m *ExitMethod) Subscribe(session *ExchangeSession) { func (m *ExitMethod) Subscribe(session *ExchangeSession) {
// TODO: pull out this implementation as a simple function to reflect.go if err := dynamic.CallStructFieldsMethod(m, "Subscribe", session); err != nil {
rv := reflect.ValueOf(m) panic(errors.Wrap(err, "dynamic call failed"))
rt := reflect.TypeOf(m)
rv = rv.Elem()
rt = rt.Elem()
infType := reflect.TypeOf((*types.Subscriber)(nil)).Elem()
argValues := dynamic.ToReflectValues(session)
for i := 0; i < rt.NumField(); i++ {
fieldType := rt.Field(i)
if fieldType.Type.Implements(infType) {
method := rv.Field(i).MethodByName("Subscribe")
method.Call(argValues)
}
} }
} }
func (m *ExitMethod) Bind(session *ExchangeSession, orderExecutor *GeneralOrderExecutor) { func (m *ExitMethod) Bind(session *ExchangeSession, orderExecutor *GeneralOrderExecutor) {
if m.ProtectiveStopLoss != nil { if m.ProtectiveStopLoss != nil {
m.ProtectiveStopLoss.Bind(session, orderExecutor) m.ProtectiveStopLoss.Bind(session, orderExecutor)
} else if m.RoiStopLoss != nil { }
if m.RoiStopLoss != nil {
m.RoiStopLoss.Bind(session, orderExecutor) m.RoiStopLoss.Bind(session, orderExecutor)
} else if m.RoiTakeProfit != nil { }
if m.RoiTakeProfit != nil {
m.RoiTakeProfit.Bind(session, orderExecutor) m.RoiTakeProfit.Bind(session, orderExecutor)
} else if m.LowerShadowTakeProfit != nil { }
if m.LowerShadowTakeProfit != nil {
m.LowerShadowTakeProfit.Bind(session, orderExecutor) m.LowerShadowTakeProfit.Bind(session, orderExecutor)
} else if m.CumulatedVolumeTakeProfit != nil { }
if m.CumulatedVolumeTakeProfit != nil {
m.CumulatedVolumeTakeProfit.Bind(session, orderExecutor) m.CumulatedVolumeTakeProfit.Bind(session, orderExecutor)
} }
} }

41
pkg/dynamic/call.go Normal file
View File

@ -0,0 +1,41 @@
package dynamic
import (
"errors"
"reflect"
)
// CallStructFieldsMethod iterates field from the given struct object
// check if the field object implements the interface, if it's implemented, then we call a specific method
func CallStructFieldsMethod(m interface{}, method string, args ...interface{}) error {
rv := reflect.ValueOf(m)
rt := reflect.TypeOf(m)
if rt.Kind() != reflect.Ptr {
return errors.New("the given object needs to be a pointer")
}
rv = rv.Elem()
rt = rt.Elem()
if rt.Kind() != reflect.Struct {
return errors.New("the given object needs to be struct")
}
argValues := ToReflectValues(args...)
for i := 0; i < rt.NumField(); i++ {
fieldType := rt.Field(i)
// skip non-exported fields
if !fieldType.IsExported() {
continue
}
if _, ok := fieldType.Type.MethodByName(method); ok {
refMethod := rv.Field(i).MethodByName(method)
refMethod.Call(argValues)
}
}
return nil
}

29
pkg/dynamic/call_test.go Normal file
View File

@ -0,0 +1,29 @@
package dynamic
import (
"testing"
"github.com/stretchr/testify/assert"
)
type callTest struct {
ChildCall1 *childCall1
ChildCall2 *childCall2
}
type childCall1 struct{}
func (c *childCall1) Subscribe(a int) {}
type childCall2 struct{}
func (c *childCall2) Subscribe(a int) {}
func TestCallStructFieldsMethod(t *testing.T) {
c := &callTest{
ChildCall1: &childCall1{},
ChildCall2: &childCall2{},
}
err := CallStructFieldsMethod(c, "Subscribe", 10)
assert.NoError(t, err)
}

View File

@ -1,5 +0,0 @@
package types
type Subscriber interface {
Subscribe()
}