package reflect2

import (
	
	
	
	
)

type Type interface {
	Kind() reflect.Kind
	// New return pointer to data of this type
	New() interface{}
	// UnsafeNew return the allocated space pointed by unsafe.Pointer
	UnsafeNew() unsafe.Pointer
	// PackEFace cast a unsafe pointer to object represented pointer
	PackEFace(ptr unsafe.Pointer) interface{}
	// Indirect dereference object represented pointer to this type
	Indirect(obj interface{}) interface{}
	// UnsafeIndirect dereference pointer to this type
	UnsafeIndirect(ptr unsafe.Pointer) interface{}
	// Type1 returns reflect.Type
	Type1() reflect.Type
	Implements(thatType Type) bool
	String() string
	RType() uintptr
	// interface{} of this type has pointer like behavior
	LikePtr() bool
	IsNullable() bool
	IsNil(obj interface{}) bool
	UnsafeIsNil(ptr unsafe.Pointer) bool
	Set(obj interface{}, val interface{})
	UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer)
	AssignableTo(anotherType Type) bool
}

type ListType interface {
	Type
	Elem() Type
	SetIndex(obj interface{}, index int, elem interface{})
	UnsafeSetIndex(obj unsafe.Pointer, index int, elem unsafe.Pointer)
	GetIndex(obj interface{}, index int) interface{}
	UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer
}

type ArrayType interface {
	ListType
	Len() int
}

type SliceType interface {
	ListType
	MakeSlice(length int, cap int) interface{}
	UnsafeMakeSlice(length int, cap int) unsafe.Pointer
	Grow(obj interface{}, newLength int)
	UnsafeGrow(ptr unsafe.Pointer, newLength int)
	Append(obj interface{}, elem interface{})
	UnsafeAppend(obj unsafe.Pointer, elem unsafe.Pointer)
	LengthOf(obj interface{}) int
	UnsafeLengthOf(ptr unsafe.Pointer) int
	SetNil(obj interface{})
	UnsafeSetNil(ptr unsafe.Pointer)
	Cap(obj interface{}) int
	UnsafeCap(ptr unsafe.Pointer) int
}

type StructType interface {
	Type
	NumField() int
	Field(i int) StructField
	FieldByName(name string) StructField
	FieldByIndex(index []int) StructField
	FieldByNameFunc(match func(string) bool) StructField
}

type StructField interface {
	Offset() uintptr
	Name() string
	PkgPath() string
	Type() Type
	Tag() reflect.StructTag
	Index() []int
	Anonymous() bool
	Set(obj interface{}, value interface{})
	UnsafeSet(obj unsafe.Pointer, value unsafe.Pointer)
	Get(obj interface{}) interface{}
	UnsafeGet(obj unsafe.Pointer) unsafe.Pointer
}

