// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package abi

import (
	
)

// Type is the runtime representation of a Go type.
//
// Be careful about accessing this type at build time, as the version
// of this type in the compiler/linker may not have the same layout
// as the version in the target binary, due to pointer width
// differences and any experiments. Use cmd/compile/internal/rttype
// or the functions in compiletype.go to access this type instead.
// (TODO: this admonition applies to every type in this package.
// Put it in some shared location?)
type Type struct {
	Size_       uintptr
	PtrBytes    uintptr // number of (prefix) bytes in the type that can contain pointers
	Hash        uint32  // hash of type; avoids computation in hash tables
	TFlag       TFlag   // extra type information flags
	Align_      uint8   // alignment of variable with this type
	FieldAlign_ uint8   // alignment of struct field with this type
	Kind_       uint8   // enumeration for C
	// function for comparing objects of this type
	// (ptr to object A, ptr to object B) -> ==?
	Equal func(unsafe.Pointer, unsafe.Pointer) bool
	// GCData stores the GC type data for the garbage collector.
	// If the KindGCProg bit is set in kind, GCData is a GC program.
	// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
	GCData    *byte
	Str       NameOff // string form
	PtrToThis TypeOff // type for pointer to this type, may be zero
}

// A Kind represents the specific kind of type that a Type represents.
// The zero Kind is not a valid kind.
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 (
	// TODO (khr, drchase) why aren't these in TFlag?  Investigate, fix if possible.
	KindDirectIface = 1 << 5
	KindGCProg      = 1 << 6 // Type.gc points to GC program
	KindMask        = (1 << 5) - 1
)

// TFlag is used by a Type to signal what extra type information is
// available in the memory directly following the Type value.
type TFlag uint8

const (
	// TFlagUncommon means that there is a data with a type, UncommonType,
	// just beyond the shared-per-type common data.  That is, the data
	// for struct types will store their UncommonType at one offset, the
	// data for interface types will store their UncommonType at a different
	// offset.  UncommonType is always accessed via a pointer that is computed
	// using trust-us-we-are-the-implementors pointer arithmetic.
	//
	// For example, if t.Kind() == Struct and t.tflag&TFlagUncommon != 0,
	// then t has UncommonType data and it can be accessed as:
	//
	//	type structTypeUncommon struct {
	//		structType
	//		u UncommonType
	//	}
	//	u := &(*structTypeUncommon)(unsafe.Pointer(t)).u
	TFlagUncommon TFlag = 1 << 0

	// TFlagExtraStar means the name in the str field has an
	// extraneous '*' prefix. This is because for most types T in
	// a program, the type *T also exists and reusing the str data
	// saves binary size.
	TFlagExtraStar TFlag = 1 << 1

	// TFlagNamed means the type has a name.
	TFlagNamed TFlag = 1 << 2

	// TFlagRegularMemory means that equal and hash functions can treat
	// this type as a single region of t.size bytes.
	TFlagRegularMemory TFlag = 1 << 3

	// TFlagUnrolledBitmap marks special types that are unrolled-bitmap
	// versions of types with GC programs.
	// These types need to be deallocated when the underlying object
	// is freed.
	TFlagUnrolledBitmap TFlag = 1 << 4
)

// NameOff is the offset to a name from moduledata.types.  See resolveNameOff in runtime.
type NameOff int32

// TypeOff is the offset to a type from moduledata.types.  See resolveTypeOff in runtime.
type TypeOff int32

// TextOff is an offset from the top of a text section.  See (rtype).textOff in runtime.
type TextOff int32

// String returns the name of k.
func ( Kind) () string {
	if int() < len(kindNames) {
		return kindNames[]
	}
	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",
	Pointer:       "ptr",
	Slice:         "slice",
	String:        "string",
	Struct:        "struct",
	UnsafePointer: "unsafe.Pointer",
}

func ( *Type) () Kind { return Kind(.Kind_ & KindMask) }

func ( *Type) () bool {
	return .TFlag&TFlagNamed != 0
}

func ( *Type) () bool { return .PtrBytes != 0 }

// IfaceIndir reports whether t is stored indirectly in an interface value.
func ( *Type) () bool {
	return .Kind_&KindDirectIface == 0
}

// isDirectIface reports whether t is stored directly in an interface value.
func ( *Type) () bool {
	return .Kind_&KindDirectIface != 0
}

func ( *Type) (,  uintptr) []byte {
	return unsafe.Slice(.GCData, int())[:]
}

// Method on non-interface type
type Method struct {
	Name NameOff // name of method
	Mtyp TypeOff // method type (without receiver)
	Ifn  TextOff // fn used in interface call (one-word receiver)
	Tfn  TextOff // fn used for normal method call
}

