reflect.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. package di
  2. import "reflect"
  3. // EmptyIn is just an empty slice of reflect.Value.
  4. var EmptyIn = []reflect.Value{}
  5. // IsZero returns true if a value is nil.
  6. // Remember; fields to be checked should be exported otherwise it returns false.
  7. // Notes for users:
  8. // Boolean's zero value is false, even if not set-ed.
  9. // UintXX are not zero on 0 because they are pointers to.
  10. func IsZero(v reflect.Value) bool {
  11. switch v.Kind() {
  12. case reflect.Struct:
  13. zero := true
  14. for i := 0; i < v.NumField(); i++ {
  15. zero = zero && IsZero(v.Field(i))
  16. }
  17. if typ := v.Type(); typ != nil && v.IsValid() {
  18. f, ok := typ.MethodByName("IsZero")
  19. // if not found
  20. // if has input arguments (1 is for the value receiver, so > 1 for the actual input args)
  21. // if output argument is not boolean
  22. // then skip this IsZero user-defined function.
  23. if !ok || f.Type.NumIn() > 1 || f.Type.NumOut() != 1 && f.Type.Out(0).Kind() != reflect.Bool {
  24. return zero
  25. }
  26. method := v.Method(f.Index)
  27. // no needed check but:
  28. if method.IsValid() && !method.IsNil() {
  29. // it shouldn't panic here.
  30. zero = method.Call(EmptyIn)[0].Interface().(bool)
  31. }
  32. }
  33. return zero
  34. case reflect.Func, reflect.Map, reflect.Slice:
  35. return v.IsNil()
  36. case reflect.Array:
  37. zero := true
  38. for i := 0; i < v.Len(); i++ {
  39. zero = zero && IsZero(v.Index(i))
  40. }
  41. return zero
  42. }
  43. // if not any special type then use the reflect's .Zero
  44. // usually for fields, but remember if it's boolean and it's false
  45. // then it's zero, even if set-ed.
  46. if !v.CanInterface() {
  47. // if can't interface, i.e return value from unexported field or method then return false
  48. return false
  49. }
  50. zero := reflect.Zero(v.Type())
  51. return v.Interface() == zero.Interface()
  52. }
  53. // IndirectValue returns the reflect.Value that "v" points to.
  54. // If "v" is a nil pointer, Indirect returns a zero Value.
  55. // If "v" is not a pointer, Indirect returns v.
  56. func IndirectValue(v reflect.Value) reflect.Value {
  57. return reflect.Indirect(v)
  58. }
  59. // ValueOf returns the reflect.Value of "o".
  60. // If "o" is already a reflect.Value returns "o".
  61. func ValueOf(o interface{}) reflect.Value {
  62. if v, ok := o.(reflect.Value); ok {
  63. return v
  64. }
  65. return reflect.ValueOf(o)
  66. }
  67. // ValuesOf same as `ValueOf` but accepts a slice of
  68. // somethings and returns a slice of reflect.Value.
  69. func ValuesOf(valuesAsInterface []interface{}) (values []reflect.Value) {
  70. for _, v := range valuesAsInterface {
  71. values = append(values, ValueOf(v))
  72. }
  73. return
  74. }
  75. // IndirectType returns the value of a pointer-type "typ".
  76. // If "typ" is a pointer, array, chan, map or slice it returns its Elem,
  77. // otherwise returns the typ as it's.
  78. func IndirectType(typ reflect.Type) reflect.Type {
  79. switch typ.Kind() {
  80. case reflect.Ptr, reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
  81. return typ.Elem()
  82. }
  83. return typ
  84. }
  85. func goodVal(v reflect.Value) bool {
  86. switch v.Kind() {
  87. case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice:
  88. if v.IsNil() {
  89. return false
  90. }
  91. }
  92. return v.IsValid()
  93. }
  94. // IsFunc returns true if the passed type is function.
  95. func IsFunc(kindable interface {
  96. Kind() reflect.Kind
  97. }) bool {
  98. return kindable.Kind() == reflect.Func
  99. }
  100. func equalTypes(got reflect.Type, expected reflect.Type) bool {
  101. if got == expected {
  102. return true
  103. }
  104. // if accepts an interface, check if the given "got" type does
  105. // implement this "expected" user handler's input argument.
  106. if expected.Kind() == reflect.Interface {
  107. // fmt.Printf("expected interface = %s and got to set on the arg is: %s\n", expected.String(), got.String())
  108. return got.Implements(expected)
  109. }
  110. return false
  111. }
  112. // for controller's fields only.
  113. func structFieldIgnored(f reflect.StructField) bool {
  114. if !f.Anonymous {
  115. return true // if not anonymous(embedded), ignore it.
  116. }
  117. s := f.Tag.Get("ignore")
  118. return s == "true" // if has an ignore tag then ignore it.
  119. }
  120. type field struct {
  121. Type reflect.Type
  122. Name string // the actual name.
  123. Index []int // the index of the field, slice if it's part of a embedded struct
  124. CanSet bool // is true if it's exported.
  125. // this could be empty, but in our cases it's not,
  126. // it's filled with the bind object (as service which means as static value)
  127. // and it's filled from the lookupFields' caller.
  128. AnyValue reflect.Value
  129. }
  130. // NumFields returns the total number of fields, and the embedded, even if the embedded struct is not exported,
  131. // it will check for its exported fields.
  132. func NumFields(elemTyp reflect.Type, skipUnexported bool) int {
  133. return len(lookupFields(elemTyp, skipUnexported, nil))
  134. }
  135. func lookupFields(elemTyp reflect.Type, skipUnexported bool, parentIndex []int) (fields []field) {
  136. if elemTyp.Kind() != reflect.Struct {
  137. return
  138. }
  139. for i, n := 0, elemTyp.NumField(); i < n; i++ {
  140. f := elemTyp.Field(i)
  141. if IndirectType(f.Type).Kind() == reflect.Struct &&
  142. !structFieldIgnored(f) {
  143. fields = append(fields, lookupFields(f.Type, skipUnexported, append(parentIndex, i))...)
  144. continue
  145. }
  146. // skip unexported fields here,
  147. // after the check for embedded structs, these can be binded if their
  148. // fields are exported.
  149. isExported := f.PkgPath == ""
  150. if skipUnexported && !isExported {
  151. continue
  152. }
  153. index := []int{i}
  154. if len(parentIndex) > 0 {
  155. index = append(parentIndex, i)
  156. }
  157. field := field{
  158. Type: f.Type,
  159. Name: f.Name,
  160. Index: index,
  161. CanSet: isExported,
  162. }
  163. fields = append(fields, field)
  164. }
  165. return
  166. }
  167. // LookupNonZeroFieldsValues lookup for filled fields based on the "v" struct value instance.
  168. // It returns a slice of reflect.Value (same type as `Values`) that can be binded,
  169. // like the end-developer's custom values.
  170. func LookupNonZeroFieldsValues(v reflect.Value, skipUnexported bool) (bindValues []reflect.Value) {
  171. elem := IndirectValue(v)
  172. fields := lookupFields(IndirectType(v.Type()), skipUnexported, nil)
  173. for _, f := range fields {
  174. if fieldVal := elem.FieldByIndex(f.Index); /*f.Type.Kind() == reflect.Ptr &&*/
  175. !IsZero(fieldVal) {
  176. bindValues = append(bindValues, fieldVal)
  177. }
  178. }
  179. return
  180. }