1
0
mirror of https://github.com/kataras/iris.git synced 2025-12-18 18:37:05 +00:00

made it work but looking for another approach

Former-commit-id: e61c4573543c57b8d6d4ef2583e40f52c391402f
This commit is contained in:
kataras
2017-12-04 05:06:03 +02:00
parent dd5de52f34
commit 7043f352d9
20 changed files with 855 additions and 792 deletions

View File

@@ -1,92 +1,206 @@
package mvc2
import (
"fmt"
"reflect"
)
// // Service is a `reflect.Value` value.
// // We keep that type here,
// // if we ever need to change this type we will not have
// // to refactor the whole mvc's codebase.
// type Service struct {
// reflect.Value
// typ reflect.Type
// }
type service struct {
Type reflect.Type
Value reflect.Value
StructFieldIndex []int
// // Valid checks if the service's Value's Value is valid for set or get.
// func (s Service) Valid() bool {
// return goodVal(s.Value)
// }
// for func input.
ReturnValue func(ctx []reflect.Value) reflect.Value
FuncInputIndex int
FuncInputContextIndex int
}
// // Equal returns if the
// func (s Service) Equal(other Service) bool {
// return equalTypes(s.typ, other.typ)
// }
type services []*service
// func (s Service) String() string {
// return s.Type().String()
// }
// func wrapService(service interface{}) Service {
// if s, ok := service.(Service); ok {
// return s // if it's a Service already.
// }
// return Service{
// Value: reflect.ValueOf(service),
// typ: reflect.TypeOf(service),
// }
// }
// // WrapServices wrap a generic services into structured Service slice.
// func WrapServices(services ...interface{}) []Service {
// if l := len(services); l > 0 {
// out := make([]Service, l, l)
// for i, s := range services {
// out[i] = wrapService(s)
// }
// return out
// }
// return nil
// }
// MustMakeServiceInputBinder calls the `MakeServiceInputBinder` and returns its first result, see its docs.
// It panics on error.
func MustMakeServiceInputBinder(service interface{}) *InputBinder {
s, err := MakeServiceInputBinder(service)
if err != nil {
panic(err)
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
}
// MakeServiceInputBinder uses a difference/or strange approach,
// we make the services as bind functions
// in order to keep the rest of the code simpler, however we have
// a performance penalty when calling the function instead
// of just put the responsible service to the certain handler's input argument.
func MakeServiceInputBinder(service interface{}) (*InputBinder, error) {
if service == nil {
return nil, errNil
}
var (
val = reflect.ValueOf(service)
typ = val.Type()
)
if !goodVal(val) {
return nil, errBad
}
if indirectTyp(typ).Kind() != reflect.Struct {
// if the pointer's struct is not a struct then return err bad.
return nil, errBad
}
return &InputBinder{
BindType: typ,
BindFunc: func(_ []reflect.Value) reflect.Value {
return val
},
}, nil
}