// UncommonType is present only for defined types or types with methods
// (if T is a defined type, the uncommonTypes for T and *T have methods).
// Using a pointer to this struct reduces the overall size required
// to describe a non-defined type with no methods.
type UncommonType struct {
	PkgPath NameOff // import path; empty for built-in types like int, string
	Mcount  uint16  // number of methods
	Xcount  uint16  // number of exported methods
	Moff    uint32  // offset from this uncommontype to [mcount]Method
	_       uint32  // unused
}

func ( *UncommonType) () []Method {
	if .Mcount == 0 {
		return nil
	}
	return (*[1 << 16]Method)(addChecked(unsafe.Pointer(), uintptr(.Moff), "t.mcount > 0"))[:.Mcount:.Mcount]
}

func ( *UncommonType) () []Method {
	if .Xcount == 0 {
		return nil
	}
	return (*[1 << 16]Method)(addChecked(unsafe.Pointer(), uintptr(.Moff), "t.xcount > 0"))[:.Xcount:.Xcount]
}

// addChecked returns p+x.
//
// The whySafe string is ignored, so that the function still inlines
// as efficiently as p+x, but all call sites should use the string to
// record why the addition is safe, which is to say why the addition
// does not cause x to advance to the very end of p's allocation
// and therefore point incorrectly at the next block in memory.
func addChecked( unsafe.Pointer,  uintptr,  string) unsafe.Pointer {
	return unsafe.Pointer(uintptr() + )
}

// Imethod represents a method on an interface type
type Imethod struct {
	Name NameOff // name of method
	Typ  TypeOff // .(*FuncType) underneath
}

// ArrayType represents a fixed array type.
type ArrayType struct {
	Type
	Elem  *Type // array element type
	Slice *Type // slice type
	Len   uintptr
}

// Len returns the length of t if t is an array type, otherwise 0
func ( *Type) () int {
	if .Kind() == Array {
		return int((*ArrayType)(unsafe.Pointer()).Len)
	}
	return 0
}

func ( *Type) () *Type {
	return 
}

type ChanDir int

const (
	RecvDir    ChanDir = 1 << iota         // <-chan
	SendDir                                // chan<-
	BothDir            = RecvDir | SendDir // chan
	InvalidDir ChanDir = 0
)

// ChanType represents a channel type
type ChanType struct {
	Type
	Elem *Type
	Dir  ChanDir
}

type structTypeUncommon struct {
	StructType
	u UncommonType
}

// ChanDir returns the direction of t if t is a channel type, otherwise InvalidDir (0).
func ( *Type) () ChanDir {
	if .Kind() == Chan {
		 := (*ChanType)(unsafe.Pointer())
		return .Dir
	}
	return InvalidDir
}

// Uncommon returns a pointer to T's "uncommon" data if there is any, otherwise nil
func ( *Type) () *UncommonType {
	if .TFlag&TFlagUncommon == 0 {
		return nil
	}
	switch .Kind() {
	case Struct:
		return &(*structTypeUncommon)(unsafe.Pointer()).u
	case Pointer:
		type  struct {
			PtrType
			 UncommonType
		}
		return &(*)(unsafe.Pointer()).
	case Func:
		type  struct {
			FuncType
			 UncommonType
		}
		return &(*)(unsafe.Pointer()).
	case Slice:
		type  struct {
			SliceType
			 UncommonType
		}
		return &(*)(unsafe.Pointer()).
	case Array:
		type  struct {
			ArrayType
			 UncommonType
		}
		return &(*)(unsafe.Pointer()).
	case Chan:
		type  struct {
			ChanType
			 UncommonType
		}
		return &(*)(unsafe.Pointer()).
	case Map:
		type  struct {
			MapType
			 UncommonType
		}
		return &(*)(unsafe.Pointer()).
	case Interface:
		type  struct {
			InterfaceType
			 UncommonType
		}
		return &(*)(unsafe.Pointer()).
	default:
		type  struct {
			Type
			 UncommonType
		}
		return &(*)(unsafe.Pointer()).
	}
}

// Elem returns the element type for t if t is an array, channel, map, pointer, or slice, otherwise nil.
func ( *Type) () *Type {
	switch .Kind() {
	case Array:
		 := (*ArrayType)(unsafe.Pointer())
		return .Elem
	case Chan:
		 := (*ChanType)(unsafe.Pointer())
		return .Elem
	case Map:
		 := (*MapType)(unsafe.Pointer())
		return .Elem
	case Pointer:
		 := (*PtrType)(unsafe.Pointer())
		return .Elem
	case Slice:
		 := (*SliceType)(unsafe.Pointer())
		return .Elem
	}
	return nil
}

