mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +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
|
||||
|
||||
- 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 `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