bbgo: implement parseStructAndInject

This commit is contained in:
c9s 2022-03-05 02:33:25 +08:00
parent 5fe0b69927
commit db4d8a31bc
2 changed files with 114 additions and 0 deletions

View File

@ -413,3 +413,57 @@ func (trader *Trader) injectCommonServices(rs reflect.Value) error {
func (trader *Trader) ReportPnL() *PnLReporterManager { func (trader *Trader) ReportPnL() *PnLReporterManager {
return NewPnLReporter(&trader.environment.Notifiability) return NewPnLReporter(&trader.environment.Notifiability)
} }
func parseStructAndInject(f interface{}, objects ...interface{}) error {
sv := reflect.ValueOf(f)
st := reflect.TypeOf(f)
if st.Kind() != reflect.Ptr {
return fmt.Errorf("f needs to be a pointer of a struct, %s given", st)
}
// solve the pointer
st = st.Elem()
sv = sv.Elem()
if st.Kind() != reflect.Struct {
return fmt.Errorf("f needs to be a struct, %s given", st)
}
for i := 0; i < sv.NumField(); i++ {
fv := sv.Field(i)
ft := fv.Type()
switch k := fv.Kind(); k {
case reflect.Ptr, reflect.Struct:
for oi := 0; oi < len(objects); oi++ {
obj := objects[oi]
ot := reflect.TypeOf(obj)
if ft.AssignableTo(ot) {
if !fv.CanSet() {
return fmt.Errorf("field %v of %s can not be set to %s", fv, sv.Type(), ot)
}
fv.Set(reflect.ValueOf(obj))
}
}
case reflect.Interface:
for oi := 0; oi < len(objects); oi++ {
obj := objects[oi]
objT := reflect.TypeOf(obj)
log.Debugln(
ft.PkgPath(),
ft.Name(),
objT, "implements", ft, "=", objT.Implements(ft),
)
if objT.Implements(ft) {
fv.Set(reflect.ValueOf(obj))
}
}
}
}
return nil
}

60
pkg/bbgo/trader_test.go Normal file
View File

@ -0,0 +1,60 @@
package bbgo
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/c9s/bbgo/pkg/types"
)
func Test_parseStructAndInject(t *testing.T) {
t.Run("pointer", func(t *testing.T) {
ss := struct {
a int
Env *Environment
}{
a: 1,
Env: nil,
}
err := parseStructAndInject(&ss, &Environment{})
assert.NoError(t, err)
assert.NotNil(t, ss.Env)
})
t.Run("struct", func(t *testing.T) {
ss := struct {
a int
Env Environment
}{
a: 1,
}
err := parseStructAndInject(&ss, Environment{
startTime: time.Now(),
})
assert.NoError(t, err)
assert.NotEqual(t, time.Time{}, ss.Env.startTime)
})
t.Run("interface/any", func(t *testing.T) {
ss := struct {
Any interface{} // anything
}{
Any: nil,
}
err := parseStructAndInject(&ss, &Environment{
startTime: time.Now(),
})
assert.NoError(t, err)
assert.NotNil(t, ss.Any)
})
t.Run("interface/stringer", func(t *testing.T) {
ss := struct {
Stringer types.Stringer // stringer interface
}{
Stringer: nil,
}
err := parseStructAndInject(&ss, &types.Trade{})
assert.NoError(t, err)
assert.NotNil(t, ss.Stringer)
})
}