type MapType interface {
	Type
	Key() Type
	Elem() Type
	MakeMap(cap int) interface{}
	UnsafeMakeMap(cap int) unsafe.Pointer
	SetIndex(obj interface{}, key interface{}, elem interface{})
	UnsafeSetIndex(obj unsafe.Pointer, key unsafe.Pointer, elem unsafe.Pointer)
	TryGetIndex(obj interface{}, key interface{}) (interface{}, bool)
	GetIndex(obj interface{}, key interface{}) interface{}
	UnsafeGetIndex(obj unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer
	Iterate(obj interface{}) MapIterator
	UnsafeIterate(obj unsafe.Pointer) MapIterator
}

type MapIterator interface {
	HasNext() bool
	Next() (key interface{}, elem interface{})
	UnsafeNext() (key unsafe.Pointer, elem unsafe.Pointer)
}

type PtrType interface {
	Type
	Elem() Type
}

type InterfaceType interface {
	NumMethod() int
}

type Config struct {
	UseSafeImplementation bool
}

type API interface {
	TypeOf(obj interface{}) Type
	Type2(type1 reflect.Type) Type
}

var ConfigUnsafe = Config{UseSafeImplementation: false}.Froze()
var ConfigSafe = Config{UseSafeImplementation: true}.Froze()

type frozenConfig struct {
	useSafeImplementation bool
	cache                 *sync.Map
}

func ( Config) () *frozenConfig {
	return &frozenConfig{
		useSafeImplementation: .UseSafeImplementation,
		cache:                 new(sync.Map),
	}
}

func ( *frozenConfig) ( interface{}) Type {
	 := uintptr(unpackEFace().rtype)
	,  := .cache.Load()
	if  {
		return .(Type)
	}
	return .Type2(reflect.TypeOf())
}

func ( *frozenConfig) ( reflect.Type) Type {
	if  == nil {
		return nil
	}
	 := uintptr(unpackEFace().data)
	,  := .cache.Load()
	if  {
		return .(Type)
	}
	 := .wrapType()
	.cache.Store(, )
	return 
}

func ( *frozenConfig) ( reflect.Type) Type {
	 := safeType{Type: , cfg: }
	switch .Kind() {
	case reflect.Struct:
		if .useSafeImplementation {
			return &safeStructType{}
		}
		return newUnsafeStructType(, )
	case reflect.Array:
		if .useSafeImplementation {
			return &safeSliceType{}
		}
		return newUnsafeArrayType(, )
	case reflect.Slice:
		if .useSafeImplementation {
			return &safeSliceType{}
		}
		return newUnsafeSliceType(, )
	case reflect.Map:
		if .useSafeImplementation {
			return &safeMapType{}
		}
		return newUnsafeMapType(, )
	case reflect.Ptr, reflect.Chan, reflect.Func:
		if .useSafeImplementation {
			return &safeMapType{}
		}
		return newUnsafePtrType(, )
	case reflect.Interface:
		if .useSafeImplementation {
			return &safeMapType{}
		}
		if .NumMethod() == 0 {
			return newUnsafeEFaceType(, )
		}
		return newUnsafeIFaceType(, )
	default:
		if .useSafeImplementation {
			return &
		}
		return newUnsafeType(, )
	}
}

func ( interface{}) Type {
	return ConfigUnsafe.TypeOf()
}

func ( interface{}) PtrType {
	return TypeOf().(PtrType)
}

func ( reflect.Type) Type {
	if  == nil {
		return nil
	}
	return ConfigUnsafe.Type2()
}

func ( Type) Type {
	return Type2(reflect.PtrTo(.Type1()))
}

func ( interface{}) unsafe.Pointer {
	return unpackEFace().data
}

func ( interface{}) uintptr {
	return uintptr(unpackEFace().rtype)
}

func ( interface{}) bool {
	if  == nil {
		return true
	}
	return unpackEFace().data == nil
}

func ( reflect.Kind) bool {
	switch  {
	case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func, reflect.Slice, reflect.Interface:
		return true
	}
	return false
}

func likePtrKind( reflect.Kind) bool {
	switch  {
	case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func:
		return true
	}
	return false
}

func likePtrType( reflect.Type) bool {
	if likePtrKind(.Kind()) {
		return true
	}
	if .Kind() == reflect.Struct {
		if .NumField() != 1 {
			return false
		}
		return (.Field(0).Type)
	}
	if .Kind() == reflect.Array {
		if .Len() != 1 {
			return false
		}
		return (.Elem())
	}
	return false
}

// NoEscape hides a pointer from escape analysis.  noescape is
// the identity function but escape analysis doesn't think the
// output depends on the input.  noescape is inlined and currently
// compiles down to zero instructions.
// USE CAREFULLY!
//go:nosplit
func ( unsafe.Pointer) unsafe.Pointer {
	 := uintptr()
	return unsafe.Pointer( ^ 0)
}

func ( string) []byte {
	 := make([]byte, 0)
	 := (*reflect.StringHeader)(unsafe.Pointer(&))
	 := (*reflect.SliceHeader)(unsafe.Pointer(&))
	.Data = .Data
	.Cap = .Len
	.Len = .Len
	runtime.KeepAlive()
	return 
}