// StructType returns t cast to a *StructType, or nil if its tag does not match.
func ( *Type) () *StructType {
	if .Kind() != Struct {
		return nil
	}
	return (*StructType)(unsafe.Pointer())
}

// MapType returns t cast to a *MapType, or nil if its tag does not match.
func ( *Type) () *MapType {
	if .Kind() != Map {
		return nil
	}
	return (*MapType)(unsafe.Pointer())
}

// ArrayType returns t cast to a *ArrayType, or nil if its tag does not match.
func ( *Type) () *ArrayType {
	if .Kind() != Array {
		return nil
	}
	return (*ArrayType)(unsafe.Pointer())
}

// FuncType returns t cast to a *FuncType, or nil if its tag does not match.
func ( *Type) () *FuncType {
	if .Kind() != Func {
		return nil
	}
	return (*FuncType)(unsafe.Pointer())
}

// InterfaceType returns t cast to a *InterfaceType, or nil if its tag does not match.
func ( *Type) () *InterfaceType {
	if .Kind() != Interface {
		return nil
	}
	return (*InterfaceType)(unsafe.Pointer())
}

// Size returns the size of data with type t.
func ( *Type) () uintptr { return .Size_ }

// Align returns the alignment of data with type t.
func ( *Type) () int { return int(.Align_) }

func ( *Type) () int { return int(.FieldAlign_) }

type InterfaceType struct {
	Type
	PkgPath Name      // import path
	Methods []Imethod // sorted by hash
}

func ( *Type) () []Method {
	 := .Uncommon()
	if  == nil {
		return nil
	}
	return .ExportedMethods()
}

func ( *Type) () int {
	if .Kind() == Interface {
		 := (*InterfaceType)(unsafe.Pointer())
		return .NumMethod()
	}
	return len(.ExportedMethods())
}

// NumMethod returns the number of interface methods in the type's method set.
func ( *InterfaceType) () int { return len(.Methods) }

type MapType struct {
	Type
	Key    *Type
	Elem   *Type
	Bucket *Type // internal type representing a hash bucket
	// function for hashing keys (ptr to key, seed) -> hash
	Hasher     func(unsafe.Pointer, uintptr) uintptr
	KeySize    uint8  // size of key slot
	ValueSize  uint8  // size of elem slot
	BucketSize uint16 // size of bucket
	Flags      uint32
}

// Note: flag values must match those used in the TMAP case
// in ../cmd/compile/internal/reflectdata/reflect.go:writeType.
func ( *MapType) () bool { // store ptr to key instead of key itself
	return .Flags&1 != 0
}
func ( *MapType) () bool { // store ptr to elem instead of elem itself
	return .Flags&2 != 0
}
func ( *MapType) () bool { // true if k==k for all keys
	return .Flags&4 != 0
}
func ( *MapType) () bool { // true if we need to update key on an overwrite
	return .Flags&8 != 0
}
func ( *MapType) () bool { // true if hash function might panic
	return .Flags&16 != 0
}

func ( *Type) () *Type {
	if .Kind() == Map {
		return (*MapType)(unsafe.Pointer()).Key
	}
	return nil
}

type SliceType struct {
	Type
	Elem *Type // slice element type
}

// funcType represents a function type.
//
// A *Type for each in and out parameter is stored in an array that
// directly follows the funcType (and possibly its uncommonType). So
// a function type with one method, one input, and one output is:
//
//	struct {
//		funcType
//		uncommonType
//		[2]*rtype    // [0] is in, [1] is out
//	}
type FuncType struct {
	Type
	InCount  uint16
	OutCount uint16 // top bit is set if last input parameter is ...
}

func ( *FuncType) ( int) *Type {
	return .InSlice()[]
}

func ( *FuncType) () int {
	return int(.InCount)
}

func ( *FuncType) () int {
	return int(.OutCount & (1<<15 - 1))
}

func ( *FuncType) ( int) *Type {
	return (.OutSlice()[])
}

func ( *FuncType) () []*Type {
	 := unsafe.Sizeof(*)
	if .TFlag&TFlagUncommon != 0 {
		 += unsafe.Sizeof(UncommonType{})
	}
	if .InCount == 0 {
		return nil
	}
	return (*[1 << 16]*Type)(addChecked(unsafe.Pointer(), , "t.inCount > 0"))[:.InCount:.InCount]
}
func ( *FuncType) () []*Type {
	 := uint16(.NumOut())
	if  == 0 {
		return nil
	}
	 := unsafe.Sizeof(*)
	if .TFlag&TFlagUncommon != 0 {
		 += unsafe.Sizeof(UncommonType{})
	}
	return (*[1 << 17]*Type)(addChecked(unsafe.Pointer(), , "outCount > 0"))[.InCount : .InCount+ : .InCount+]
}

