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:
274
mvc2/service.go
274
mvc2/service.go
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user