mirror of
https://github.com/kataras/iris.git
synced 2025-12-18 02:17:05 +00:00
Add status code 103 Early Hints. Add the ability to customize and change the order of controller's fields and their registered valid dependencies relative to: #1343
Former-commit-id: 5bd9e02e5fafca135d17cad87f4a9aec526b333b
This commit is contained in:
@@ -33,6 +33,7 @@ func Struct(s interface{}, values ...reflect.Value) *StructInjector {
|
||||
ValueOf(s),
|
||||
DefaultHijacker,
|
||||
DefaultTypeChecker,
|
||||
SortByNumMethods,
|
||||
Values(values).CloneWithFieldsOf(s)...,
|
||||
)
|
||||
}
|
||||
@@ -64,6 +65,7 @@ type D struct {
|
||||
|
||||
hijacker Hijacker
|
||||
goodFunc TypeChecker
|
||||
sorter Sorter
|
||||
}
|
||||
|
||||
// New creates and returns a new Dependency Injection container.
|
||||
@@ -85,13 +87,20 @@ func (d *D) GoodFunc(fn TypeChecker) *D {
|
||||
return d
|
||||
}
|
||||
|
||||
// Sort sets the fields and valid bindable values sorter for struct injection.
|
||||
func (d *D) Sort(with Sorter) *D {
|
||||
d.sorter = with
|
||||
return d
|
||||
}
|
||||
|
||||
// Clone returns a new Dependency Injection container, it adopts the
|
||||
// parent's (current "D") hijacker, good func type checker and all dependencies values.
|
||||
// parent's (current "D") hijacker, good func type checker, sorter and all dependencies values.
|
||||
func (d *D) Clone() *D {
|
||||
return &D{
|
||||
Values: d.Values.Clone(),
|
||||
hijacker: d.hijacker,
|
||||
goodFunc: d.goodFunc,
|
||||
sorter: d.sorter,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +117,7 @@ func (d *D) Struct(s interface{}) *StructInjector {
|
||||
ValueOf(s),
|
||||
d.hijacker,
|
||||
d.goodFunc,
|
||||
d.sorter,
|
||||
d.Values.CloneWithFieldsOf(s)...,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -178,11 +178,6 @@ type field struct {
|
||||
Name string // the actual name.
|
||||
Index []int // the index of the field, slice if it's part of a embedded struct
|
||||
CanSet bool // is true if it's exported.
|
||||
|
||||
// this could be empty, but in our cases it's not,
|
||||
// it's filled with the bind object (as service which means as static value)
|
||||
// and it's filled from the lookupFields' caller.
|
||||
AnyValue reflect.Value
|
||||
}
|
||||
|
||||
// NumFields returns the total number of fields, and the embedded, even if the embedded struct is not exported,
|
||||
|
||||
@@ -3,6 +3,7 @@ package di
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Scope is the struct injector's struct value scope/permant state.
|
||||
@@ -40,6 +41,8 @@ type (
|
||||
targetStructField struct {
|
||||
Object *BindObject
|
||||
FieldIndex []int
|
||||
// ValueIndex is used mostly for debugging, it's the order of the registered binded value targets to that field.
|
||||
ValueIndex int
|
||||
}
|
||||
|
||||
// StructInjector keeps the data that are needed in order to do the binding injection
|
||||
@@ -68,13 +71,37 @@ func (s *StructInjector) countBindType(typ BindType) (n int) {
|
||||
return
|
||||
}
|
||||
|
||||
// Sorter is the type for sort customization of a struct's fields
|
||||
// and its available bindable values.
|
||||
//
|
||||
// Sorting applies only when a field can accept more than one registered value.
|
||||
type Sorter func(t1 reflect.Type, t2 reflect.Type) bool
|
||||
|
||||
// SortByNumMethods is a builtin sorter to sort fields and values
|
||||
// based on their type and its number of methods, highest number of methods goes first.
|
||||
//
|
||||
// It is the default sorter on package-level struct injector function `Struct`.
|
||||
var SortByNumMethods Sorter = func(t1 reflect.Type, t2 reflect.Type) bool {
|
||||
if t1.Kind() != t2.Kind() {
|
||||
return true
|
||||
}
|
||||
|
||||
if k := t1.Kind(); k == reflect.Interface || k == reflect.Struct {
|
||||
return t1.NumMethod() > t2.NumMethod()
|
||||
} else if k != reflect.Struct {
|
||||
return false // non-structs goes last.
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// MakeStructInjector returns a new struct injector, which will be the object
|
||||
// that the caller should use to bind exported fields or
|
||||
// embedded unexported fields that contain exported fields
|
||||
// of the "v" struct value or pointer.
|
||||
//
|
||||
// The hijack and the goodFunc are optional, the "values" is the dependencies collection.
|
||||
func MakeStructInjector(v reflect.Value, hijack Hijacker, goodFunc TypeChecker, values ...reflect.Value) *StructInjector {
|
||||
func MakeStructInjector(v reflect.Value, hijack Hijacker, goodFunc TypeChecker, sorter Sorter, values ...reflect.Value) *StructInjector {
|
||||
s := &StructInjector{
|
||||
initRef: v,
|
||||
initRefAsSlice: []reflect.Value{v},
|
||||
@@ -96,7 +123,19 @@ func MakeStructInjector(v reflect.Value, hijack Hijacker, goodFunc TypeChecker,
|
||||
|
||||
visited := make(map[int]struct{}, 0) // add a visited to not add twice a single value (09-Jul-2019).
|
||||
fields := lookupFields(s.elemType, true, nil)
|
||||
|
||||
// for idx, val := range values {
|
||||
// fmt.Printf("[%d] value type [%s] value name [%s]\n", idx, val.Type().String(), val.String())
|
||||
// }
|
||||
|
||||
if len(fields) > 1 && sorter != nil {
|
||||
sort.Slice(fields, func(i, j int) bool {
|
||||
return sorter(fields[i].Type, fields[j].Type)
|
||||
})
|
||||
}
|
||||
|
||||
for _, f := range fields {
|
||||
// fmt.Printf("[%d] field type [%s] value name [%s]\n", idx, f.Type.String(), f.Name)
|
||||
if hijack != nil {
|
||||
if b, ok := hijack(f.Type); ok && b != nil {
|
||||
s.fields = append(s.fields, &targetStructField{
|
||||
@@ -108,6 +147,8 @@ func MakeStructInjector(v reflect.Value, hijack Hijacker, goodFunc TypeChecker,
|
||||
}
|
||||
}
|
||||
|
||||
var possibleValues []*targetStructField
|
||||
|
||||
for idx, val := range values {
|
||||
if _, alreadySet := visited[idx]; alreadySet {
|
||||
continue
|
||||
@@ -120,15 +161,33 @@ func MakeStructInjector(v reflect.Value, hijack Hijacker, goodFunc TypeChecker,
|
||||
}
|
||||
|
||||
if b.IsAssignable(f.Type) {
|
||||
visited[idx] = struct{}{}
|
||||
// fmt.Printf("bind the object to the field: %s at index: %#v and type: %s\n", f.Name, f.Index, f.Type.String())
|
||||
s.fields = append(s.fields, &targetStructField{
|
||||
possibleValues = append(possibleValues, &targetStructField{
|
||||
ValueIndex: idx,
|
||||
FieldIndex: f.Index,
|
||||
Object: &b,
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if l := len(possibleValues); l == 0 {
|
||||
continue
|
||||
} else if l > 1 && sorter != nil {
|
||||
sort.Slice(possibleValues, func(i, j int) bool {
|
||||
// if first.Object.BindType != second.Object.BindType {
|
||||
// return true
|
||||
// }
|
||||
|
||||
// if first.Object.BindType != Static { // dynamic goes last.
|
||||
// return false
|
||||
// }
|
||||
return sorter(possibleValues[i].Object.Type, possibleValues[j].Object.Type)
|
||||
})
|
||||
}
|
||||
|
||||
tf := possibleValues[0]
|
||||
visited[tf.ValueIndex] = struct{}{}
|
||||
// fmt.Printf("bind the object to the field: %s at index: %#v and type: %s\n", f.Name, f.Index, f.Type.String())
|
||||
s.fields = append(s.fields, tf)
|
||||
}
|
||||
|
||||
s.Has = len(s.fields) > 0
|
||||
|
||||
Reference in New Issue
Block a user