func ( *FuncType) () bool {
	return .OutCount&(1<<15) != 0
}

type PtrType struct {
	Type
	Elem *Type // pointer element (pointed at) type
}

type StructField struct {
	Name   Name    // name is always non-empty
	Typ    *Type   // type of field
	Offset uintptr // byte offset of field
}

func ( *StructField) () bool {
	return .Name.IsEmbedded()
}

type StructType struct {
	Type
	PkgPath Name
	Fields  []StructField
}

// Name is an encoded type Name with optional extra data.
//
// The first byte is a bit field containing:
//
//	1<<0 the name is exported
//	1<<1 tag data follows the name
//	1<<2 pkgPath nameOff follows the name and tag
//	1<<3 the name is of an embedded (a.k.a. anonymous) field
//
// Following that, there is a varint-encoded length of the name,
// followed by the name itself.
//
// If tag data is present, it also has a varint-encoded length
// followed by the tag itself.
//
// If the import path follows, then 4 bytes at the end of
// the data form a nameOff. The import path is only set for concrete
// methods that are defined in a different package than their type.
//
// If a name starts with "*", then the exported bit represents
// whether the pointed to type is exported.
//
// Note: this encoding must match here and in:
//   cmd/compile/internal/reflectdata/reflect.go
//   cmd/link/internal/ld/decodesym.go

type Name struct {
	Bytes *byte
}

// DataChecked does pointer arithmetic on n's Bytes, and that arithmetic is asserted to
// be safe for the reason in whySafe (which can appear in a backtrace, etc.)
func ( Name) ( int,  string) *byte {
	return (*byte)(addChecked(unsafe.Pointer(.Bytes), uintptr(), ))
}

// Data does pointer arithmetic on n's Bytes, and that arithmetic is asserted to
// be safe because the runtime made the call (other packages use DataChecked)
func ( Name) ( int) *byte {
	return (*byte)(addChecked(unsafe.Pointer(.Bytes), uintptr(), "the runtime doesn't need to give you a reason"))
}

// IsExported returns "is n exported?"
func ( Name) () bool {
	return (*.Bytes)&(1<<0) != 0
}

// HasTag returns true iff there is tag data following this name
func ( Name) () bool {
	return (*.Bytes)&(1<<1) != 0
}

// IsEmbedded returns true iff n is embedded (an anonymous field).
func ( Name) () bool {
	return (*.Bytes)&(1<<3) != 0
}

// ReadVarint parses a varint as encoded by encoding/binary.
// It returns the number of encoded bytes and the encoded value.
func ( Name) ( int) (int, int) {
	 := 0
	for  := 0; ; ++ {
		 := *.DataChecked(+, "read varint")
		 += int(&0x7f) << (7 * )
		if &0x80 == 0 {
			return  + 1, 
		}
	}
}

// IsBlank indicates whether n is "_".
func ( Name) () bool {
	if .Bytes == nil {
		return false
	}
	,  := .ReadVarint(1)
	return  == 1 && *.Data(2) == '_'
}

// writeVarint writes n to buf in varint form. Returns the
// number of bytes written. n must be nonnegative.
// Writes at most 10 bytes.
func writeVarint( []byte,  int) int {
	for  := 0; ; ++ {
		 := byte( & 0x7f)
		 >>= 7
		if  == 0 {
			[] = 
			return  + 1
		}
		[] =  | 0x80
	}
}

// Name returns the tag string for n, or empty if there is none.
func ( Name) () string {
	if .Bytes == nil {
		return ""
	}
	,  := .ReadVarint(1)
	return unsafe.String(.DataChecked(1+, "non-empty string"), )
}

// Tag returns the tag string for n, or empty if there is none.
func ( Name) () string {
	if !.HasTag() {
		return ""
	}
	,  := .ReadVarint(1)
	,  := .ReadVarint(1 +  + )
	return unsafe.String(.DataChecked(1+++, "non-empty string"), )
}

func (,  string, ,  bool) Name {
	if len() >= 1<<29 {
		panic("abi.NewName: name too long: " + [:1024] + "...")
	}
	if len() >= 1<<29 {
		panic("abi.NewName: tag too long: " + [:1024] + "...")
	}
	var  [10]byte
	var  [10]byte
	 := writeVarint([:], len())
	 := writeVarint([:], len())

	var  byte
	 := 1 +  + len()
	if  {
		 |= 1 << 0
	}
	if len() > 0 {
		 +=  + len()
		 |= 1 << 1
	}
	if  {
		 |= 1 << 3
	}

	 := make([]byte, )
	[0] = 
	copy([1:], [:])
	copy([1+:], )
	if len() > 0 {
		 := [1++len():]
		copy(, [:])
		copy([:], )
	}

	return Name{Bytes: &[0]}
}