iris/mvc2/service.go

207 lines
4.4 KiB
Go
Raw Normal View History

package mvc2
import (
"fmt"
"reflect"
)
type service struct {
Type reflect.Type
Value reflect.Value
StructFieldIndex []int
// for func input.
ReturnValue func(ctx []reflect.Value) reflect.Value
FuncInputIndex int
FuncInputContextIndex int
}
type services []*service
func (serv *services) AddSource(dest reflect.Value, source ...reflect.Value) {
fmt.Println("--------------AddSource------------")
if len(source) == 0 {
return
}
typ := indirectTyp(dest.Type()) //indirectTyp(reflect.TypeOf(dest))
_serv := *serv
if typ.Kind() == reflect.Func {
n := typ.NumIn()
for i := 0; i < n; i++ {
inTyp := typ.In(i)
if isContext(inTyp) {
_serv = append(_serv, &service{FuncInputContextIndex: i})
continue
}
for _, s := range source {
gotTyp := s.Type()
service := service{
Type: gotTyp,
Value: s,
FuncInputIndex: i,
FuncInputContextIndex: -1,
}
if s.Type().Kind() == reflect.Func {
fmt.Printf("Source is Func\n")
returnValue, outType, err := makeReturnValue(s)
if err != nil {
fmt.Printf("Err on makeReturnValue: %v\n", err)
continue
}
gotTyp = outType
service.ReturnValue = returnValue
}
fmt.Printf("Types: In=%s vs Got=%s\n", inTyp.String(), gotTyp.String())
if equalTypes(gotTyp, inTyp) {
service.Type = gotTyp
fmt.Printf("Bind In=%s->%s for func\n", inTyp.String(), gotTyp.String())
_serv = append(_serv, &service)
break
}
}
}
fmt.Printf("[1] Bind %d for %s\n", len(_serv), typ.String())
*serv = _serv
return
}
if typ.Kind() == reflect.Struct {
fields := lookupFields(typ, -1)
for _, f := range fields {
for _, s := range source {
gotTyp := s.Type()
service := service{
Type: gotTyp,
Value: s,
StructFieldIndex: f.Index,
FuncInputContextIndex: -1,
}
if s.Type().Kind() == reflect.Func {
returnValue, outType, err := makeReturnValue(s)
if err != nil {
continue
}
gotTyp = outType
service.ReturnValue = returnValue
}
if equalTypes(gotTyp, f.Type) {
service.Type = gotTyp
_serv = append(_serv, &service)
fmt.Printf("[2] Bind In=%s->%s for struct field[%d]\n", f.Type, gotTyp.String(), f.Index)
break
}
}
}
fmt.Printf("[2] Bind %d for %s\n", len(_serv), typ.String())
*serv = _serv
return
}
}
func (serv services) FillStructStaticValues(elem reflect.Value) {
if len(serv) == 0 {
return
}
for _, s := range serv {
if len(s.StructFieldIndex) > 0 {
// fmt.Printf("FillStructStaticValues for index: %d\n", s.StructFieldIndex)
elem.FieldByIndex(s.StructFieldIndex).Set(s.Value)
}
}
}
func (serv services) FillStructDynamicValues(elem reflect.Value, ctx []reflect.Value) {
if len(serv) == 0 {
return
}
for _, s := range serv {
if len(s.StructFieldIndex) > 0 {
elem.FieldByIndex(s.StructFieldIndex).Set(s.ReturnValue(ctx))
}
}
}
func (serv services) FillFuncInput(ctx []reflect.Value, destIn *[]reflect.Value) {
if len(serv) == 0 {
return
}
in := *destIn
for _, s := range serv {
if s.ReturnValue != nil {
in[s.FuncInputIndex] = s.ReturnValue(ctx)
continue
}
in[s.FuncInputIndex] = s.Value
if s.FuncInputContextIndex >= 0 {
in[s.FuncInputContextIndex] = ctx[0]
}
}
*destIn = in
}
func makeReturnValue(fn reflect.Value) (func([]reflect.Value) reflect.Value, reflect.Type, error) {
typ := indirectTyp(fn.Type())
// invalid if not a func.
if typ.Kind() != reflect.Func {
return nil, typ, errBad
}
// invalid if not returns one single value.
if typ.NumOut() != 1 {
return nil, typ, errBad
}
// invalid if input args length is not one.
if typ.NumIn() != 1 {
return nil, typ, errBad
}
// invalid if that single input arg is not a typeof context.Context.
if !isContext(typ.In(0)) {
return nil, typ, errBad
}
outTyp := typ.Out(0)
zeroOutVal := reflect.New(outTyp).Elem()
bf := func(ctxValue []reflect.Value) reflect.Value {
// []reflect.Value{reflect.ValueOf(ctx)}
results := fn.Call(ctxValue) // ctxValue is like that because of; read makeHandler.
if len(results) == 0 {
return zeroOutVal
}
v := results[0]
if !v.IsValid() {
return zeroOutVal
}
return v
}
return bf, outTyp, nil
}
func getServicesFor(dest reflect.Value, source []reflect.Value) (s services) {
s.AddSource(dest, source...)
return s
}