github.com/searKing/golang/go@v1.2.117/reflect/type.go (about) 1 // Copyright 2020 The searKing Author. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package reflect 6 7 import ( 8 "bytes" 9 "fmt" 10 "reflect" 11 12 bytes_ "github.com/searKing/golang/go/bytes" 13 "github.com/searKing/golang/go/container/traversal" 14 ) 15 16 // nil, unknown type 17 func IsNilType(v reflect.Type) (result bool) { 18 return v == nil 19 } 20 func FollowTypePointer(v reflect.Type) reflect.Type { 21 if IsNilType(v) { 22 return v 23 } 24 if v.Kind() == reflect.Ptr { 25 return FollowTypePointer(v.Elem()) 26 } 27 return v 28 } 29 30 // A field represents a single field found in a struct. 31 type FieldTypeInfo struct { 32 structField reflect.StructField 33 index []int 34 } 35 36 func (info FieldTypeInfo) MiddleNodes() []any { 37 typ := info.structField.Type 38 var middles []any 39 typ = FollowTypePointer(typ) 40 if IsNilType(typ) { 41 return nil 42 } 43 if typ.Kind() != reflect.Struct { 44 return nil 45 } 46 // Scan typ for fields to include. 47 for i := 0; i < typ.NumField(); i++ { 48 index := make([]int, len(info.index)+1) 49 copy(index, info.index) 50 index[len(info.index)] = i 51 sf := typ.Field(i) 52 middles = append(middles, FieldTypeInfo{ 53 structField: sf, 54 index: index, 55 }) 56 } 57 return middles 58 } 59 60 func (info FieldTypeInfo) Depth() int { 61 return len(info.index) 62 } 63 64 func (info FieldTypeInfo) StructField() (reflect.StructField, bool) { 65 if IsEmptyValue(reflect.ValueOf(info.structField)) { 66 return info.structField, false 67 } 68 return info.structField, true 69 } 70 71 func (info FieldTypeInfo) Index() []int { 72 return info.index 73 } 74 75 func (info FieldTypeInfo) String() string { 76 if info.structField.Type == nil { 77 return fmt.Sprintf("%+v", nil) 78 } 79 return fmt.Sprintf("%+v", info.structField.Type.String()) 80 } 81 82 type FieldTypeInfoHandler interface { 83 Handler(info FieldTypeInfo) (goon bool) 84 } 85 type FieldTypeInfoHandlerFunc func(info FieldTypeInfo) (goon bool) 86 87 func (f FieldTypeInfoHandlerFunc) Handler(info FieldTypeInfo) (goon bool) { 88 return f(info) 89 } 90 91 // Breadth First Search 92 func WalkTypeBFS(typ reflect.Type, handler FieldTypeInfoHandler) { 93 traversal.BreadthFirstSearchOrder(FieldTypeInfo{ 94 structField: reflect.StructField{ 95 Type: typ, 96 }, 97 }, traversal.HandlerFunc(func(node any, depth int) (goon bool) { 98 return handler.Handler(node.(FieldTypeInfo)) 99 })) 100 } 101 102 // Wid First Search 103 func WalkTypeDFS(typ reflect.Type, handler FieldTypeInfoHandler) { 104 traversal.DepthFirstSearchOrder(FieldTypeInfo{ 105 structField: reflect.StructField{ 106 Type: typ, 107 }, 108 }, traversal.HandlerFunc(func(node any, depth int) (goon bool) { 109 return handler.Handler(node.(FieldTypeInfo)) 110 })) 111 } 112 113 func DumpTypeInfoDFS(t reflect.Type) string { 114 dumpInfo := &bytes.Buffer{} 115 first := true 116 WalkTypeDFS(t, FieldTypeInfoHandlerFunc(func(info FieldTypeInfo) (goon bool) { 117 if first { 118 first = false 119 bytes_.NewIndent(dumpInfo, "", "\t", info.Depth()) 120 } else { 121 bytes_.NewLine(dumpInfo, "", "\t", info.Depth()) 122 } 123 dumpInfo.WriteString(fmt.Sprintf("%+v", info.String())) 124 return true 125 })) 126 return dumpInfo.String() 127 } 128 129 func DumpTypeInfoBFS(t reflect.Type) string { 130 dumpInfo := &bytes.Buffer{} 131 first := true 132 WalkTypeBFS(t, FieldTypeInfoHandlerFunc(func(info FieldTypeInfo) (goon bool) { 133 if first { 134 first = false 135 bytes_.NewIndent(dumpInfo, "", "\t", info.Depth()) 136 } else { 137 bytes_.NewLine(dumpInfo, "", "\t", info.Depth()) 138 } 139 dumpInfo.WriteString(fmt.Sprintf("%+v", info.String())) 140 return true 141 })) 142 return dumpInfo.String() 143 }