mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 15:30:36 +01:00
add a new x/reflex sub-package for reflection common functions - may be improved in the near future
This commit is contained in:
parent
fc2f8f4776
commit
410e5eae83
|
@ -28,6 +28,8 @@ The codebase for Dependency Injection, Internationalization and localization and
|
||||||
|
|
||||||
## Fixes and Improvements
|
## Fixes and Improvements
|
||||||
|
|
||||||
|
- Add a new [x/reflex](/x/reflex) sub-package.
|
||||||
|
|
||||||
- Add `Context.ReadMultipartRelated` as requested at: [issues/#1787](https://github.com/kataras/iris/issues/1787).
|
- Add `Context.ReadMultipartRelated` as requested at: [issues/#1787](https://github.com/kataras/iris/issues/1787).
|
||||||
|
|
||||||
- Add `Container.DependencyMatcher` and `Dependency.Match` to implement the feature requested at [issues/#1842](https://github.com/kataras/iris/issues/1842).
|
- Add `Container.DependencyMatcher` and `Dependency.Match` to implement the feature requested at [issues/#1842](https://github.com/kataras/iris/issues/1842).
|
||||||
|
|
8
x/reflex/error.go
Normal file
8
x/reflex/error.go
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package reflex
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
// IsError reports whether "typ" is an error type.
|
||||||
|
func IsError(typ interface{ Implements(reflect.Type) bool }) bool {
|
||||||
|
return typ.Implements(ErrTyp)
|
||||||
|
}
|
44
x/reflex/func.go
Normal file
44
x/reflex/func.go
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package reflex
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
// IsFunc reports whether the "kindable" is a type of function.
|
||||||
|
func IsFunc(typ interface{ Kind() reflect.Kind }) bool {
|
||||||
|
return typ.Kind() == reflect.Func
|
||||||
|
}
|
||||||
|
|
||||||
|
// FuncParam holds the properties of function input or output.
|
||||||
|
type FuncParam struct {
|
||||||
|
Index int
|
||||||
|
Type reflect.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupInputs returns the index and type of each function's input argument.
|
||||||
|
// Panics if "fn" is not a type of Func.
|
||||||
|
func LookupInputs(fn reflect.Type) []FuncParam {
|
||||||
|
n := fn.NumIn()
|
||||||
|
params := make([]FuncParam, 0, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
in := fn.In(i)
|
||||||
|
params = append(params, FuncParam{
|
||||||
|
Index: i,
|
||||||
|
Type: in,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupOutputs returns the index and type of each function's output argument.
|
||||||
|
// Panics if "fn" is not a type of Func.
|
||||||
|
func LookupOutputs(fn reflect.Type) []FuncParam {
|
||||||
|
n := fn.NumOut()
|
||||||
|
params := make([]FuncParam, 0, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
out := fn.Out(i)
|
||||||
|
params = append(params, FuncParam{
|
||||||
|
Index: i,
|
||||||
|
Type: out,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
}
|
19
x/reflex/reflectx.go
Normal file
19
x/reflex/reflectx.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package reflex
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
// IndirectType returns the value of a pointer-type "typ".
|
||||||
|
// If "IndirectType" is a pointer, array, chan, map or slice it returns its Elem,
|
||||||
|
// otherwise returns the "typ" as it is.
|
||||||
|
func IndirectType(typ reflect.Type) reflect.Type {
|
||||||
|
switch typ.Kind() {
|
||||||
|
case reflect.Ptr, reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
|
||||||
|
return typ.Elem()
|
||||||
|
}
|
||||||
|
return typ
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndirectValue returns the element type (e.g. if pointer of *User it will return the User type).
|
||||||
|
func IndirectValue(val reflect.Value) reflect.Value {
|
||||||
|
return reflect.Indirect(val)
|
||||||
|
}
|
56
x/reflex/struct.go
Normal file
56
x/reflex/struct.go
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package reflex
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
// LookupFields returns a slice of all fields containg a struct field
|
||||||
|
// of the given "fieldTag" of the "typ" struct. The fields returned
|
||||||
|
// are flatted and reclusive over fields with value of struct.
|
||||||
|
// Panics if "typ" is not a type of Struct.
|
||||||
|
func LookupFields(typ reflect.Type, fieldTag string) []reflect.StructField {
|
||||||
|
fields := lookupFields(typ, fieldTag, nil)
|
||||||
|
return fields[0:len(fields):len(fields)]
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupFields(typ reflect.Type, fieldTag string, parentIndex []int) []reflect.StructField {
|
||||||
|
n := typ.NumField()
|
||||||
|
fields := make([]reflect.StructField, 0, n)
|
||||||
|
checkTag := fieldTag != ""
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
field := typ.Field(i)
|
||||||
|
if field.PkgPath != "" { // skip unexported fields.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if checkTag {
|
||||||
|
if v := field.Tag.Get(fieldTag); v == "" || v == "-" {
|
||||||
|
// Skip fields that don't contain the 'fieldTag' tag or has '-'.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldType := IndirectType(field.Type)
|
||||||
|
|
||||||
|
if fieldType.Kind() == reflect.Struct { // It's a struct inside a struct and it's not time, flat it.
|
||||||
|
if fieldType != TimeType {
|
||||||
|
structFields := lookupFields(fieldType, fieldTag, append(parentIndex, i))
|
||||||
|
if nn := len(structFields); nn > 0 {
|
||||||
|
fields = append(fields, structFields...)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
index := []int{i}
|
||||||
|
if len(parentIndex) > 0 {
|
||||||
|
index = append(parentIndex, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp := make([]int, len(index))
|
||||||
|
copy(tmp, index)
|
||||||
|
field.Index = tmp
|
||||||
|
|
||||||
|
fields = append(fields, field)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
30
x/reflex/types.go
Normal file
30
x/reflex/types.go
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package reflex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Common reflect types for go standard data types.
|
||||||
|
var (
|
||||||
|
StringType = reflect.TypeOf("")
|
||||||
|
BytesType = reflect.TypeOf([]byte{})
|
||||||
|
IntType = reflect.TypeOf(int(0))
|
||||||
|
Int16Type = reflect.TypeOf(int16(0))
|
||||||
|
Int32Type = reflect.TypeOf(int32(0))
|
||||||
|
Int64Type = reflect.TypeOf(int64(0))
|
||||||
|
Float32Type = reflect.TypeOf(float32(0))
|
||||||
|
Float64Type = reflect.TypeOf(float64(0))
|
||||||
|
TimeType = reflect.TypeOf(time.Time{})
|
||||||
|
IpTyp = reflect.TypeOf(net.IP{})
|
||||||
|
JSONNumberTyp = reflect.TypeOf(json.Number(""))
|
||||||
|
StringerTyp = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
|
||||||
|
ArrayIntegerTyp = reflect.TypeOf([]int{})
|
||||||
|
ArrayStringTyp = reflect.TypeOf([]string{})
|
||||||
|
DoubleArrayIntegerTyp = reflect.TypeOf([][]int{})
|
||||||
|
DoubleArrayStringTyp = reflect.TypeOf([][]string{})
|
||||||
|
ErrTyp = reflect.TypeOf((*error)(nil)).Elem()
|
||||||
|
)
|
65
x/reflex/zero.go
Normal file
65
x/reflex/zero.go
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
package reflex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Zeroer can be implemented by custom types
|
||||||
|
// to report whether its current value is zero.
|
||||||
|
// Standard Time also implements that.
|
||||||
|
type Zeroer interface {
|
||||||
|
IsZero() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZero reports whether "v" is zero value or no.
|
||||||
|
// The given "v" value can complete the Zeroer interface
|
||||||
|
// which can be used to customize the behavior for each type of "v".
|
||||||
|
func IsZero(v interface{}) bool {
|
||||||
|
switch t := v.(type) {
|
||||||
|
case Zeroer: // completes the time.Time as well.
|
||||||
|
return t.IsZero()
|
||||||
|
case string:
|
||||||
|
return t == ""
|
||||||
|
case int:
|
||||||
|
return t == 0
|
||||||
|
case int8:
|
||||||
|
return t == 0
|
||||||
|
case int16:
|
||||||
|
return t == 0
|
||||||
|
case int32:
|
||||||
|
return t == 0
|
||||||
|
case int64:
|
||||||
|
return t == 0
|
||||||
|
case uint:
|
||||||
|
return t == 0
|
||||||
|
case uint8:
|
||||||
|
return t == 0
|
||||||
|
case uint16:
|
||||||
|
return t == 0
|
||||||
|
case uint32:
|
||||||
|
return t == 0
|
||||||
|
case uint64:
|
||||||
|
return t == 0
|
||||||
|
case float32:
|
||||||
|
return t == 0
|
||||||
|
case float64:
|
||||||
|
return t == 0
|
||||||
|
case bool:
|
||||||
|
return !t
|
||||||
|
case []int:
|
||||||
|
return len(t) == 0
|
||||||
|
case []string:
|
||||||
|
return len(t) == 0
|
||||||
|
case [][]int:
|
||||||
|
return len(t) == 0
|
||||||
|
case [][]string:
|
||||||
|
return len(t) == 0
|
||||||
|
case json.Number:
|
||||||
|
return t.String() == ""
|
||||||
|
case net.IP:
|
||||||
|
return len(t) == 0
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user