github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/x/typesx/type.go (about) 1 package typesx 2 3 import ( 4 "encoding" 5 "go/ast" 6 "go/types" 7 "reflect" 8 "strings" 9 10 "github.com/machinefi/w3bstream/pkg/depends/x/reflectx" 11 ) 12 13 type Type interface { 14 Unwrap() any 15 16 Name() string 17 PkgPath() string 18 String() string 19 Kind() reflect.Kind 20 Implements(Type) bool 21 AssignableTo(Type) bool 22 ConvertibleTo(Type) bool 23 Comparable() bool 24 25 Key() Type 26 Elem() Type 27 Len() int 28 29 NumField() int 30 Field(int) StructField 31 FieldByName(string) (StructField, bool) 32 FieldByNameFunc(func(string) bool) (StructField, bool) 33 34 NumMethod() int 35 Method(int) Method 36 MethodByName(string) (Method, bool) 37 38 IsVariadic() bool 39 NumIn() int 40 In(int) Type 41 NumOut() int 42 Out(int) Type 43 } 44 45 type Method interface { 46 PkgPath() string 47 Name() string 48 Type() Type 49 } 50 51 type StructField interface { 52 PkgPath() string 53 Name() string 54 Tag() reflect.StructTag 55 Type() Type 56 Anonymous() bool 57 } 58 59 func TryNew(u Type) (reflect.Value, bool) { 60 if v, ok := u.(*ReflectType); ok { 61 return reflectx.New(v.Type), true 62 } 63 return reflect.Value{}, false 64 } 65 66 var RtTextMarshaler = FromReflectType(reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()) 67 68 func EncodingTextMarshalerTypeReplacer(u Type) (Type, bool) { 69 switch x := u.(type) { 70 case *GoType: 71 return FromGoType(types.Typ[types.String]), x.Implements(RtTextMarshaler) 72 case *ReflectType: 73 return FromReflectType(reflect.TypeOf("")), x.Implements(RtTextMarshaler) 74 } 75 return nil, false 76 } 77 78 func DeRef(t Type) Type { 79 for t.Kind() == reflect.Ptr { 80 t = t.Elem() 81 } 82 return t 83 } 84 85 func FullTypeName(t Type) string { 86 b := strings.Builder{} 87 88 for t.Kind() == reflect.Ptr { 89 b.WriteByte('*') 90 t = t.Elem() 91 } 92 93 if name := t.Name(); name != "" { 94 if path := t.PkgPath(); path != "" { 95 b.WriteString(path) 96 b.WriteRune('.') 97 } 98 b.WriteString(name) 99 return b.String() 100 } 101 b.WriteString(b.String()) 102 return b.String() 103 } 104 105 func FieldDisplayName(tag reflect.StructTag, key string, name string) (keyTag string, omitempty, exists bool) { 106 keyTag, exists = tag.Lookup(key) 107 if !exists { 108 keyTag = name 109 return 110 } 111 omitempty = strings.Index(keyTag, "omitempty") > 0 112 commaIdx := strings.IndexRune(keyTag, ',') 113 if keyTag == "" || commaIdx == 0 { 114 return name, omitempty, true 115 } 116 if commaIdx == -1 { 117 return 118 } 119 keyTag = keyTag[0:commaIdx] 120 return 121 } 122 123 func EachField(t Type, key string, each func(f StructField, display string, omitempty bool) bool, keepNestedTags ...string) { 124 for i := 0; i < t.NumField(); i++ { 125 f := t.Field(i) 126 fname := f.Name() 127 ftag := f.Tag() 128 129 display, omitempty, exists := FieldDisplayName(ftag, key, fname) 130 131 if !ast.IsExported(fname) || display == "-" { 132 continue 133 } 134 ftype := DeRef(f.Type()) 135 if f.Anonymous() { 136 k := ftype.Kind() 137 if k == reflect.Interface { 138 continue 139 } 140 if k == reflect.Struct { 141 if !exists { 142 for _, tag := range keepNestedTags { 143 if _, ok := ftag.Lookup(tag); ok { 144 exists = true 145 break 146 } 147 } 148 } 149 if !exists { 150 EachField(ftype, key, each) 151 continue 152 } 153 } 154 } 155 if !each(f, display, omitempty) { 156 break 157 } 158 } 159 }