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  }