package reflectlite
import (
"internal/unsafeheader"
"unsafe"
)
type Type interface {
Name () string
PkgPath () string
Size () uintptr
Kind () Kind
Implements (u Type ) bool
AssignableTo (u Type ) bool
Comparable () bool
String () string
Elem () Type
common () *rtype
uncommon () *uncommonType
}
type Kind uint
const (
Invalid Kind = iota
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Pointer
Slice
String
Struct
UnsafePointer
)
const Ptr = Pointer
type tflag uint8
const (
tflagUncommon tflag = 1 << 0
tflagExtraStar tflag = 1 << 1
tflagNamed tflag = 1 << 2
tflagRegularMemory tflag = 1 << 3
)
type rtype struct {
size uintptr
ptrdata uintptr
hash uint32
tflag tflag
align uint8
fieldAlign uint8
kind uint8
equal func (unsafe .Pointer , unsafe .Pointer ) bool
gcdata *byte
str nameOff
ptrToThis typeOff
}
type method struct {
name nameOff
mtyp typeOff
ifn textOff
tfn textOff
}
type uncommonType struct {
pkgPath nameOff
mcount uint16
xcount uint16
moff uint32
_ uint32
}
type chanDir int
const (
recvDir chanDir = 1 << iota
sendDir
bothDir = recvDir | sendDir
)
type arrayType struct {
rtype
elem *rtype
slice *rtype
len uintptr
}
type chanType struct {
rtype
elem *rtype
dir uintptr
}
type funcType struct {
rtype
inCount uint16
outCount uint16
}
type imethod struct {
name nameOff
typ typeOff
}
type interfaceType struct {
rtype
pkgPath name
methods []imethod
}
type mapType struct {
rtype
key *rtype
elem *rtype
bucket *rtype
hasher func (unsafe .Pointer , uintptr ) uintptr
keysize uint8
valuesize uint8
bucketsize uint16
flags uint32
}
type ptrType struct {
rtype
elem *rtype
}
type sliceType struct {
rtype
elem *rtype
}
type structField struct {
name name
typ *rtype
offsetEmbed uintptr
}
func (f *structField ) offset () uintptr {
return f .offsetEmbed >> 1
}
func (f *structField ) embedded () bool {
return f .offsetEmbed &1 != 0
}
type structType struct {
rtype
pkgPath name
fields []structField
}
type name struct {
bytes *byte
}
func (n name ) data (off int , whySafe string ) *byte {
return (*byte )(add (unsafe .Pointer (n .bytes ), uintptr (off ), whySafe ))
}
func (n name ) isExported () bool {
return (*n .bytes )&(1 <<0 ) != 0
}
func (n name ) hasTag () bool {
return (*n .bytes )&(1 <<1 ) != 0
}
func (n name ) readVarint (off int ) (int , int ) {
v := 0
for i := 0 ; ; i ++ {
x := *n .data (off +i , "read varint" )
v += int (x &0x7f ) << (7 * i )
if x &0x80 == 0 {
return i + 1 , v
}
}
}
func (n name ) name () (s string ) {
if n .bytes == nil {
return
}
i , l := n .readVarint (1 )
hdr := (*unsafeheader .String )(unsafe .Pointer (&s ))
hdr .Data = unsafe .Pointer (n .data (1 +i , "non-empty string" ))
hdr .Len = l
return
}
func (n name ) tag () (s string ) {
if !n .hasTag () {
return ""
}
i , l := n .readVarint (1 )
i2 , l2 := n .readVarint (1 + i + l )
hdr := (*unsafeheader .String )(unsafe .Pointer (&s ))
hdr .Data = unsafe .Pointer (n .data (1 +i +l +i2 , "non-empty string" ))
hdr .Len = l2
return
}
func (n name ) pkgPath () string {
if n .bytes == nil || *n .data (0 , "name flag field" )&(1 <<2 ) == 0 {
return ""
}
i , l := n .readVarint (1 )
off := 1 + i + l
if n .hasTag () {
i2 , l2 := n .readVarint (off )
off += i2 + l2
}
var nameOff int32
copy ((*[4 ]byte )(unsafe .Pointer (&nameOff ))[:], (*[4 ]byte )(unsafe .Pointer (n .data (off , "name offset field" )))[:])
pkgPathName := name {(*byte )(resolveTypeOff (unsafe .Pointer (n .bytes ), nameOff ))}
return pkgPathName .name ()
}
const (
kindDirectIface = 1 << 5
kindGCProg = 1 << 6
kindMask = (1 << 5 ) - 1
)
func (k Kind ) String () string {
if int (k ) < len (kindNames ) {
return kindNames [k ]
}
return kindNames [0 ]
}
var kindNames = []string {
Invalid : "invalid" ,
Bool : "bool" ,
Int : "int" ,
Int8 : "int8" ,
Int16 : "int16" ,
Int32 : "int32" ,
Int64 : "int64" ,
Uint : "uint" ,
Uint8 : "uint8" ,
Uint16 : "uint16" ,
Uint32 : "uint32" ,
Uint64 : "uint64" ,
Uintptr : "uintptr" ,
Float32 : "float32" ,
Float64 : "float64" ,
Complex64 : "complex64" ,
Complex128 : "complex128" ,
Array : "array" ,
Chan : "chan" ,
Func : "func" ,
Interface : "interface" ,
Map : "map" ,
Ptr : "ptr" ,
Slice : "slice" ,
String : "string" ,
Struct : "struct" ,
UnsafePointer : "unsafe.Pointer" ,
}
func (t *uncommonType ) methods () []method {
if t .mcount == 0 {
return nil
}
return (*[1 << 16 ]method )(add (unsafe .Pointer (t ), uintptr (t .moff ), "t.mcount > 0" ))[:t .mcount :t .mcount ]
}
func (t *uncommonType ) exportedMethods () []method {
if t .xcount == 0 {
return nil
}
return (*[1 << 16 ]method )(add (unsafe .Pointer (t ), uintptr (t .moff ), "t.xcount > 0" ))[:t .xcount :t .xcount ]
}
func resolveNameOff (ptrInModule unsafe .Pointer , off int32 ) unsafe .Pointer
func resolveTypeOff (rtype unsafe .Pointer , off int32 ) unsafe .Pointer
type nameOff int32
type typeOff int32
type textOff int32
func (t *rtype ) nameOff (off nameOff ) name {
return name {(*byte )(resolveNameOff (unsafe .Pointer (t ), int32 (off )))}
}
func (t *rtype ) typeOff (off typeOff ) *rtype {
return (*rtype )(resolveTypeOff (unsafe .Pointer (t ), int32 (off )))
}
func (t *rtype ) uncommon () *uncommonType {
if t .tflag &tflagUncommon == 0 {
return nil
}
switch t .Kind () {
case Struct :
return &(*structTypeUncommon )(unsafe .Pointer (t )).u
case Ptr :
type u struct {
ptrType
u uncommonType
}
return &(*u )(unsafe .Pointer (t )).u
case Func :
type u struct {
funcType
u uncommonType
}
return &(*u )(unsafe .Pointer (t )).u
case Slice :
type u struct {
sliceType
u uncommonType
}
return &(*u )(unsafe .Pointer (t )).u
case Array :
type u struct {
arrayType
u uncommonType
}
return &(*u )(unsafe .Pointer (t )).u
case Chan :
type u struct {
chanType
u uncommonType
}
return &(*u )(unsafe .Pointer (t )).u
case Map :
type u struct {
mapType
u uncommonType
}
return &(*u )(unsafe .Pointer (t )).u
case Interface :
type u struct {
interfaceType
u uncommonType
}
return &(*u )(unsafe .Pointer (t )).u
default :
type u struct {
rtype
u uncommonType
}
return &(*u )(unsafe .Pointer (t )).u
}
}
func (t *rtype ) String () string {
s := t .nameOff (t .str ).name ()
if t .tflag &tflagExtraStar != 0 {
return s [1 :]
}
return s
}
func (t *rtype ) Size () uintptr { return t .size }
func (t *rtype ) Kind () Kind { return Kind (t .kind & kindMask ) }
func (t *rtype ) pointers () bool { return t .ptrdata != 0 }
func (t *rtype ) common () *rtype { return t }
func (t *rtype ) exportedMethods () []method {
ut := t .uncommon ()
if ut == nil {
return nil
}
return ut .exportedMethods ()
}
func (t *rtype ) NumMethod () int {
if t .Kind () == Interface {
tt := (*interfaceType )(unsafe .Pointer (t ))
return tt .NumMethod ()
}
return len (t .exportedMethods ())
}
func (t *rtype ) PkgPath () string {
if t .tflag &tflagNamed == 0 {
return ""
}
ut := t .uncommon ()
if ut == nil {
return ""
}
return t .nameOff (ut .pkgPath ).name ()
}
func (t *rtype ) hasName () bool {
return t .tflag &tflagNamed != 0
}
func (t *rtype ) Name () string {
if !t .hasName () {
return ""
}
s := t .String ()
i := len (s ) - 1
for i >= 0 && s [i ] != '.' {
i --
}
return s [i +1 :]
}
func (t *rtype ) chanDir () chanDir {
if t .Kind () != Chan {
panic ("reflect: chanDir of non-chan type" )
}
tt := (*chanType )(unsafe .Pointer (t ))
return chanDir (tt .dir )
}
func (t *rtype ) Elem () Type {
switch t .Kind () {
case Array :
tt := (*arrayType )(unsafe .Pointer (t ))
return toType (tt .elem )
case Chan :
tt := (*chanType )(unsafe .Pointer (t ))
return toType (tt .elem )
case Map :
tt := (*mapType )(unsafe .Pointer (t ))
return toType (tt .elem )
case Ptr :
tt := (*ptrType )(unsafe .Pointer (t ))
return toType (tt .elem )
case Slice :
tt := (*sliceType )(unsafe .Pointer (t ))
return toType (tt .elem )
}
panic ("reflect: Elem of invalid type" )
}
func (t *rtype ) In (i int ) Type {
if t .Kind () != Func {
panic ("reflect: In of non-func type" )
}
tt := (*funcType )(unsafe .Pointer (t ))
return toType (tt .in ()[i ])
}
func (t *rtype ) Key () Type {
if t .Kind () != Map {
panic ("reflect: Key of non-map type" )
}
tt := (*mapType )(unsafe .Pointer (t ))
return toType (tt .key )
}
func (t *rtype ) Len () int {
if t .Kind () != Array {
panic ("reflect: Len of non-array type" )
}
tt := (*arrayType )(unsafe .Pointer (t ))
return int (tt .len )
}
func (t *rtype ) NumField () int {
if t .Kind () != Struct {
panic ("reflect: NumField of non-struct type" )
}
tt := (*structType )(unsafe .Pointer (t ))
return len (tt .fields )
}
func (t *rtype ) NumIn () int {
if t .Kind () != Func {
panic ("reflect: NumIn of non-func type" )
}
tt := (*funcType )(unsafe .Pointer (t ))
return int (tt .inCount )
}
func (t *rtype ) NumOut () int {
if t .Kind () != Func {
panic ("reflect: NumOut of non-func type" )
}
tt := (*funcType )(unsafe .Pointer (t ))
return len (tt .out ())
}
func (t *rtype ) Out (i int ) Type {
if t .Kind () != Func {
panic ("reflect: Out of non-func type" )
}
tt := (*funcType )(unsafe .Pointer (t ))
return toType (tt .out ()[i ])
}
func (t *funcType ) in () []*rtype {
uadd := unsafe .Sizeof (*t )
if t .tflag &tflagUncommon != 0 {
uadd += unsafe .Sizeof (uncommonType {})
}
if t .inCount == 0 {
return nil
}
return (*[1 << 20 ]*rtype )(add (unsafe .Pointer (t ), uadd , "t.inCount > 0" ))[:t .inCount :t .inCount ]
}
func (t *funcType ) out () []*rtype {
uadd := unsafe .Sizeof (*t )
if t .tflag &tflagUncommon != 0 {
uadd += unsafe .Sizeof (uncommonType {})
}
outCount := t .outCount & (1 <<15 - 1 )
if outCount == 0 {
return nil
}
return (*[1 << 20 ]*rtype )(add (unsafe .Pointer (t ), uadd , "outCount > 0" ))[t .inCount : t .inCount +outCount : t .inCount +outCount ]
}
func add (p unsafe .Pointer , x uintptr , whySafe string ) unsafe .Pointer {
return unsafe .Pointer (uintptr (p ) + x )
}
func (t *interfaceType ) NumMethod () int { return len (t .methods ) }
func TypeOf (i any ) Type {
eface := *(*emptyInterface )(unsafe .Pointer (&i ))
return toType (eface .typ )
}
func (t *rtype ) Implements (u Type ) bool {
if u == nil {
panic ("reflect: nil type passed to Type.Implements" )
}
if u .Kind () != Interface {
panic ("reflect: non-interface type passed to Type.Implements" )
}
return implements (u .(*rtype ), t )
}
func (t *rtype ) AssignableTo (u Type ) bool {
if u == nil {
panic ("reflect: nil type passed to Type.AssignableTo" )
}
uu := u .(*rtype )
return directlyAssignable (uu , t ) || implements (uu , t )
}
func (t *rtype ) Comparable () bool {
return t .equal != nil
}
func implements (T , V *rtype ) bool {
if T .Kind () != Interface {
return false
}
t := (*interfaceType )(unsafe .Pointer (T ))
if len (t .methods ) == 0 {
return true
}
if V .Kind () == Interface {
v := (*interfaceType )(unsafe .Pointer (V ))
i := 0
for j := 0 ; j < len (v .methods ); j ++ {
tm := &t .methods [i ]
tmName := t .nameOff (tm .name )
vm := &v .methods [j ]
vmName := V .nameOff (vm .name )
if vmName .name () == tmName .name () && V .typeOff (vm .typ ) == t .typeOff (tm .typ ) {
if !tmName .isExported () {
tmPkgPath := tmName .pkgPath ()
if tmPkgPath == "" {
tmPkgPath = t .pkgPath .name ()
}
vmPkgPath := vmName .pkgPath ()
if vmPkgPath == "" {
vmPkgPath = v .pkgPath .name ()
}
if tmPkgPath != vmPkgPath {
continue
}
}
if i ++; i >= len (t .methods ) {
return true
}
}
}
return false
}
v := V .uncommon ()
if v == nil {
return false
}
i := 0
vmethods := v .methods ()
for j := 0 ; j < int (v .mcount ); j ++ {
tm := &t .methods [i ]
tmName := t .nameOff (tm .name )
vm := vmethods [j ]
vmName := V .nameOff (vm .name )
if vmName .name () == tmName .name () && V .typeOff (vm .mtyp ) == t .typeOff (tm .typ ) {
if !tmName .isExported () {
tmPkgPath := tmName .pkgPath ()
if tmPkgPath == "" {
tmPkgPath = t .pkgPath .name ()
}
vmPkgPath := vmName .pkgPath ()
if vmPkgPath == "" {
vmPkgPath = V .nameOff (v .pkgPath ).name ()
}
if tmPkgPath != vmPkgPath {
continue
}
}
if i ++; i >= len (t .methods ) {
return true
}
}
}
return false
}
func directlyAssignable (T , V *rtype ) bool {
if T == V {
return true
}
if T .hasName () && V .hasName () || T .Kind () != V .Kind () {
return false
}
return haveIdenticalUnderlyingType (T , V , true )
}
func haveIdenticalType (T , V Type , cmpTags bool ) bool {
if cmpTags {
return T == V
}
if T .Name () != V .Name () || T .Kind () != V .Kind () {
return false
}
return haveIdenticalUnderlyingType (T .common (), V .common (), false )
}
func haveIdenticalUnderlyingType (T , V *rtype , cmpTags bool ) bool {
if T == V {
return true
}
kind := T .Kind ()
if kind != V .Kind () {
return false
}
if Bool <= kind && kind <= Complex128 || kind == String || kind == UnsafePointer {
return true
}
switch kind {
case Array :
return T .Len () == V .Len () && haveIdenticalType (T .Elem (), V .Elem (), cmpTags )
case Chan :
if V .chanDir () == bothDir && haveIdenticalType (T .Elem (), V .Elem (), cmpTags ) {
return true
}
return V .chanDir () == T .chanDir () && haveIdenticalType (T .Elem (), V .Elem (), cmpTags )
case Func :
t := (*funcType )(unsafe .Pointer (T ))
v := (*funcType )(unsafe .Pointer (V ))
if t .outCount != v .outCount || t .inCount != v .inCount {
return false
}
for i := 0 ; i < t .NumIn (); i ++ {
if !haveIdenticalType (t .In (i ), v .In (i ), cmpTags ) {
return false
}
}
for i := 0 ; i < t .NumOut (); i ++ {
if !haveIdenticalType (t .Out (i ), v .Out (i ), cmpTags ) {
return false
}
}
return true
case Interface :
t := (*interfaceType )(unsafe .Pointer (T ))
v := (*interfaceType )(unsafe .Pointer (V ))
if len (t .methods ) == 0 && len (v .methods ) == 0 {
return true
}
return false
case Map :
return haveIdenticalType (T .Key (), V .Key (), cmpTags ) && haveIdenticalType (T .Elem (), V .Elem (), cmpTags )
case Ptr , Slice :
return haveIdenticalType (T .Elem (), V .Elem (), cmpTags )
case Struct :
t := (*structType )(unsafe .Pointer (T ))
v := (*structType )(unsafe .Pointer (V ))
if len (t .fields ) != len (v .fields ) {
return false
}
if t .pkgPath .name () != v .pkgPath .name () {
return false
}
for i := range t .fields {
tf := &t .fields [i ]
vf := &v .fields [i ]
if tf .name .name () != vf .name .name () {
return false
}
if !haveIdenticalType (tf .typ , vf .typ , cmpTags ) {
return false
}
if cmpTags && tf .name .tag () != vf .name .tag () {
return false
}
if tf .offsetEmbed != vf .offsetEmbed {
return false
}
}
return true
}
return false
}
type structTypeUncommon struct {
structType
u uncommonType
}
func toType (t *rtype ) Type {
if t == nil {
return nil
}
return t
}
func ifaceIndir (t *rtype ) bool {
return t .kind &kindDirectIface == 0
}