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

ok make it cleaner, it's working well and blazing fast but I have to do a lot cleaning and commenting and docs as well before push it to master --- hope at christmas day, also thinking some internal ideas - the whole code is not ready to be readen by a third person yet.

Former-commit-id: 0b3fb2841d5032ff47bdca42a6f4ccfeb789ce3c
This commit is contained in:
Gerasimos (Makis) Maropoulos
2017-12-19 23:40:42 +02:00
parent 4261b5784a
commit c15763c556
11 changed files with 343 additions and 313 deletions

View File

@@ -5,6 +5,13 @@ import (
"reflect"
)
type State uint8
const (
Stateless State = iota
Singleton
)
type (
targetStructField struct {
Object *BindObject
@@ -12,22 +19,38 @@ type (
}
StructInjector struct {
elemType reflect.Type
initRef reflect.Value
initRefAsSlice []reflect.Value // useful when the struct is passed on a func as input args via reflection.
elemType reflect.Type
//
fields []*targetStructField
Valid bool // is true when contains fields and it's a valid target struct.
trace string // for debug info.
// is true when contains bindable fields and it's a valid target struct,
// it maybe 0 but struct may contain unexported fields or exported but no bindable (Stateless)
// see `setState`.
HasFields bool
CanInject bool // if any bindable fields when the state is NOT singleton.
State State
}
)
func (s *StructInjector) countBindType(typ BindType) (n int) {
for _, f := range s.fields {
if f.Object.BindType == typ {
n++
}
}
return
}
func MakeStructInjector(v reflect.Value, hijack Hijacker, goodFunc TypeChecker, values ...reflect.Value) *StructInjector {
s := &StructInjector{
elemType: IndirectType(v.Type()),
initRef: v,
initRefAsSlice: []reflect.Value{v},
elemType: IndirectType(v.Type()),
}
fields := lookupFields(s.elemType, nil)
fields := lookupFields(s.elemType, true, nil)
for _, f := range fields {
if hijack != nil {
if b, ok := hijack(f.Type); ok && b != nil {
s.fields = append(s.fields, &targetStructField{
@@ -55,28 +78,75 @@ func MakeStructInjector(v reflect.Value, hijack Hijacker, goodFunc TypeChecker,
})
break
}
}
}
s.Valid = len(s.fields) > 0
if s.Valid {
for i, f := range s.fields {
bindmethodTyp := "Static"
if f.Object.BindType == Dynamic {
bindmethodTyp = "Dynamic"
}
elemField := s.elemType.FieldByIndex(f.FieldIndex)
s.trace += fmt.Sprintf("[%d] %s binding: '%s' for field '%s %s'\n", i+1, bindmethodTyp, f.Object.Type.String(), elemField.Name, elemField.Type.String())
}
}
s.HasFields = len(s.fields) > 0
// set the overall state of this injector.
s.setState()
s.fillStruct()
return s
}
func (s *StructInjector) String() string {
return s.trace
// set the state, once.
func (s *StructInjector) setState() {
// note for zero length of struct's fields:
// if struct doesn't contain any field
// so both of the below variables will be 0,
// so it's a singleton.
// At the other hand the `s.HasFields` maybe false
// but the struct may contain UNEXPORTED fields or non-bindable fields (request-scoped on both cases)
// so a new controller/struct at the caller side should be initialized on each request,
// we should not depend on the `HasFields` for singleton or no, this is the reason I
// added the `.State` now.
staticBindingsFieldsLength := s.countBindType(Static)
structFieldsLength := NumFields(s.elemType, false)
// println("staticBindingsFieldsLength: ", staticBindingsFieldsLength)
// println("structFieldsLength: ", structFieldsLength)
// if the number of static values binded is equal to the
// total struct's fields(including unexported fields this time) then set as singleton.
if staticBindingsFieldsLength == structFieldsLength {
s.State = Singleton
return
}
s.CanInject = s.State == Stateless && s.HasFields
// the default is `Stateless`, which means that a new instance should be created
// on each inject action by the caller.
}
// fill the static bindings values once.
func (s *StructInjector) fillStruct() {
if !s.HasFields {
return
}
// if field is Static then set it to the value that passed by the caller,
// so will have the static bindings already and we can just use that value instead
// of creating new instance.
destElem := IndirectValue(s.initRef)
for _, f := range s.fields {
// if field is Static then set it to the value that passed by the caller,
// so will have the static bindings already and we can just use that value instead
// of creating new instance.
if s.State == Singleton && f.Object.BindType == Static {
destElem.FieldByIndex(f.FieldIndex).Set(f.Object.Value)
}
}
}
func (s *StructInjector) String() (trace string) {
for i, f := range s.fields {
elemField := s.elemType.FieldByIndex(f.FieldIndex)
trace += fmt.Sprintf("[%d] %s binding: '%s' for field '%s %s'\n",
i+1, bindTypeString(f.Object.BindType), f.Object.Type.String(),
elemField.Name, elemField.Type.String())
}
return
}
func (s *StructInjector) Inject(dest interface{}, ctx ...reflect.Value) {
@@ -91,25 +161,21 @@ func (s *StructInjector) Inject(dest interface{}, ctx ...reflect.Value) {
func (s *StructInjector) InjectElem(destElem reflect.Value, ctx ...reflect.Value) {
for _, f := range s.fields {
f.Object.Assign(ctx, func(v reflect.Value) {
// fmt.Printf("%s for %s at index: %d\n", destElem.Type().String(), f.Object.Type.String(), f.FieldIndex)
destElem.FieldByIndex(f.FieldIndex).Set(v)
})
}
}
func (s *StructInjector) InjectElemStaticOnly(destElem reflect.Value) (n int) {
for _, f := range s.fields {
if f.Object.BindType != Static {
continue
}
destElem.FieldByIndex(f.FieldIndex).Set(f.Object.Value)
n++
func (s *StructInjector) New() reflect.Value {
if s.State == Singleton {
return s.initRef
}
return
return reflect.New(s.elemType)
}
func (s *StructInjector) New(ctx ...reflect.Value) reflect.Value {
dest := reflect.New(s.elemType)
s.InjectElem(dest, ctx...)
return dest
func (s *StructInjector) NewAsSlice() []reflect.Value {
if s.State == Singleton {
return s.initRefAsSlice
}
return []reflect.Value{reflect.New(s.elemType)}
}