Selaa lähdekoodia

import from plz

Tao Wen 7 vuotta sitten
vanhempi
commit
3fc4794c80
56 muutettua tiedostoa jossa 2798 lisäystä ja 0 poistoa
  1. 8 0
      go_above_17.go
  2. 14 0
      go_above_19.go
  3. 9 0
      go_below_17.go
  4. 14 0
      go_below_19.go
  5. 282 0
      reflect2.go
  6. 0 0
      reflect2_amd64.s
  7. 30 0
      reflect2_kind.go
  8. 0 0
      relfect2_386.s
  9. 0 0
      relfect2_amd64p32.s
  10. 0 0
      relfect2_arm.s
  11. 0 0
      relfect2_arm64.s
  12. 0 0
      relfect2_mips64x.s
  13. 0 0
      relfect2_mipsx.s
  14. 0 0
      relfect2_ppc64x.s
  15. 0 0
      relfect2_s390x.s
  16. 58 0
      safe_field.go
  17. 101 0
      safe_map.go
  18. 92 0
      safe_slice.go
  19. 13 0
      safe_struct.go
  20. 78 0
      safe_type.go
  21. 38 0
      test/array_test.go
  22. 41 0
      test/int_test.go
  23. 44 0
      test/map_elem_array_test.go
  24. 34 0
      test/map_elem_bytes_test.go
  25. 50 0
      test/map_elem_eface_test.go
  26. 23 0
      test/map_elem_map_test.go
  27. 57 0
      test/map_elem_struct_test.go
  28. 43 0
      test/map_key_eface_test.go
  29. 47 0
      test/map_key_iface_test.go
  30. 50 0
      test/map_key_ptr_test.go
  31. 120 0
      test/map_test.go
  32. 17 0
      test/op_test.go
  33. 37 0
      test/slice_array_test.go
  34. 16 0
      test/slice_bytes_test.go
  35. 77 0
      test/slice_eface_test.go
  36. 80 0
      test/slice_iface_test.go
  37. 43 0
      test/slice_map_test.go
  38. 57 0
      test/slice_ptr_test.go
  39. 16 0
      test/slice_string_test.go
  40. 53 0
      test/slice_struct_test.go
  41. 114 0
      test/slice_test.go
  42. 28 0
      test/struct_eface_test.go
  43. 24 0
      test/struct_ptr_test.go
  44. 63 0
      test/struct_test.go
  45. 18 0
      test15/map_test.go
  46. 72 0
      type_map.go
  47. 65 0
      unsafe_array.go
  48. 59 0
      unsafe_eface.go
  49. 74 0
      unsafe_field.go
  50. 64 0
      unsafe_iface.go
  51. 70 0
      unsafe_link.go
  52. 138 0
      unsafe_map.go
  53. 46 0
      unsafe_ptr.go
  54. 177 0
      unsafe_slice.go
  55. 59 0
      unsafe_struct.go
  56. 85 0
      unsafe_type.go

+ 8 - 0
go_above_17.go

@@ -0,0 +1,8 @@
+//+build go1.7
+
+package reflect2
+
+import "unsafe"
+
+//go:linkname resolveTypeOff reflect.resolveTypeOff
+func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer

+ 14 - 0
go_above_19.go

@@ -0,0 +1,14 @@
+//+build go1.9
+
+package reflect2
+
+import (
+	"unsafe"
+)
+
+//go:linkname makemap reflect.makemap
+func makemap(rtype unsafe.Pointer, cap int) (m unsafe.Pointer)
+
+func makeMapWithSize(rtype unsafe.Pointer, cap int) unsafe.Pointer {
+	return makemap(rtype, cap)
+}

+ 9 - 0
go_below_17.go

@@ -0,0 +1,9 @@
+//+build !go1.7
+
+package reflect2
+
+import "unsafe"
+
+func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer {
+	return nil
+}

+ 14 - 0
go_below_19.go

@@ -0,0 +1,14 @@
+//+build !go1.9
+
+package reflect2
+
+import (
+	"unsafe"
+)
+
+//go:linkname makemap reflect.makemap
+func makemap(rtype unsafe.Pointer) (m unsafe.Pointer)
+
+func makeMapWithSize(rtype unsafe.Pointer, cap int) unsafe.Pointer {
+	return makemap(rtype)
+}

+ 282 - 0
reflect2.go

@@ -0,0 +1,282 @@
+package reflect2
+
+import (
+	"reflect"
+	"unsafe"
+	"github.com/v2pro/plz/concurrent"
+)
+
+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                 *concurrent.Map
+}
+
+func (cfg Config) Froze() *frozenConfig {
+	return &frozenConfig{
+		useSafeImplementation: cfg.UseSafeImplementation,
+		cache:                 concurrent.NewMap(),
+	}
+}
+
+func (cfg *frozenConfig) TypeOf(obj interface{}) Type {
+	cacheKey := uintptr(unpackEFace(obj).rtype)
+	typeObj, found := cfg.cache.Load(cacheKey)
+	if found {
+		return typeObj.(Type)
+	}
+	return cfg.Type2(reflect.TypeOf(obj))
+}
+
+func (cfg *frozenConfig) Type2(type1 reflect.Type) Type {
+	cacheKey := uintptr(unpackEFace(type1).data)
+	typeObj, found := cfg.cache.Load(cacheKey)
+	if found {
+		return typeObj.(Type)
+	}
+	type2 := cfg.wrapType(type1)
+	cfg.cache.Store(cacheKey, type2)
+	return type2
+}
+
+func (cfg *frozenConfig) wrapType(type1 reflect.Type) Type {
+	safeType := safeType{Type: type1, cfg: cfg}
+	switch type1.Kind() {
+	case reflect.Struct:
+		if cfg.useSafeImplementation {
+			return &safeStructType{safeType}
+		}
+		return newUnsafeStructType(cfg, type1)
+	case reflect.Array:
+		if cfg.useSafeImplementation {
+			return &safeSliceType{safeType}
+		}
+		return newUnsafeArrayType(cfg, type1)
+	case reflect.Slice:
+		if cfg.useSafeImplementation {
+			return &safeSliceType{safeType}
+		}
+		return newUnsafeSliceType(cfg, type1)
+	case reflect.Map:
+		if cfg.useSafeImplementation {
+			return &safeMapType{safeType}
+		}
+		return newUnsafeMapType(cfg, type1)
+	case reflect.Ptr, reflect.Chan, reflect.Func:
+		if cfg.useSafeImplementation {
+			return &safeMapType{safeType}
+		}
+		return newUnsafePtrType(cfg, type1)
+	case reflect.Interface:
+		if cfg.useSafeImplementation {
+			return &safeMapType{safeType}
+		}
+		if type1.NumMethod() == 0 {
+			return newUnsafeEFaceType(cfg, type1)
+		}
+		return newUnsafeIFaceType(cfg, type1)
+	default:
+		if cfg.useSafeImplementation {
+			return &safeType
+		}
+		return newUnsafeType(cfg, type1)
+	}
+}
+
+func TypeOf(obj interface{}) Type {
+	return ConfigUnsafe.TypeOf(obj)
+}
+
+func TypeOfPtr(obj interface{}) PtrType {
+	return TypeOf(obj).(PtrType)
+}
+
+func Type2(type1 reflect.Type) Type {
+	return ConfigUnsafe.Type2(type1)
+}
+
+func PtrTo(typ Type) Type {
+	return Type2(reflect.PtrTo(typ.Type1()))
+}
+
+func PtrOf(obj interface{}) unsafe.Pointer {
+	return unpackEFace(obj).data
+}
+
+func RTypeOf(obj interface{}) uintptr {
+	return uintptr(unpackEFace(obj).rtype)
+}
+
+func IsNil(obj interface{}) bool {
+	if obj == nil {
+		return true
+	}
+	return unpackEFace(obj).data == nil
+}
+
+func IsNullable(kind reflect.Kind) bool {
+	switch kind {
+	case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func, reflect.Slice, reflect.Interface:
+		return true
+	}
+	return false
+}
+
+func likePtrKind(kind reflect.Kind) bool {
+	switch kind {
+	case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func:
+		return true
+	}
+	return false
+}
+
+func likePtrType(typ reflect.Type) bool {
+	if likePtrKind(typ.Kind()) {
+		return true
+	}
+	if typ.Kind() == reflect.Struct {
+		if typ.NumField() != 1 {
+			return false
+		}
+		return likePtrType(typ.Field(0).Type)
+	}
+	if typ.Kind() == reflect.Array {
+		if typ.Len() != 1 {
+			return false
+		}
+		return likePtrType(typ.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 NoEscape(p unsafe.Pointer) unsafe.Pointer {
+	x := uintptr(p)
+	return unsafe.Pointer(x ^ 0)
+}

+ 0 - 0
reflect2_amd64.s


+ 30 - 0
reflect2_kind.go

@@ -0,0 +1,30 @@
+package reflect2
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+// DefaultTypeOfKind return the non aliased default type for the kind
+func DefaultTypeOfKind(kind reflect.Kind) Type {
+	return kindTypes[kind]
+}
+
+var kindTypes = map[reflect.Kind]Type{
+	reflect.Bool: TypeOf(true),
+	reflect.Uint8: TypeOf(uint8(0)),
+	reflect.Int8: TypeOf(int8(0)),
+	reflect.Uint16: TypeOf(uint16(0)),
+	reflect.Int16: TypeOf(int16(0)),
+	reflect.Uint32: TypeOf(uint32(0)),
+	reflect.Int32: TypeOf(int32(0)),
+	reflect.Uint64: TypeOf(uint64(0)),
+	reflect.Int64: TypeOf(int64(0)),
+	reflect.Uint: TypeOf(uint(0)),
+	reflect.Int: TypeOf(int(0)),
+	reflect.Float32: TypeOf(float32(0)),
+	reflect.Float64: TypeOf(float64(0)),
+	reflect.Uintptr: TypeOf(uintptr(0)),
+	reflect.String: TypeOf(""),
+	reflect.UnsafePointer: TypeOf(unsafe.Pointer(nil)),
+}

+ 0 - 0
relfect2_386.s


+ 0 - 0
relfect2_amd64p32.s


+ 0 - 0
relfect2_arm.s


+ 0 - 0
relfect2_arm64.s


+ 0 - 0
relfect2_mips64x.s


+ 0 - 0
relfect2_mipsx.s


+ 0 - 0
relfect2_ppc64x.s


+ 0 - 0
relfect2_s390x.s


+ 58 - 0
safe_field.go

@@ -0,0 +1,58 @@
+package reflect2
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+type safeField struct {
+	reflect.StructField
+}
+
+func (field *safeField) Offset() uintptr {
+	return field.StructField.Offset
+}
+
+func (field *safeField) Name() string {
+	return field.StructField.Name
+}
+
+func (field *safeField) PkgPath() string {
+	return field.StructField.PkgPath
+}
+
+func (field *safeField) Type() Type {
+	panic("not implemented")
+}
+
+func (field *safeField) Tag() reflect.StructTag {
+	return field.StructField.Tag
+}
+
+func (field *safeField) Index() []int {
+	return field.StructField.Index
+}
+
+func (field *safeField) Anonymous() bool {
+	return field.StructField.Anonymous
+}
+
+func (field *safeField) Set(obj interface{}, value interface{}) {
+	val := reflect.ValueOf(obj).Elem()
+	val.FieldByIndex(field.Index()).Set(reflect.ValueOf(value).Elem())
+}
+
+func (field *safeField) UnsafeSet(obj unsafe.Pointer, value unsafe.Pointer) {
+	panic("unsafe operation is not supported")
+}
+
+func (field *safeField) Get(obj interface{}) interface{} {
+	val := reflect.ValueOf(obj).Elem().FieldByIndex(field.Index())
+	ptr := reflect.New(val.Type())
+	ptr.Elem().Set(val)
+	return ptr.Interface()
+}
+
+func (field *safeField) UnsafeGet(obj unsafe.Pointer) unsafe.Pointer {
+	panic("does not support unsafe operation")
+}

+ 101 - 0
safe_map.go

@@ -0,0 +1,101 @@
+package reflect2
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+type safeMapType struct {
+	safeType
+}
+
+func (type2 *safeMapType) Key() Type {
+	return type2.safeType.cfg.Type2(type2.Type.Key())
+}
+
+func (type2 *safeMapType) MakeMap(cap int) interface{} {
+	ptr := reflect.New(type2.Type)
+	ptr.Elem().Set(reflect.MakeMap(type2.Type))
+	return ptr.Interface()
+}
+
+func (type2 *safeMapType) UnsafeMakeMap(cap int) unsafe.Pointer {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeMapType) SetIndex(obj interface{}, key interface{}, elem interface{}) {
+	keyVal := reflect.ValueOf(key)
+	elemVal := reflect.ValueOf(elem)
+	val := reflect.ValueOf(obj)
+	val.Elem().SetMapIndex(keyVal.Elem(), elemVal.Elem())
+}
+
+func (type2 *safeMapType) UnsafeSetIndex(obj unsafe.Pointer, key unsafe.Pointer, elem unsafe.Pointer) {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeMapType) TryGetIndex(obj interface{}, key interface{}) (interface{}, bool) {
+	keyVal := reflect.ValueOf(key)
+	if key == nil {
+		keyVal = reflect.New(type2.Type.Key()).Elem()
+	}
+	val := reflect.ValueOf(obj).MapIndex(keyVal)
+	if !val.IsValid() {
+		return nil, false
+	}
+	return val.Interface(), true
+}
+
+func (type2 *safeMapType) GetIndex(obj interface{}, key interface{}) interface{} {
+	val := reflect.ValueOf(obj).Elem()
+	keyVal := reflect.ValueOf(key).Elem()
+	elemVal := val.MapIndex(keyVal)
+	if !elemVal.IsValid() {
+		ptr := reflect.New(reflect.PtrTo(val.Type().Elem()))
+		return ptr.Elem().Interface()
+	}
+	ptr := reflect.New(elemVal.Type())
+	ptr.Elem().Set(elemVal)
+	return ptr.Interface()
+}
+
+func (type2 *safeMapType) UnsafeGetIndex(obj unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeMapType) Iterate(obj interface{}) MapIterator {
+	m := reflect.ValueOf(obj).Elem()
+	return &safeMapIterator{
+		m:    m,
+		keys: m.MapKeys(),
+	}
+}
+
+func (type2 *safeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator {
+	panic("does not support unsafe operation")
+}
+
+type safeMapIterator struct {
+	i int
+	m reflect.Value
+	keys []reflect.Value
+}
+
+func (iter *safeMapIterator) HasNext() bool {
+	return iter.i != len(iter.keys)
+}
+
+func (iter *safeMapIterator) Next() (interface{}, interface{}) {
+	key := iter.keys[iter.i]
+	elem := iter.m.MapIndex(key)
+	iter.i += 1
+	keyPtr := reflect.New(key.Type())
+	keyPtr.Elem().Set(key)
+	elemPtr := reflect.New(elem.Type())
+	elemPtr.Elem().Set(elem)
+	return keyPtr.Interface(), elemPtr.Interface()
+}
+
+func (iter *safeMapIterator) UnsafeNext() (unsafe.Pointer, unsafe.Pointer) {
+	panic("does not support unsafe operation")
+}

+ 92 - 0
safe_slice.go

@@ -0,0 +1,92 @@
+package reflect2
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+type safeSliceType struct {
+	safeType
+}
+
+func (type2 *safeSliceType) SetIndex(obj interface{}, index int, value interface{}) {
+	val := reflect.ValueOf(obj).Elem()
+	elem := reflect.ValueOf(value).Elem()
+	val.Index(index).Set(elem)
+}
+
+func (type2 *safeSliceType) UnsafeSetIndex(obj unsafe.Pointer, index int, value unsafe.Pointer) {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeSliceType) GetIndex(obj interface{}, index int) interface{} {
+	val := reflect.ValueOf(obj).Elem()
+	elem := val.Index(index)
+	ptr := reflect.New(elem.Type())
+	ptr.Elem().Set(elem)
+	return ptr.Interface()
+}
+
+func (type2 *safeSliceType) UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeSliceType) MakeSlice(length int, cap int) interface{} {
+	val := reflect.MakeSlice(type2.Type, length, cap)
+	ptr := reflect.New(val.Type())
+	ptr.Elem().Set(val)
+	return ptr.Interface()
+}
+
+func (type2 *safeSliceType) UnsafeMakeSlice(length int, cap int) unsafe.Pointer {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeSliceType) Grow(obj interface{}, newLength int) {
+	oldCap := type2.Cap(obj)
+	oldSlice := reflect.ValueOf(obj).Elem()
+	delta := newLength - oldCap
+	deltaVals := make([]reflect.Value, delta)
+	newSlice := reflect.Append(oldSlice, deltaVals...)
+	oldSlice.Set(newSlice)
+}
+
+func (type2 *safeSliceType) UnsafeGrow(ptr unsafe.Pointer, newLength int) {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeSliceType) Append(obj interface{}, elem interface{}) {
+	val := reflect.ValueOf(obj).Elem()
+	elemVal := reflect.ValueOf(elem).Elem()
+	newVal := reflect.Append(val, elemVal)
+	val.Set(newVal)
+}
+
+func (type2 *safeSliceType) UnsafeAppend(obj unsafe.Pointer, elem unsafe.Pointer) {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeSliceType) SetNil(obj interface{}) {
+	val := reflect.ValueOf(obj).Elem()
+	val.Set(reflect.Zero(val.Type()))
+}
+
+func (type2 *safeSliceType) UnsafeSetNil(ptr unsafe.Pointer) {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeSliceType) LengthOf(obj interface{}) int {
+	return reflect.ValueOf(obj).Elem().Len()
+}
+
+func (type2 *safeSliceType) UnsafeLengthOf(ptr unsafe.Pointer) int {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeSliceType) Cap(obj interface{}) int {
+	return reflect.ValueOf(obj).Elem().Cap()
+}
+
+func (type2 *safeSliceType) UnsafeCap(ptr unsafe.Pointer) int {
+	panic("does not support unsafe operation")
+}

+ 13 - 0
safe_struct.go

@@ -0,0 +1,13 @@
+package reflect2
+
+type safeStructType struct {
+	safeType
+}
+
+func (type2 *safeStructType) FieldByName(name string) StructField {
+	field, found := type2.Type.FieldByName(name)
+	if !found {
+		panic("field " + name + " not found")
+	}
+	return &safeField{StructField: field}
+}

+ 78 - 0
safe_type.go

@@ -0,0 +1,78 @@
+package reflect2
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+type safeType struct {
+	reflect.Type
+	cfg *frozenConfig
+}
+
+func (type2 *safeType) New() interface{} {
+	return reflect.New(type2.Type).Interface()
+}
+
+func (type2 *safeType) UnsafeNew() unsafe.Pointer {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeType) Elem() Type {
+	return type2.cfg.Type2(type2.Type.Elem())
+}
+
+func (type2 *safeType) Type1() reflect.Type {
+	return type2.Type
+}
+
+func (type2 *safeType) PackEFace(ptr unsafe.Pointer) interface{} {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeType) Implements(thatType Type) bool {
+	return type2.Type.Implements(thatType.Type1())
+}
+
+func (type2 *safeType) RType() uintptr {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeType) Indirect(obj interface{}) interface{} {
+	return reflect.Indirect(reflect.ValueOf(obj)).Interface()
+}
+
+func (type2 *safeType) UnsafeIndirect(ptr unsafe.Pointer) interface{} {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeType) LikePtr() bool {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeType) IsNullable() bool {
+	return IsNullable(type2.Kind())
+}
+
+func (type2 *safeType) IsNil(obj interface{}) bool {
+	if obj == nil {
+		return true
+	}
+	return reflect.ValueOf(obj).Elem().IsNil()
+}
+
+func (type2 *safeType) UnsafeIsNil(ptr unsafe.Pointer) bool {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeType) Set(obj interface{}, val interface{}) {
+	reflect.ValueOf(obj).Elem().Set(reflect.ValueOf(val).Elem())
+}
+
+func (type2 *safeType) UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer) {
+	panic("does not support unsafe operation")
+}
+
+func (type2 *safeType) AssignableTo(anotherType Type) bool {
+	return type2.Type1().AssignableTo(anotherType.Type1())
+}

+ 38 - 0
test/array_test.go

@@ -0,0 +1,38 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+)
+
+func Test_array(t *testing.T) {
+	var pInt = func(val int) *int {
+		return &val
+	}
+	t.Run("New", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf([2]int{})
+		obj := valType.New()
+		(*(obj.(*[2]int)))[0] = 100
+		(*(obj.(*[2]int)))[1] = 200
+		return obj
+	}))
+	t.Run("Indirect", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf([2]int{})
+		return valType.Indirect(&[2]int{})
+	}))
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := [2]int{}
+		valType := api.TypeOf(obj).(reflect2.ArrayType)
+		valType.SetIndex(&obj, 0, pInt(100))
+		valType.SetIndex(&obj, 1, pInt(200))
+		return obj
+	}))
+	t.Run("GetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := [2]int{1, 2}
+		valType := api.TypeOf(obj).(reflect2.ArrayType)
+		return []interface{} {
+			valType.GetIndex(&obj, 0),
+			valType.GetIndex(&obj, 1),
+		}
+	}))
+}

+ 41 - 0
test/int_test.go

@@ -0,0 +1,41 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+	"github.com/v2pro/plz/test"
+	"github.com/v2pro/plz/countlog"
+	"unsafe"
+	"github.com/v2pro/plz/test/must"
+)
+
+func Test_int(t *testing.T) {
+	t.Run("New", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf(1)
+		obj := valType.New()
+		*obj.(*int) = 100
+		return obj
+	}))
+	t.Run("PackEFace", test.Case(func(ctx *countlog.Context) {
+		valType := reflect2.TypeOf(1)
+		hundred := 100
+		must.Equal(&hundred, valType.PackEFace(unsafe.Pointer(&hundred)))
+	}))
+	t.Run("Indirect", test.Case(func(ctx *countlog.Context) {
+		valType := reflect2.TypeOf(1)
+		hundred := 100
+		must.Equal(100, valType.Indirect(&hundred))
+	}))
+	t.Run("Indirect", test.Case(func(ctx *countlog.Context) {
+		valType := reflect2.TypeOf(1)
+		hundred := 100
+		must.Equal(100, valType.UnsafeIndirect(unsafe.Pointer(&hundred)))
+	}))
+	t.Run("Set", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf(1)
+		i := 1
+		j := 10
+		valType.Set(&i, &j)
+		return i
+	}))
+}

+ 44 - 0
test/map_elem_array_test.go

@@ -0,0 +1,44 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+)
+
+func Test_map_elem_array(t *testing.T) {
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := map[int][2]*int{}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		valType.SetIndex(obj, 2, [2]*int{(*int)(reflect2.PtrOf(1)), (*int)(reflect2.PtrOf(2))})
+		valType.SetIndex(obj, 3, [2]*int{(*int)(reflect2.PtrOf(3)), (*int)(reflect2.PtrOf(4))})
+		return obj
+	}))
+	t.Run("SetIndex zero length array", testOp(func(api reflect2.API) interface{} {
+		obj := map[int][0]*int{}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		valType.SetIndex(obj, 2, [0]*int{})
+		valType.SetIndex(obj, 3, [0]*int{})
+		return obj
+	}))
+	t.Run("SetIndex single ptr array", testOp(func(api reflect2.API) interface{} {
+		obj := map[int][1]*int{}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		valType.SetIndex(obj, 2, [1]*int{(*int)(reflect2.PtrOf(1))})
+		valType.SetIndex(obj, 3, [1]*int{})
+		return obj
+	}))
+	t.Run("SetIndex single chan array", testOp(func(api reflect2.API) interface{} {
+		obj := map[int][1]chan int{}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		valType.SetIndex(obj, 2, [1]chan int{})
+		valType.SetIndex(obj, 3, [1]chan int{})
+		return obj
+	}))
+	t.Run("SetIndex single func array", testOp(func(api reflect2.API) interface{} {
+		obj := map[int][1]func(){}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		valType.SetIndex(obj, 2, [1]func(){})
+		valType.SetIndex(obj, 3, [1]func(){})
+		return obj
+	}))
+}

+ 34 - 0
test/map_elem_bytes_test.go

@@ -0,0 +1,34 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+	"github.com/v2pro/plz/test"
+	"github.com/v2pro/plz/countlog"
+	"github.com/v2pro/plz/test/must"
+)
+
+func Test_map_elem_bytes(t *testing.T) {
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := map[int][]byte{}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		valType.SetIndex(obj, 2, []byte("hello"))
+		valType.SetIndex(obj, 3, nil)
+		return obj
+	}))
+	t.Run("UnsafeSetIndex", test.Case(func(ctx *countlog.Context) {
+		obj := map[int][]byte{}
+		valType := reflect2.TypeOf(obj).(reflect2.MapType)
+		hello := []byte("hello")
+		valType.UnsafeSetIndex(reflect2.PtrOf(obj), reflect2.PtrOf(2), reflect2.PtrOf(hello))
+		valType.UnsafeSetIndex(reflect2.PtrOf(obj), reflect2.PtrOf(3), nil)
+		must.Equal([]byte("hello"), obj[2])
+		must.Nil(obj[3])
+	}))
+	t.Run("UnsafeGetIndex", test.Case(func(ctx *countlog.Context) {
+		obj := map[int][]byte{2: []byte("hello")}
+		valType := reflect2.TypeOf(obj).(reflect2.MapType)
+		elem := valType.UnsafeGetIndex(reflect2.PtrOf(obj), reflect2.PtrOf(2))
+		must.Equal([]byte("hello"), valType.Elem().PackEFace(elem))
+	}))
+}

+ 50 - 0
test/map_elem_eface_test.go

@@ -0,0 +1,50 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+	"github.com/v2pro/plz/test/must"
+	"github.com/v2pro/plz/countlog"
+	"github.com/v2pro/plz/test"
+)
+
+func Test_map_elem_eface(t *testing.T) {
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := map[int]interface{}{}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		valType.SetIndex(obj, 2, 4)
+		valType.SetIndex(obj, 3, nil)
+		return obj
+	}))
+	t.Run("GetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := map[int]interface{}{3: 9, 2: nil}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		return []interface{}{
+			valType.GetIndex(obj, 3),
+			valType.GetIndex(obj, 2),
+			valType.GetIndex(obj, 0),
+		}
+	}))
+	t.Run("TryGetIndex", test.Case(func(ctx *countlog.Context) {
+		obj := map[int]interface{}{3: 9, 2: nil}
+		valType := reflect2.TypeOf(obj).(reflect2.MapType)
+		elem, found := valType.TryGetIndex(obj, 3)
+		must.Equal(9, elem)
+		must.Pass(found)
+		elem, found = valType.TryGetIndex(obj, 2)
+		must.Nil(elem)
+		must.Pass(found)
+		elem, found = valType.TryGetIndex(obj, 0)
+		must.Nil(elem)
+		must.Pass(!found)
+	}))
+	t.Run("Iterate", testOp(func(api reflect2.API) interface{} {
+		obj := map[int]interface{}{2: 4}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		iter := valType.Iterate(obj)
+		must.Pass(iter.HasNext(), "api", api)
+		key1, elem1 := iter.Next()
+		must.Pass(!iter.HasNext(), "api", api)
+		return []interface{}{key1, elem1}
+	}))
+}

+ 23 - 0
test/map_elem_map_test.go

@@ -0,0 +1,23 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+)
+
+func Test_map_elem_map(t *testing.T) {
+	var pInt = func(val int) *int {
+		return &val
+	}
+	var pMap = func(val map[int]int) *map[int]int {
+		return &val
+	}
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := map[int]map[int]int{}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		valType.SetIndex(&obj, pInt(2), pMap(map[int]int{4:4}))
+		valType.SetIndex(&obj, pInt(3), pMap(map[int]int{9:9}))
+		valType.SetIndex(&obj, pInt(3), pMap(nil))
+		return obj
+	}))
+}

+ 57 - 0
test/map_elem_struct_test.go

@@ -0,0 +1,57 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+	"time"
+)
+
+func Test_map_elem_struct(t *testing.T) {
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := map[int]time.Time{}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		valType.SetIndex(obj, 2, time.Time{})
+		valType.SetIndex(obj, 3, time.Time{})
+		return obj
+	}))
+	t.Run("SetIndex single ptr struct", testOp(func(api reflect2.API) interface{} {
+		type TestObject struct {
+			Field1 *int
+		}
+		obj := map[int]TestObject{}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		valType.SetIndex(obj, 2, TestObject{})
+		valType.SetIndex(obj, 3, TestObject{})
+		return obj
+	}))
+	t.Run("SetIndex single map struct", testOp(func(api reflect2.API) interface{} {
+		type TestObject struct {
+			Field1 map[int]int
+		}
+		obj := map[int]TestObject{}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		valType.SetIndex(obj, 2, TestObject{})
+		valType.SetIndex(obj, 3, TestObject{})
+		return obj
+	}))
+	t.Run("SetIndex single chan struct", testOp(func(api reflect2.API) interface{} {
+		type TestObject struct {
+			Field1 chan int
+		}
+		obj := map[int]TestObject{}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		valType.SetIndex(obj, 2, TestObject{})
+		valType.SetIndex(obj, 3, TestObject{})
+		return obj
+	}))
+	t.Run("SetIndex single func struct", testOp(func(api reflect2.API) interface{} {
+		type TestObject struct {
+			Field1 func()
+		}
+		obj := map[int]TestObject{}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		valType.SetIndex(obj, 2, TestObject{})
+		valType.SetIndex(obj, 3, TestObject{})
+		return obj
+	}))
+}

+ 43 - 0
test/map_key_eface_test.go

@@ -0,0 +1,43 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+	"github.com/v2pro/plz/test/must"
+)
+
+func Test_map_key_eface(t *testing.T) {
+	var pEFace = func(val interface{}) interface{} {
+		return &val
+	}
+	var pInt = func(val int) *int {
+		return &val
+	}
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := map[interface{}]int{}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		valType.SetIndex(&obj, pEFace(2), pInt(4))
+		valType.SetIndex(&obj, pEFace(3), pInt(9))
+		valType.SetIndex(&obj, pEFace(nil), pInt(9))
+		return obj
+	}))
+	t.Run("GetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := map[interface{}]int{3: 9, 2: 4}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		return []interface{}{
+			valType.GetIndex(&obj, pEFace(3)),
+			valType.GetIndex(&obj, pEFace(0)),
+			valType.GetIndex(&obj, pEFace(nil)),
+			valType.GetIndex(&obj, pEFace("")),
+		}
+	}))
+	t.Run("Iterate", testOp(func(api reflect2.API) interface{} {
+		obj := map[interface{}]int{2: 4}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		iter := valType.Iterate(obj)
+		must.Pass(iter.HasNext(), "api", api)
+		key1, elem1 := iter.Next()
+		must.Pass(!iter.HasNext(), "api", api)
+		return []interface{}{key1, elem1}
+	}))
+}

+ 47 - 0
test/map_key_iface_test.go

@@ -0,0 +1,47 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+	"github.com/v2pro/plz/test/must"
+)
+
+type intError int
+
+func (err intError) Error() string {
+	return ""
+}
+
+func Test_map_iface_key(t *testing.T) {
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := map[error]int{}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		valType.SetIndex(obj, intError(2), 4)
+		valType.SetIndex(obj, intError(2), 9)
+		valType.SetIndex(obj, nil, 9)
+		must.Panic(func() {
+			valType.SetIndex(obj, "", 9)
+		})
+		return obj
+	}))
+	t.Run("GetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := map[error]int{intError(3): 9, intError(2): 4}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		must.Panic(func() {
+			valType.GetIndex(obj, "")
+		})
+		return []interface{}{
+			valType.GetIndex(obj, intError(3)),
+			valType.GetIndex(obj, nil),
+		}
+	}))
+	t.Run("Iterate", testOp(func(api reflect2.API) interface{} {
+		obj := map[error]int{intError(2): 4}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		iter := valType.Iterate(obj)
+		must.Pass(iter.HasNext(), "api", api)
+		key1, elem1 := iter.Next()
+		must.Pass(!iter.HasNext(), "api", api)
+		return []interface{}{key1, elem1}
+	}))
+}

+ 50 - 0
test/map_key_ptr_test.go

@@ -0,0 +1,50 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+	"github.com/v2pro/plz/test/must"
+	"github.com/v2pro/plz/test"
+	"github.com/v2pro/plz/countlog"
+	"unsafe"
+)
+
+func Test_map_key_ptr(t *testing.T) {
+	var pInt = func(val int) *int {
+		return &val
+	}
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := map[*int]int{}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		key := pInt(2)
+		valType.SetIndex(obj, &key, 4)
+		valType.SetIndex(obj, &key, 9)
+		//valType.SetIndex(obj, nil, 9)
+		return obj[pInt(2)]
+	}))
+	t.Run("UnsafeSetIndex", test.Case(func(ctx *countlog.Context) {
+		obj := map[*int]int{}
+		valType := reflect2.TypeOf(obj).(reflect2.MapType)
+		v := pInt(2)
+		valType.UnsafeSetIndex(reflect2.PtrOf(obj), unsafe.Pointer(v), reflect2.PtrOf(4))
+		must.Equal(4, obj[v])
+	}))
+	t.Run("GetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := map[*int]int{pInt(3): 9, pInt(2): 4}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		return []interface{}{
+			valType.GetIndex(obj, pInt(3)),
+			valType.GetIndex(obj, pInt(2)),
+			valType.GetIndex(obj, nil),
+		}
+	}))
+	t.Run("Iterate", testOp(func(api reflect2.API) interface{} {
+		obj := map[*int]int{pInt(2): 4}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		iter := valType.Iterate(&obj)
+		must.Pass(iter.HasNext(), "api", api)
+		key1, elem1 := iter.Next()
+		must.Pass(!iter.HasNext(), "api", api)
+		return []interface{}{key1, elem1}
+	}))
+}

+ 120 - 0
test/map_test.go

@@ -0,0 +1,120 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+	"github.com/v2pro/plz/test/must"
+	"github.com/v2pro/plz/countlog"
+	"github.com/v2pro/plz/test"
+	"unsafe"
+	"reflect"
+)
+
+func Test_map(t *testing.T) {
+	var pInt = func(val int) *int {
+		return &val
+	}
+	t.Run("New", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf(map[int]int{})
+		m := valType.New().(*map[int]int)
+		return m
+	}))
+	t.Run("IsNil", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf(map[int]int{})
+		var nilMap map[int]int
+		m := map[int]int{}
+		return []interface{}{
+			valType.IsNil(&nilMap),
+			valType.IsNil(&m),
+		}
+	}))
+	t.Run("MakeMap", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf(map[int]int{}).(reflect2.MapType)
+		m := *(valType.MakeMap(0).(*map[int]int))
+		m[2] = 4
+		m[3] = 9
+		return m
+	}))
+	t.Run("UnsafeMakeMap", test.Case(func(ctx *countlog.Context) {
+		valType := reflect2.TypeOf(map[int]int{}).(reflect2.MapType)
+		m := *(*map[int]int)(valType.UnsafeMakeMap(0))
+		m[2] = 4
+		m[3] = 9
+	}))
+	t.Run("PackEFace", test.Case(func(ctx *countlog.Context) {
+		valType := reflect2.TypeOf(map[int]int{}).(reflect2.MapType)
+		m := valType.UnsafeMakeMap(0)
+		must.Equal(&map[int]int{}, valType.PackEFace(unsafe.Pointer(m)))
+	}))
+	t.Run("Indirect", testOp(func(api reflect2.API) interface{} {
+		valType := reflect2.TypeOf(map[int]int{})
+		return valType.Indirect(&map[int]int{})
+	}))
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := map[int]int{}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		valType.SetIndex(&obj, pInt(2), pInt(4))
+		valType.SetIndex(&obj, pInt(3), pInt(9))
+		must.Equal(4, obj[2])
+		return obj
+	}))
+	t.Run("UnsafeSetIndex", test.Case(func(ctx *countlog.Context) {
+		obj := map[int]int{}
+		valType := reflect2.TypeOf(obj).(reflect2.MapType)
+		valType.UnsafeSetIndex(unsafe.Pointer(&obj), reflect2.PtrOf(2), reflect2.PtrOf(4))
+		must.Equal(map[int]int{2: 4}, obj)
+	}))
+	t.Run("GetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := map[int]int{3: 9, 2: 4}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		return []interface{}{
+			*valType.GetIndex(&obj, pInt(3)).(*int),
+			valType.GetIndex(&obj, pInt(0)).(*int),
+		}
+	}))
+	t.Run("UnsafeGetIndex", test.Case(func(ctx *countlog.Context) {
+		obj := map[int]int{3: 9, 2: 4}
+		valType := reflect2.TypeOf(obj).(reflect2.MapType)
+		elem := valType.UnsafeGetIndex(unsafe.Pointer(&obj), reflect2.PtrOf(3))
+		must.Equal(9, *(*int)(elem))
+	}))
+	t.Run("Iterate", testOp(func(api reflect2.API) interface{} {
+		obj := map[int]int{2: 4}
+		valType := api.TypeOf(obj).(reflect2.MapType)
+		iter := valType.Iterate(&obj)
+		must.Pass(iter.HasNext(), "api", api)
+		key1, elem1 := iter.Next()
+		must.Pass(!iter.HasNext(), "api", api)
+		return []interface{}{key1, elem1}
+	}))
+	t.Run("UnsafeIterate", test.Case(func(ctx *countlog.Context) {
+		obj := map[int]int{2: 4}
+		valType := reflect2.TypeOf(obj).(reflect2.MapType)
+		iter := valType.UnsafeIterate(unsafe.Pointer(&obj))
+		must.Pass(iter.HasNext())
+		key, elem := iter.UnsafeNext()
+		must.Equal(2, *(*int)(key))
+		must.Equal(4, *(*int)(elem))
+	}))
+}
+
+func Benchmark_map_unsafe(b *testing.B) {
+	obj := map[int]int{}
+	valType := reflect2.TypeOf(obj).(*reflect2.UnsafeMapType)
+	m := unsafe.Pointer(&obj)
+	b.ReportAllocs()
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		valType.UnsafeSetIndex(m, reflect2.PtrOf(2), reflect2.PtrOf(4))
+	}
+}
+
+func Benchmark_map_safe(b *testing.B) {
+	obj := map[int]int{}
+	val := reflect.ValueOf(obj)
+	b.ReportAllocs()
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		val.SetMapIndex(reflect.ValueOf(2), reflect.ValueOf(4))
+	}
+}

+ 17 - 0
test/op_test.go

@@ -0,0 +1,17 @@
+package test
+
+import (
+	"github.com/modern-go/reflect2"
+	"testing"
+	"github.com/v2pro/plz/countlog"
+	"github.com/v2pro/plz/test/must"
+	"github.com/v2pro/plz/test"
+)
+
+func testOp(f func(api reflect2.API) interface{}) func(t *testing.T) {
+	return test.Case(func(ctx *countlog.Context) {
+		unsafeResult := f(reflect2.ConfigUnsafe)
+		safeResult := f(reflect2.ConfigSafe)
+		must.Equal(safeResult, unsafeResult)
+	})
+}

+ 37 - 0
test/slice_array_test.go

@@ -0,0 +1,37 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+)
+
+func Test_slice_array(t *testing.T) {
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := [][1]int{{}, {}}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.SetIndex(obj, 0, [1]int{1})
+		valType.SetIndex(obj, 1, [1]int{2})
+		return obj
+	}))
+	t.Run("SetIndex single ptr struct", testOp(func(api reflect2.API) interface{} {
+		obj := [][1]*int{{}, {}}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.SetIndex(obj, 0, [1]*int{})
+		valType.SetIndex(obj, 1, [1]*int{})
+		return obj
+	}))
+	t.Run("SetIndex single chan struct", testOp(func(api reflect2.API) interface{} {
+		obj := [][1]chan int{{}, {}}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.SetIndex(obj, 0, [1]chan int{})
+		valType.SetIndex(obj, 1, [1]chan int{})
+		return obj
+	}))
+	t.Run("SetIndex single func struct", testOp(func(api reflect2.API) interface{} {
+		obj := [][1]func(){{}, {}}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.SetIndex(obj, 0, [1]func(){})
+		valType.SetIndex(obj, 1, [1]func(){})
+		return obj
+	}))
+}

+ 16 - 0
test/slice_bytes_test.go

@@ -0,0 +1,16 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+)
+
+func Test_slice_bytes(t *testing.T) {
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := [][]byte{[]byte("hello"), []byte("world")}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.SetIndex(&obj, 0, []byte("hi"))
+		valType.SetIndex(&obj, 1, []byte("there"))
+		return obj
+	}))
+}

+ 77 - 0
test/slice_eface_test.go

@@ -0,0 +1,77 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+	"github.com/v2pro/plz/test"
+	"github.com/v2pro/plz/countlog"
+	"github.com/v2pro/plz/test/must"
+	"unsafe"
+	"github.com/v2pro/plz/test/should"
+	"fmt"
+)
+
+func Test_slice_eface(t *testing.T) {
+	t.Run("MakeSlice", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf([]interface{}{}).(reflect2.SliceType)
+		obj := valType.MakeSlice(5, 10)
+		obj.([]interface{})[0] = 100
+		obj.([]interface{})[4] = 20
+		return obj
+	}))
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := []interface{}{1, nil}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		elem0 := interface{}(100)
+		valType.SetIndex(obj, 0, &elem0)
+		elem1 := interface{}(20)
+		valType.SetIndex(obj, 1, &elem1)
+		return obj
+	}))
+	t.Run("UnsafeSetIndex", test.Case(func(ctx *countlog.Context) {
+		obj := []interface{}{1, 2}
+		valType := reflect2.TypeOf(obj).(reflect2.SliceType)
+		var elem0 interface{} = 100
+		valType.UnsafeSetIndex(reflect2.PtrOf(obj), 0, unsafe.Pointer(&elem0))
+		var elem1 interface{} = 10
+		valType.UnsafeSetIndex(reflect2.PtrOf(obj), 1, unsafe.Pointer(&elem1))
+		must.Equal([]interface{}{100, 10}, obj)
+	}))
+	t.Run("GetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := []interface{}{1, nil}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		fmt.Println(api, *valType.GetIndex(obj, 0).(*interface{}))
+		return []interface{}{
+			valType.GetIndex(obj, 0),
+			valType.GetIndex(obj, 1),
+		}
+	}))
+	t.Run("UnsafeGetIndex", test.Case(func(ctx *countlog.Context) {
+		obj := []interface{}{1, nil}
+		valType := reflect2.TypeOf(obj).(reflect2.SliceType)
+		elem0 := valType.UnsafeGetIndex(reflect2.PtrOf(obj), 0)
+		must.Equal(1, *(*interface{})(elem0))
+	}))
+	t.Run("Append", testOp(func(api reflect2.API) interface{} {
+		obj := make([]interface{}, 2, 3)
+		obj[0] = 1
+		obj[1] = 2
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.Append(&obj, 3)
+		// will trigger grow
+		valType.Append(&obj, 4)
+		return obj
+	}))
+	t.Run("UnsafeAppend", test.Case(func(ctx *countlog.Context) {
+		obj := make([]interface{}, 2, 3)
+		obj[0] = 1
+		obj[1] = 2
+		valType := reflect2.TypeOf(obj).(reflect2.SliceType)
+		ptr := reflect2.PtrOf(obj)
+		var elem2 interface{} = 3
+		valType.UnsafeAppend(ptr, unsafe.Pointer(&elem2))
+		var elem3 interface{} = 4
+		valType.UnsafeAppend(ptr, unsafe.Pointer(&elem3))
+		should.Equal([]interface{}{1, 2, 3, 4}, valType.PackEFace(ptr))
+	}))
+}

+ 80 - 0
test/slice_iface_test.go

@@ -0,0 +1,80 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+	"errors"
+	"github.com/v2pro/plz/test"
+	"github.com/v2pro/plz/countlog"
+	"unsafe"
+	"github.com/v2pro/plz/test/must"
+)
+
+func Test_slice_iface(t *testing.T) {
+	var pError = func(msg string) *error {
+		err := errors.New(msg)
+		return &err
+	}
+	t.Run("MakeSlice", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf([]error{}).(reflect2.SliceType)
+		obj := *(valType.MakeSlice(5, 10).(*[]error))
+		obj[0] = errors.New("hello")
+		obj[4] = errors.New("world")
+		return obj
+	}))
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := []error{errors.New("hello"), nil}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.SetIndex(&obj, 0, pError("hi"))
+		valType.SetIndex(&obj, 1, pError("world"))
+		return obj
+	}))
+	t.Run("UnsafeSetIndex", test.Case(func(ctx *countlog.Context) {
+		obj := []error{errors.New("hello"), nil}
+		valType := reflect2.TypeOf(obj).(reflect2.SliceType)
+		elem0 := errors.New("hi")
+		valType.UnsafeSetIndex(reflect2.PtrOf(obj), 0, unsafe.Pointer(&elem0))
+		elem1 := errors.New("world")
+		valType.UnsafeSetIndex(reflect2.PtrOf(obj), 1, unsafe.Pointer(&elem1))
+		must.Equal([]error{elem0, elem1}, obj)
+	}))
+	t.Run("GetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := []error{errors.New("hello"), nil}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		return []interface{}{
+			valType.GetIndex(&obj, 0),
+			valType.GetIndex(&obj, 1),
+		}
+	}))
+	t.Run("UnsafeGetIndex", test.Case(func(ctx *countlog.Context) {
+		obj := []error{errors.New("hello"), nil}
+		valType := reflect2.TypeOf(obj).(reflect2.SliceType)
+		elem0 := valType.UnsafeGetIndex(reflect2.PtrOf(obj), 0)
+		must.Equal(errors.New("hello"), *(*error)(elem0))
+	}))
+	t.Run("Append", testOp(func(api reflect2.API) interface{} {
+		obj := make([]error, 2, 3)
+		obj[0] = errors.New("1")
+		obj[1] = errors.New("2")
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		ptr := &obj
+		valType.Append(ptr, pError("3"))
+		// will trigger grow
+		valType.Append(ptr, pError("4"))
+		return ptr
+	}))
+	t.Run("UnsafeAppend", test.Case(func(ctx *countlog.Context) {
+		obj := make([]error, 2, 3)
+		obj[0] = errors.New("1")
+		obj[1] = errors.New("2")
+		valType := reflect2.TypeOf(obj).(reflect2.SliceType)
+		ptr := reflect2.PtrOf(obj)
+		elem2 := errors.New("3")
+		valType.UnsafeAppend(ptr, unsafe.Pointer(&elem2))
+		elem3 := errors.New("4")
+		valType.UnsafeAppend(ptr, unsafe.Pointer(&elem3))
+		must.Equal(&[]error{
+			obj[0], obj[1], elem2, elem3,
+		}, valType.PackEFace(ptr))
+	}))
+}

+ 43 - 0
test/slice_map_test.go

@@ -0,0 +1,43 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+)
+
+func Test_slice_map(t *testing.T) {
+	t.Run("MakeSlice", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf([]map[int]int{}).(reflect2.SliceType)
+		obj := valType.MakeSlice(5, 10)
+		obj.([]map[int]int)[0] = map[int]int{1:1}
+		obj.([]map[int]int)[4] = map[int]int{2:2}
+		return obj
+	}))
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := []map[int]int{{1: 1}, nil}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.SetIndex(obj, 0, &map[int]int{10:10})
+		valType.SetIndex(obj, 1, &map[int]int{2:2})
+		return obj
+	}))
+	t.Run("GetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := []map[int]int{{1:1}, nil}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		return []interface{}{
+			valType.GetIndex(&obj, 0),
+			valType.GetIndex(&obj, 1),
+			valType.GetIndex(obj, 0),
+			valType.GetIndex(obj, 1),
+		}
+	}))
+	t.Run("Append", testOp(func(api reflect2.API) interface{} {
+		obj := make([]map[int]int, 2, 3)
+		obj[0] = map[int]int{1:1}
+		obj[1] = map[int]int{2:2}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.Append(obj, map[int]int{3:3})
+		// will trigger grow
+		valType.Append(obj, map[int]int{4:4})
+		return obj
+	}))
+}

+ 57 - 0
test/slice_ptr_test.go

@@ -0,0 +1,57 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+	"github.com/v2pro/plz/test"
+	"github.com/v2pro/plz/countlog"
+	"unsafe"
+	"github.com/v2pro/plz/test/must"
+)
+
+func Test_slice_ptr(t *testing.T) {
+	var pInt = func(val int) *int {
+		return &val
+	}
+	t.Run("MakeSlice", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf([]*int{}).(reflect2.SliceType)
+		obj := valType.MakeSlice(5, 10)
+		obj.([]*int)[0] = pInt(1)
+		obj.([]*int)[4] = pInt(5)
+		return obj
+	}))
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := []*int{pInt(1), nil}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.SetIndex(obj, 0, pInt(2))
+		valType.SetIndex(obj, 1, pInt(3))
+		return obj
+	}))
+	t.Run("UnsafeSetIndex", test.Case(func(ctx *countlog.Context) {
+		obj := []*int{pInt(1), nil}
+		valType := reflect2.TypeOf(obj).(reflect2.SliceType)
+		valType.UnsafeSetIndex(reflect2.PtrOf(obj), 0, unsafe.Pointer(pInt(2)))
+		valType.UnsafeSetIndex(reflect2.PtrOf(obj), 1, unsafe.Pointer(pInt(1)))
+		must.Equal([]*int{pInt(2), pInt(1)}, obj)
+	}))
+	t.Run("GetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := []*int{pInt(1), nil}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		return []interface{}{
+			valType.GetIndex(&obj, 0),
+			valType.GetIndex(&obj, 1),
+			valType.GetIndex(obj, 0),
+			valType.GetIndex(obj, 1),
+		}
+	}))
+	t.Run("Append", testOp(func(api reflect2.API) interface{} {
+		obj := make([]*int, 2, 3)
+		obj[0] = pInt(1)
+		obj[1] = pInt(2)
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.Append(obj, pInt(3))
+		// will trigger grow
+		valType.Append(obj, pInt(4))
+		return obj
+	}))
+}

+ 16 - 0
test/slice_string_test.go

@@ -0,0 +1,16 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+)
+
+func Test_slice_string(t *testing.T) {
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := []string{"hello", "world"}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.SetIndex(&obj, 0, "hi")
+		valType.SetIndex(&obj, 1, "there")
+		return obj
+	}))
+}

+ 53 - 0
test/slice_struct_test.go

@@ -0,0 +1,53 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+)
+
+func Test_slice_struct(t *testing.T) {
+	var pInt = func(val int) *int {
+		return &val
+	}
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		type TestObject struct {
+			Field1 float64
+			Field2 float64
+		}
+		obj := []TestObject{{}, {}}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.SetIndex(obj, 0, &TestObject{1, 3})
+		valType.SetIndex(obj, 1, &TestObject{2, 4})
+		return obj
+	}))
+	t.Run("SetIndex single ptr struct", testOp(func(api reflect2.API) interface{} {
+		type TestObject struct {
+			Field1 *int
+		}
+		obj := []TestObject{{}, {}}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.SetIndex(obj, 0, &TestObject{pInt(1)})
+		valType.SetIndex(obj, 1, &TestObject{pInt(2)})
+		return obj
+	}))
+	t.Run("SetIndex single chan struct", testOp(func(api reflect2.API) interface{} {
+		type TestObject struct {
+			Field1 chan int
+		}
+		obj := []TestObject{{}, {}}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.SetIndex(obj, 0, TestObject{})
+		valType.SetIndex(obj, 1, TestObject{})
+		return obj
+	}))
+	t.Run("SetIndex single func struct", testOp(func(api reflect2.API) interface{} {
+		type TestObject struct {
+			Field1 func()
+		}
+		obj := []TestObject{{}, {}}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.SetIndex(obj, 0, TestObject{})
+		valType.SetIndex(obj, 1, TestObject{})
+		return obj
+	}))
+}

+ 114 - 0
test/slice_test.go

@@ -0,0 +1,114 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+	"github.com/v2pro/plz/test"
+	"github.com/v2pro/plz/countlog"
+	"github.com/v2pro/plz/test/must"
+)
+
+func Test_slice(t *testing.T) {
+	var pInt = func(val int) *int {
+		return &val
+	}
+	t.Run("New", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf([]int{})
+		obj := *valType.New().(*[]int)
+		obj = append(obj, 1)
+		return obj
+	}))
+	t.Run("IsNil", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf([]int{})
+		var nilSlice []int
+		s := []int{}
+		return []interface{}{
+			valType.IsNil(&nilSlice),
+			valType.IsNil(&s),
+			valType.IsNil(nil),
+		}
+	}))
+	t.Run("SetNil", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf([]int{}).(reflect2.SliceType)
+		s := []int{1}
+		valType.SetNil(&s)
+		return s
+	}))
+	t.Run("Set", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf([]int{}).(reflect2.SliceType)
+		s1 := []int{1}
+		s2 := []int{2}
+		valType.Set(&s1, &s2)
+		return s1
+	}))
+	t.Run("MakeSlice", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf([]int{}).(reflect2.SliceType)
+		obj := *(valType.MakeSlice(5, 10).(*[]int))
+		obj[0] = 100
+		obj[4] = 20
+		return obj
+	}))
+	t.Run("UnsafeMakeSlice", test.Case(func(ctx *countlog.Context) {
+		valType := reflect2.TypeOf([]int{}).(reflect2.SliceType)
+		obj := valType.UnsafeMakeSlice(5, 10)
+		must.Equal(&[]int{0, 0, 0, 0, 0}, valType.PackEFace(obj))
+	}))
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := []int{1, 2}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		valType.SetIndex(&obj, 0, pInt(100))
+		valType.SetIndex(&obj, 1, pInt(20))
+		return obj
+	}))
+	t.Run("UnsafeSetIndex", test.Case(func(ctx *countlog.Context) {
+		obj := []int{1, 2}
+		valType := reflect2.TypeOf(obj).(reflect2.SliceType)
+		valType.UnsafeSetIndex(reflect2.PtrOf(obj), 0, reflect2.PtrOf(100))
+		valType.UnsafeSetIndex(reflect2.PtrOf(obj), 1, reflect2.PtrOf(10))
+		must.Equal([]int{100, 10}, obj)
+	}))
+	t.Run("GetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := []int{1, 2}
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		return []interface{}{
+			valType.GetIndex(&obj, 1).(*int),
+		}
+	}))
+	t.Run("UnsafeGetIndex", test.Case(func(ctx *countlog.Context) {
+		obj := []int{1, 2}
+		valType := reflect2.TypeOf(obj).(reflect2.SliceType)
+		elem0 := valType.UnsafeGetIndex(reflect2.PtrOf(obj), 0)
+		must.Equal(1, *(*int)(elem0))
+		elem1 := valType.UnsafeGetIndex(reflect2.PtrOf(obj), 1)
+		must.Equal(2, *(*int)(elem1))
+	}))
+	t.Run("Append", testOp(func(api reflect2.API) interface{} {
+		obj := make([]int, 2, 3)
+		obj[0] = 1
+		obj[1] = 2
+		valType := api.TypeOf(obj).(reflect2.SliceType)
+		ptr := &obj
+		valType.Append(ptr, pInt(3))
+		// will trigger grow
+		valType.Append(ptr, pInt(4))
+		return ptr
+	}))
+	t.Run("UnsafeAppend", test.Case(func(ctx *countlog.Context) {
+		obj := make([]int, 2, 3)
+		obj[0] = 1
+		obj[1] = 2
+		valType := reflect2.TypeOf(obj).(reflect2.SliceType)
+		ptr := reflect2.PtrOf(obj)
+		valType.UnsafeAppend(ptr, reflect2.PtrOf(3))
+		valType.UnsafeAppend(ptr, reflect2.PtrOf(4))
+		must.Equal(&[]int{1, 2, 3, 4}, valType.PackEFace(ptr))
+	}))
+	t.Run("Grow", testOp(func(api reflect2.API) interface{} {
+		obj := make([]int, 2, 3)
+		obj[0] = 1
+		obj[1] = 2
+		valType := reflect2.TypeOf(obj).(reflect2.SliceType)
+		valType.Grow(&obj, 4)
+		return obj
+	}))
+}

+ 28 - 0
test/struct_eface_test.go

@@ -0,0 +1,28 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+)
+
+func Test_struct_eface(t *testing.T) {
+	type TestObject struct {
+		Field1 interface{}
+	}
+	var pEFace = func(val interface{}) interface{} {
+		return &val
+	}
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf(TestObject{}).(reflect2.StructType)
+		field1 := valType.FieldByName("Field1")
+		obj := TestObject{}
+		field1.Set(&obj, pEFace(100))
+		return obj
+	}))
+	t.Run("GetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := TestObject{Field1: 100}
+		valType := api.TypeOf(obj).(reflect2.StructType)
+		field1 := valType.FieldByName("Field1")
+		return field1.Get(&obj)
+	}))
+}

+ 24 - 0
test/struct_ptr_test.go

@@ -0,0 +1,24 @@
+package test
+
+import (
+	"testing"
+	"github.com/v2pro/plz/countlog"
+	"github.com/modern-go/reflect2"
+	"github.com/v2pro/plz/test/must"
+	"github.com/v2pro/plz/test"
+)
+
+func Test_struct_ptr(t *testing.T) {
+	type TestObject struct {
+		Field1 *int
+	}
+	t.Run("PackEFace", test.Case(func(ctx *countlog.Context) {
+		valType := reflect2.TypeOf(TestObject{})
+		ptr := valType.UnsafeNew()
+		must.Equal(&TestObject{}, valType.PackEFace(ptr))
+	}))
+	t.Run("Indirect", test.Case(func(ctx *countlog.Context) {
+		valType := reflect2.TypeOf(TestObject{})
+		must.Equal(TestObject{}, valType.Indirect(&TestObject{}))
+	}))
+}

+ 63 - 0
test/struct_test.go

@@ -0,0 +1,63 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+	"github.com/v2pro/plz/test"
+	"github.com/v2pro/plz/countlog"
+	"unsafe"
+	"github.com/v2pro/plz/test/must"
+)
+
+func Test_struct(t *testing.T) {
+	type TestObject struct {
+		Field1 int
+		Field2 int
+	}
+	var pInt = func(val int) *int {
+		return &val
+	}
+	t.Run("New", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf(TestObject{})
+		obj := valType.New()
+		obj.(*TestObject).Field1 = 20
+		obj.(*TestObject).Field2 = 100
+		return obj
+	}))
+	t.Run("PackEFace", test.Case(func(ctx *countlog.Context) {
+		valType := reflect2.TypeOf(TestObject{})
+		ptr := valType.UnsafeNew()
+		must.Equal(&TestObject{}, valType.PackEFace(ptr))
+	}))
+	t.Run("Indirect", test.Case(func(ctx *countlog.Context) {
+		valType := reflect2.TypeOf(TestObject{})
+		must.Equal(TestObject{}, valType.Indirect(&TestObject{}))
+	}))
+	t.Run("SetIndex", testOp(func(api reflect2.API) interface{} {
+		valType := api.TypeOf(TestObject{}).(reflect2.StructType)
+		field1 := valType.FieldByName("Field1")
+		obj := TestObject{}
+		field1.Set(&obj, pInt(100))
+		return obj
+	}))
+	t.Run("UnsafeSetIndex", test.Case(func(ctx *countlog.Context) {
+		valType := reflect2.TypeOf(TestObject{}).(reflect2.StructType)
+		field1 := valType.FieldByName("Field1")
+		obj := TestObject{}
+		field1.UnsafeSet(unsafe.Pointer(&obj), reflect2.PtrOf(100))
+		must.Equal(100, obj.Field1)
+	}))
+	t.Run("GetIndex", testOp(func(api reflect2.API) interface{} {
+		obj := TestObject{Field1: 100}
+		valType := api.TypeOf(obj).(reflect2.StructType)
+		field1 := valType.FieldByName("Field1")
+		return field1.Get(&obj)
+	}))
+	t.Run("UnsafeGetIndex", test.Case(func(ctx *countlog.Context) {
+		obj := TestObject{Field1: 100}
+		valType := reflect2.TypeOf(obj).(reflect2.StructType)
+		field1 := valType.FieldByName("Field1")
+		value := field1.UnsafeGet(unsafe.Pointer(&obj))
+		must.Equal(100, *(*int)(value))
+	}))
+}

+ 18 - 0
test15/map_test.go

@@ -0,0 +1,18 @@
+package test
+
+import (
+	"testing"
+	"github.com/modern-go/reflect2"
+)
+
+func Test_map(t *testing.T) {
+	var pInt = func(val int) *int {
+		return &val
+	}
+	valType := reflect2.TypeOf(map[int]int{}).(reflect2.MapType)
+	m := map[int]int{}
+	valType.SetIndex(&m, pInt(1), pInt(1))
+	if m[1] != 1 {
+		t.Fail()
+	}
+}

+ 72 - 0
type_map.go

@@ -0,0 +1,72 @@
+package reflect2
+
+import (
+	"unsafe"
+	"reflect"
+	"runtime"
+	"strings"
+)
+
+// typelinks1 for 1.5 ~ 1.6
+//go:linkname typelinks1 reflect.typelinks
+func typelinks1() [][]unsafe.Pointer
+
+// typelinks2 for 1.7 ~
+//go:linkname typelinks2 reflect.typelinks
+func typelinks2() (sections []unsafe.Pointer, offset [][]int32)
+
+var types = map[string]reflect.Type{}
+
+func init() {
+	ver := runtime.Version()
+	if ver == "go1.5" || strings.HasPrefix(ver, "go1.5.") {
+		loadGo15Types()
+	} else if ver == "go1.6" || strings.HasPrefix(ver, "go1.6.") {
+		loadGo15Types()
+	} else {
+		loadGo17Types()
+	}
+}
+
+func loadGo15Types() {
+	var obj interface{} = reflect.TypeOf(0)
+	typePtrss := typelinks1()
+	for _, typePtrs := range typePtrss {
+		for _, typePtr := range typePtrs {
+			(*emptyInterface)(unsafe.Pointer(&obj)).word = typePtr
+			typ := obj.(reflect.Type)
+			if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct {
+				types[typ.Elem().String()] = typ.Elem()
+			}
+			if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Ptr &&
+				typ.Elem().Elem().Kind() == reflect.Struct {
+				types[typ.Elem().Elem().String()] = typ.Elem().Elem()
+			}
+		}
+	}
+}
+
+func loadGo17Types() {
+	var obj interface{} = reflect.TypeOf(0)
+	sections, offset := typelinks2()
+	for i, offs := range offset {
+		rodata := sections[i]
+		for _, off := range offs {
+			(*emptyInterface)(unsafe.Pointer(&obj)).word = resolveTypeOff(unsafe.Pointer(rodata), off)
+			typ := obj.(reflect.Type)
+			if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct {
+				types[typ.Elem().String()] = typ.Elem()
+			}
+		}
+	}
+}
+
+type emptyInterface struct {
+	typ  unsafe.Pointer
+	word unsafe.Pointer
+}
+
+// TypeByName return the type by its name, just like Class.forName in java
+func TypeByName(typeName string) Type {
+	return Type2(types[typeName])
+}

+ 65 - 0
unsafe_array.go

@@ -0,0 +1,65 @@
+package reflect2
+
+import (
+	"unsafe"
+	"reflect"
+)
+
+type UnsafeArrayType struct {
+	unsafeType
+	elemRType  unsafe.Pointer
+	pElemRType unsafe.Pointer
+	elemSize   uintptr
+	likePtr    bool
+}
+
+func newUnsafeArrayType(cfg *frozenConfig, type1 reflect.Type) *UnsafeArrayType {
+	return &UnsafeArrayType{
+		unsafeType: *newUnsafeType(cfg, type1),
+		elemRType:  unpackEFace(type1.Elem()).data,
+		pElemRType: unpackEFace(reflect.PtrTo(type1.Elem())).data,
+		elemSize:   type1.Elem().Size(),
+		likePtr:    likePtrType(type1),
+	}
+}
+
+func (type2 *UnsafeArrayType) LikePtr() bool {
+	return type2.likePtr
+}
+
+func (type2 *UnsafeArrayType) Indirect(obj interface{}) interface{} {
+	objEFace := unpackEFace(obj)
+	assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype)
+	return type2.UnsafeIndirect(objEFace.data)
+}
+
+func (type2 *UnsafeArrayType) UnsafeIndirect(ptr unsafe.Pointer) interface{} {
+	if type2.likePtr {
+		return packEFace(type2.rtype, *(*unsafe.Pointer)(ptr))
+	}
+	return packEFace(type2.rtype, ptr)
+}
+
+func (type2 *UnsafeArrayType) SetIndex(obj interface{}, index int, elem interface{}) {
+	objEFace := unpackEFace(obj)
+	assertType("ArrayType.SetIndex argument 1", type2.ptrRType, objEFace.rtype)
+	elemEFace := unpackEFace(elem)
+	assertType("ArrayType.SetIndex argument 3", type2.pElemRType, elemEFace.rtype)
+	type2.UnsafeSetIndex(objEFace.data, index, elemEFace.data)
+}
+
+func (type2 *UnsafeArrayType) UnsafeSetIndex(obj unsafe.Pointer, index int, elem unsafe.Pointer) {
+	elemPtr := arrayAt(obj, index, type2.elemSize, "i < s.Len")
+	typedmemmove(type2.elemRType, elemPtr, elem)
+}
+
+func (type2 *UnsafeArrayType) GetIndex(obj interface{}, index int) interface{} {
+	objEFace := unpackEFace(obj)
+	assertType("ArrayType.GetIndex argument 1", type2.ptrRType, objEFace.rtype)
+	elemPtr := type2.UnsafeGetIndex(objEFace.data, index)
+	return packEFace(type2.pElemRType, elemPtr)
+}
+
+func (type2 *UnsafeArrayType) UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer {
+	return arrayAt(obj, index, type2.elemSize, "i < s.Len")
+}

+ 59 - 0
unsafe_eface.go

@@ -0,0 +1,59 @@
+package reflect2
+
+import (
+	"unsafe"
+	"reflect"
+)
+
+type eface struct {
+	rtype unsafe.Pointer
+	data  unsafe.Pointer
+}
+
+func unpackEFace(obj interface{}) *eface {
+	return (*eface)(unsafe.Pointer(&obj))
+}
+
+func packEFace(rtype unsafe.Pointer, data unsafe.Pointer) interface{} {
+	var i interface{}
+	e := (*eface)(unsafe.Pointer(&i))
+	e.rtype = rtype
+	e.data = data
+	return i
+}
+
+type UnsafeEFaceType struct {
+	unsafeType
+}
+
+func newUnsafeEFaceType(cfg *frozenConfig, type1 reflect.Type) *UnsafeEFaceType {
+	return &UnsafeEFaceType{
+		unsafeType: *newUnsafeType(cfg, type1),
+	}
+}
+
+func (type2 *UnsafeEFaceType) IsNil(obj interface{}) bool {
+	if obj == nil {
+		return true
+	}
+	objEFace := unpackEFace(obj)
+	assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype)
+	return type2.UnsafeIsNil(objEFace.data)
+}
+
+func (type2 *UnsafeEFaceType) UnsafeIsNil(ptr unsafe.Pointer) bool {
+	if ptr == nil {
+		return true
+	}
+	return unpackEFace(*(*interface{})(ptr)).data == nil
+}
+
+func (type2 *UnsafeEFaceType) Indirect(obj interface{}) interface{} {
+	objEFace := unpackEFace(obj)
+	assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype)
+	return type2.UnsafeIndirect(objEFace.data)
+}
+
+func (type2 *UnsafeEFaceType) UnsafeIndirect(ptr unsafe.Pointer) interface{} {
+	return *(*interface{})(ptr)
+}

+ 74 - 0
unsafe_field.go

@@ -0,0 +1,74 @@
+package reflect2
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+type UnsafeStructField struct {
+	reflect.StructField
+	structType *UnsafeStructType
+	rtype      unsafe.Pointer
+	ptrRType   unsafe.Pointer
+}
+
+func newUnsafeStructField(structType *UnsafeStructType, structField reflect.StructField) *UnsafeStructField {
+	return &UnsafeStructField{
+		StructField: structField,
+		rtype:       unpackEFace(structField.Type).data,
+		ptrRType:    unpackEFace(reflect.PtrTo(structField.Type)).data,
+		structType:  structType,
+	}
+}
+
+func (field *UnsafeStructField) Offset() uintptr {
+	return field.StructField.Offset
+}
+
+func (field *UnsafeStructField) Name() string {
+	return field.StructField.Name
+}
+
+func (field *UnsafeStructField) PkgPath() string {
+	return field.StructField.PkgPath
+}
+
+func (field *UnsafeStructField) Type() Type {
+	return field.structType.cfg.Type2(field.StructField.Type)
+}
+
+func (field *UnsafeStructField) Tag() reflect.StructTag {
+	return field.StructField.Tag
+}
+
+func (field *UnsafeStructField) Index() []int {
+	return field.StructField.Index
+}
+
+func (field *UnsafeStructField) Anonymous() bool {
+	return field.StructField.Anonymous
+}
+
+func (field *UnsafeStructField) Set(obj interface{}, value interface{}) {
+	objEFace := unpackEFace(obj)
+	assertType("StructField.SetIndex argument 1", field.structType.ptrRType, objEFace.rtype)
+	valueEFace := unpackEFace(value)
+	assertType("StructField.SetIndex argument 2", field.ptrRType, valueEFace.rtype)
+	field.UnsafeSet(objEFace.data, valueEFace.data)
+}
+
+func (field *UnsafeStructField) UnsafeSet(obj unsafe.Pointer, value unsafe.Pointer) {
+	fieldPtr := add(obj, field.StructField.Offset, "same as non-reflect &v.field")
+	typedmemmove(field.rtype, fieldPtr, value)
+}
+
+func (field *UnsafeStructField) Get(obj interface{}) interface{} {
+	objEFace := unpackEFace(obj)
+	assertType("StructField.GetIndex argument 1", field.structType.ptrRType, objEFace.rtype)
+	value := field.UnsafeGet(objEFace.data)
+	return packEFace(field.ptrRType, value)
+}
+
+func (field *UnsafeStructField) UnsafeGet(obj unsafe.Pointer) unsafe.Pointer {
+	return add(obj, field.StructField.Offset, "same as non-reflect &v.field")
+}

+ 64 - 0
unsafe_iface.go

@@ -0,0 +1,64 @@
+package reflect2
+
+import (
+	"unsafe"
+	"reflect"
+)
+
+type iface struct {
+	itab *itab
+	data unsafe.Pointer
+}
+
+type itab struct {
+	ignore unsafe.Pointer
+	rtype  unsafe.Pointer
+}
+
+func IFaceToEFace(ptr unsafe.Pointer) interface{} {
+	iface := (*iface)(ptr)
+	if iface.itab == nil {
+		return nil
+	}
+	return packEFace(iface.itab.rtype, iface.data)
+}
+
+type UnsafeIFaceType struct {
+	unsafeType
+}
+
+func newUnsafeIFaceType(cfg *frozenConfig, type1 reflect.Type) *UnsafeIFaceType {
+	return &UnsafeIFaceType{
+		unsafeType: *newUnsafeType(cfg, type1),
+	}
+}
+
+func (type2 *UnsafeIFaceType) Indirect(obj interface{}) interface{} {
+	objEFace := unpackEFace(obj)
+	assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype)
+	return type2.UnsafeIndirect(objEFace.data)
+}
+
+func (type2 *UnsafeIFaceType) UnsafeIndirect(ptr unsafe.Pointer) interface{} {
+	return IFaceToEFace(ptr)
+}
+
+func (type2 *UnsafeIFaceType) IsNil(obj interface{}) bool {
+	if obj == nil {
+		return true
+	}
+	objEFace := unpackEFace(obj)
+	assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype)
+	return type2.UnsafeIsNil(objEFace.data)
+}
+
+func (type2 *UnsafeIFaceType) UnsafeIsNil(ptr unsafe.Pointer) bool {
+	if ptr == nil {
+		return true
+	}
+	iface := (*iface)(ptr)
+	if iface.itab == nil {
+		return true
+	}
+	return false
+}

+ 70 - 0
unsafe_link.go

@@ -0,0 +1,70 @@
+package reflect2
+
+import "unsafe"
+
+//go:linkname unsafe_New reflect.unsafe_New
+func unsafe_New(rtype unsafe.Pointer) unsafe.Pointer
+
+//go:linkname typedmemmove reflect.typedmemmove
+func typedmemmove(rtype unsafe.Pointer, dst, src unsafe.Pointer)
+
+//go:linkname unsafe_NewArray reflect.unsafe_NewArray
+func unsafe_NewArray(rtype unsafe.Pointer, length int) unsafe.Pointer
+
+// typedslicecopy copies a slice of elemType values from src to dst,
+// returning the number of elements copied.
+//go:linkname typedslicecopy reflect.typedslicecopy
+//go:noescape
+func typedslicecopy(elemType unsafe.Pointer, dst, src sliceHeader) int
+
+//go:linkname mapassign reflect.mapassign
+//go:noescape
+func mapassign(rtype unsafe.Pointer, m unsafe.Pointer, key, val unsafe.Pointer)
+
+//go:linkname mapaccess reflect.mapaccess
+//go:noescape
+func mapaccess(rtype unsafe.Pointer, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer)
+
+// m escapes into the return value, but the caller of mapiterinit
+// doesn't let the return value escape.
+//go:noescape
+//go:linkname mapiterinit reflect.mapiterinit
+func mapiterinit(rtype unsafe.Pointer, m unsafe.Pointer) *hiter
+
+//go:noescape
+//go:linkname mapiternext reflect.mapiternext
+func mapiternext(it *hiter)
+
+//go:linkname ifaceE2I reflect.ifaceE2I
+func ifaceE2I(rtype unsafe.Pointer, src interface{}, dst unsafe.Pointer)
+
+// A hash iteration structure.
+// If you modify hiter, also change cmd/internal/gc/reflect.go to indicate
+// the layout of this structure.
+type hiter struct {
+	key   unsafe.Pointer // Must be in first position.  Write nil to indicate iteration end (see cmd/internal/gc/range.go).
+	value unsafe.Pointer // Must be in second position (see cmd/internal/gc/range.go).
+	// rest fields are ignored
+}
+
+// add 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 add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer {
+	return unsafe.Pointer(uintptr(p) + x)
+}
+
+// arrayAt returns the i-th element of p,
+// an array whose elements are eltSize bytes wide.
+// The array pointed at by p must have at least i+1 elements:
+// it is invalid (but impossible to check here) to pass i >= len,
+// because then the result will point outside the array.
+// whySafe must explain why i < len. (Passing "i < len" is fine;
+// the benefit is to surface this assumption at the call site.)
+func arrayAt(p unsafe.Pointer, i int, eltSize uintptr, whySafe string) unsafe.Pointer {
+	return add(p, uintptr(i)*eltSize, "i < len")
+}

+ 138 - 0
unsafe_map.go

@@ -0,0 +1,138 @@
+package reflect2
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+type UnsafeMapType struct {
+	unsafeType
+	pKeyRType  unsafe.Pointer
+	pElemRType unsafe.Pointer
+}
+
+func newUnsafeMapType(cfg *frozenConfig, type1 reflect.Type) MapType {
+	return &UnsafeMapType{
+		unsafeType: *newUnsafeType(cfg, type1),
+		pKeyRType:  unpackEFace(reflect.PtrTo(type1.Key())).data,
+		pElemRType: unpackEFace(reflect.PtrTo(type1.Elem())).data,
+	}
+}
+
+func (type2 *UnsafeMapType) IsNil(obj interface{}) bool {
+	if obj == nil {
+		return true
+	}
+	objEFace := unpackEFace(obj)
+	assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype)
+	return type2.UnsafeIsNil(objEFace.data)
+}
+
+func (type2 *UnsafeMapType) UnsafeIsNil(ptr unsafe.Pointer) bool {
+	if ptr == nil {
+		return true
+	}
+	return *(*unsafe.Pointer)(ptr) == nil
+}
+
+func (type2 *UnsafeMapType) LikePtr() bool {
+	return true
+}
+
+func (type2 *UnsafeMapType) Indirect(obj interface{}) interface{} {
+	objEFace := unpackEFace(obj)
+	assertType("MapType.Indirect argument 1", type2.ptrRType, objEFace.rtype)
+	return type2.UnsafeIndirect(objEFace.data)
+}
+
+func (type2 *UnsafeMapType) UnsafeIndirect(ptr unsafe.Pointer) interface{} {
+	return packEFace(type2.rtype, *(*unsafe.Pointer)(ptr))
+}
+
+func (type2 *UnsafeMapType) Key() Type {
+	return type2.cfg.Type2(type2.Type.Key())
+}
+
+func (type2 *UnsafeMapType) MakeMap(cap int) interface{} {
+	return packEFace(type2.ptrRType, type2.UnsafeMakeMap(cap))
+}
+
+func (type2 *UnsafeMapType) UnsafeMakeMap(cap int) unsafe.Pointer {
+	m := makeMapWithSize(type2.rtype, cap)
+	return unsafe.Pointer(&m)
+}
+
+func (type2 *UnsafeMapType) SetIndex(obj interface{}, key interface{}, elem interface{}) {
+	objEFace := unpackEFace(obj)
+	assertType("MapType.SetIndex argument 1", type2.ptrRType, objEFace.rtype)
+	keyEFace := unpackEFace(key)
+	assertType("MapType.SetIndex argument 2", type2.pKeyRType, keyEFace.rtype)
+	elemEFace := unpackEFace(elem)
+	assertType("MapType.SetIndex argument 3", type2.pElemRType, elemEFace.rtype)
+	type2.UnsafeSetIndex(objEFace.data, keyEFace.data, elemEFace.data)
+}
+
+func (type2 *UnsafeMapType) UnsafeSetIndex(obj unsafe.Pointer, key unsafe.Pointer, elem unsafe.Pointer) {
+	mapassign(type2.rtype, *(*unsafe.Pointer)(obj), key, elem)
+}
+
+func (type2 *UnsafeMapType) TryGetIndex(obj interface{}, key interface{}) (interface{}, bool) {
+	objEFace := unpackEFace(obj)
+	assertType("MapType.TryGetIndex argument 1", type2.ptrRType, objEFace.rtype)
+	keyEFace := unpackEFace(key)
+	assertType("MapType.TryGetIndex argument 2", type2.pKeyRType, keyEFace.rtype)
+	elemPtr := type2.UnsafeGetIndex(objEFace.data, keyEFace.data)
+	if elemPtr == nil {
+		return nil, false
+	}
+	return packEFace(type2.pElemRType, elemPtr), true
+}
+
+func (type2 *UnsafeMapType) GetIndex(obj interface{}, key interface{}) interface{} {
+	objEFace := unpackEFace(obj)
+	assertType("MapType.GetIndex argument 1", type2.ptrRType, objEFace.rtype)
+	keyEFace := unpackEFace(key)
+	assertType("MapType.GetIndex argument 2", type2.pKeyRType, keyEFace.rtype)
+	elemPtr := type2.UnsafeGetIndex(objEFace.data, keyEFace.data)
+	return packEFace(type2.pElemRType, elemPtr)
+}
+
+func (type2 *UnsafeMapType) UnsafeGetIndex(obj unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer {
+	return mapaccess(type2.rtype, *(*unsafe.Pointer)(obj), key)
+}
+
+func (type2 *UnsafeMapType) Iterate(obj interface{}) MapIterator {
+	objEFace := unpackEFace(obj)
+	assertType("MapType.Iterate argument 1", type2.ptrRType, objEFace.rtype)
+	return type2.UnsafeIterate(objEFace.data)
+}
+
+func (type2 *UnsafeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator {
+	return &UnsafeMapIterator{
+		hiter:      mapiterinit(type2.rtype, *(*unsafe.Pointer)(obj)),
+		pKeyRType:  type2.pKeyRType,
+		pElemRType: type2.pElemRType,
+	}
+}
+
+type UnsafeMapIterator struct {
+	*hiter
+	pKeyRType  unsafe.Pointer
+	pElemRType unsafe.Pointer
+}
+
+func (iter *UnsafeMapIterator) HasNext() bool {
+	return iter.key != nil
+}
+
+func (iter *UnsafeMapIterator) Next() (interface{}, interface{}) {
+	key, elem := iter.UnsafeNext()
+	return packEFace(iter.pKeyRType, key), packEFace(iter.pElemRType, elem)
+}
+
+func (iter *UnsafeMapIterator) UnsafeNext() (unsafe.Pointer, unsafe.Pointer) {
+	key := iter.key
+	elem := iter.value
+	mapiternext(iter.hiter)
+	return key, elem
+}

+ 46 - 0
unsafe_ptr.go

@@ -0,0 +1,46 @@
+package reflect2
+
+import (
+	"unsafe"
+	"reflect"
+)
+
+type UnsafePtrType struct {
+	unsafeType
+}
+
+func newUnsafePtrType(cfg *frozenConfig, type1 reflect.Type) *UnsafePtrType {
+	return &UnsafePtrType{
+		unsafeType: *newUnsafeType(cfg, type1),
+	}
+}
+
+func (type2 *UnsafePtrType) IsNil(obj interface{}) bool {
+	if obj == nil {
+		return true
+	}
+	objEFace := unpackEFace(obj)
+	assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype)
+	return type2.UnsafeIsNil(objEFace.data)
+}
+
+func (type2 *UnsafePtrType) UnsafeIsNil(ptr unsafe.Pointer) bool {
+	if ptr == nil {
+		return true
+	}
+	return *(*unsafe.Pointer)(ptr) == nil
+}
+
+func (type2 *UnsafePtrType) LikePtr() bool {
+	return true
+}
+
+func (type2 *UnsafePtrType) Indirect(obj interface{}) interface{} {
+	objEFace := unpackEFace(obj)
+	assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype)
+	return type2.UnsafeIndirect(objEFace.data)
+}
+
+func (type2 *UnsafePtrType) UnsafeIndirect(ptr unsafe.Pointer) interface{} {
+	return packEFace(type2.rtype, *(*unsafe.Pointer)(ptr))
+}

+ 177 - 0
unsafe_slice.go

@@ -0,0 +1,177 @@
+package reflect2
+
+import (
+	"unsafe"
+	"reflect"
+)
+
+// sliceHeader is a safe version of SliceHeader used within this package.
+type sliceHeader struct {
+	Data unsafe.Pointer
+	Len  int
+	Cap  int
+}
+
+type UnsafeSliceType struct {
+	unsafeType
+	elemRType  unsafe.Pointer
+	pElemRType unsafe.Pointer
+	elemSize   uintptr
+}
+
+func newUnsafeSliceType(cfg *frozenConfig, type1 reflect.Type) SliceType {
+	elemType := type1.Elem()
+	return &UnsafeSliceType{
+		unsafeType: *newUnsafeType(cfg, type1),
+		pElemRType: unpackEFace(reflect.PtrTo(elemType)).data,
+		elemRType:  unpackEFace(elemType).data,
+		elemSize:   elemType.Size(),
+	}
+}
+
+func (type2 *UnsafeSliceType) Set(obj interface{}, val interface{}) {
+	objEFace := unpackEFace(obj)
+	assertType("Type.Set argument 1", type2.ptrRType, objEFace.rtype)
+	valEFace := unpackEFace(val)
+	assertType("Type.Set argument 2", type2.ptrRType, valEFace.rtype)
+	type2.UnsafeSet(objEFace.data, valEFace.data)
+}
+
+func (type2 *UnsafeSliceType) UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer) {
+	*(*sliceHeader)(ptr) = *(*sliceHeader)(val)
+}
+
+func (type2 *UnsafeSliceType) IsNil(obj interface{}) bool {
+	if obj == nil {
+		return true
+	}
+	objEFace := unpackEFace(obj)
+	assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype)
+	return type2.UnsafeIsNil(objEFace.data)
+}
+
+func (type2 *UnsafeSliceType) UnsafeIsNil(ptr unsafe.Pointer) bool {
+	if ptr == nil {
+		return true
+	}
+	return (*sliceHeader)(ptr).Data == nil
+}
+
+func (type2 *UnsafeSliceType) SetNil(obj interface{}) {
+	objEFace := unpackEFace(obj)
+	assertType("SliceType.SetNil argument 1", type2.ptrRType, objEFace.rtype)
+	type2.UnsafeSetNil(objEFace.data)
+}
+
+func (type2 *UnsafeSliceType) UnsafeSetNil(ptr unsafe.Pointer) {
+	header := (*sliceHeader)(ptr)
+	header.Len = 0
+	header.Cap = 0
+	header.Data = nil
+}
+
+func (type2 *UnsafeSliceType) MakeSlice(length int, cap int) interface{} {
+	return packEFace(type2.ptrRType, type2.UnsafeMakeSlice(length, cap))
+}
+
+func (type2 *UnsafeSliceType) UnsafeMakeSlice(length int, cap int) unsafe.Pointer {
+	header := &sliceHeader{unsafe_NewArray(type2.elemRType, cap), length, cap}
+	return unsafe.Pointer(header)
+}
+
+func (type2 *UnsafeSliceType) LengthOf(obj interface{}) int {
+	objEFace := unpackEFace(obj)
+	assertType("SliceType.Len argument 1", type2.ptrRType, objEFace.rtype)
+	return type2.UnsafeLengthOf(objEFace.data)
+}
+
+func (type2 *UnsafeSliceType) UnsafeLengthOf(obj unsafe.Pointer) int {
+	header := (*sliceHeader)(obj)
+	return header.Len
+}
+
+func (type2 *UnsafeSliceType) SetIndex(obj interface{}, index int, elem interface{}) {
+	objEFace := unpackEFace(obj)
+	assertType("SliceType.SetIndex argument 1", type2.ptrRType, objEFace.rtype)
+	elemEFace := unpackEFace(elem)
+	assertType("SliceType.SetIndex argument 3", type2.pElemRType, elemEFace.rtype)
+	type2.UnsafeSetIndex(objEFace.data, index, elemEFace.data)
+}
+
+func (type2 *UnsafeSliceType) UnsafeSetIndex(obj unsafe.Pointer, index int, elem unsafe.Pointer) {
+	header := (*sliceHeader)(obj)
+	elemPtr := arrayAt(header.Data, index, type2.elemSize, "i < s.Len")
+	typedmemmove(type2.elemRType, elemPtr, elem)
+}
+
+func (type2 *UnsafeSliceType) GetIndex(obj interface{}, index int) interface{} {
+	objEFace := unpackEFace(obj)
+	assertType("SliceType.GetIndex argument 1", type2.ptrRType, objEFace.rtype)
+	elemPtr := type2.UnsafeGetIndex(objEFace.data, index)
+	return packEFace(type2.pElemRType, elemPtr)
+}
+
+func (type2 *UnsafeSliceType) UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer {
+	header := (*sliceHeader)(obj)
+	return arrayAt(header.Data, index, type2.elemSize, "i < s.Len")
+}
+
+func (type2 *UnsafeSliceType) Append(obj interface{}, elem interface{}) {
+	objEFace := unpackEFace(obj)
+	assertType("SliceType.Append argument 1", type2.ptrRType, objEFace.rtype)
+	elemEFace := unpackEFace(elem)
+	assertType("SliceType.Append argument 2", type2.pElemRType, elemEFace.rtype)
+	type2.UnsafeAppend(objEFace.data, elemEFace.data)
+}
+
+func (type2 *UnsafeSliceType) UnsafeAppend(obj unsafe.Pointer, elem unsafe.Pointer) {
+	header := (*sliceHeader)(obj)
+	oldLen := header.Len
+	type2.UnsafeGrow(obj, oldLen+1)
+	type2.UnsafeSetIndex(obj, oldLen, elem)
+}
+
+func (type2 *UnsafeSliceType) Cap(obj interface{}) int {
+	objEFace := unpackEFace(obj)
+	assertType("SliceType.Cap argument 1", type2.ptrRType, objEFace.rtype)
+	return type2.UnsafeCap(objEFace.data)
+}
+
+func (type2 *UnsafeSliceType) UnsafeCap(ptr unsafe.Pointer) int {
+	return (*sliceHeader)(ptr).Cap
+}
+
+func (type2 *UnsafeSliceType) Grow(obj interface{}, newLength int) {
+	objEFace := unpackEFace(obj)
+	assertType("SliceType.Grow argument 1", type2.ptrRType, objEFace.rtype)
+	type2.UnsafeGrow(objEFace.data, newLength)
+}
+
+func (type2 *UnsafeSliceType) UnsafeGrow(obj unsafe.Pointer, newLength int) {
+	header := (*sliceHeader)(obj)
+	if newLength <= header.Cap {
+		header.Len = newLength
+		return
+	}
+	newCap := calcNewCap(header.Cap, newLength)
+	newHeader := (*sliceHeader)(type2.UnsafeMakeSlice(header.Len, newCap))
+	typedslicecopy(type2.elemRType, *newHeader, *header)
+	header.Data = newHeader.Data
+	header.Cap = newHeader.Cap
+	header.Len = newLength
+}
+
+func calcNewCap(cap int, expectedCap int) int {
+	if cap == 0 {
+		cap = expectedCap
+	} else {
+		for cap < expectedCap {
+			if cap < 1024 {
+				cap += cap
+			} else {
+				cap += cap / 4
+			}
+		}
+	}
+	return cap
+}

+ 59 - 0
unsafe_struct.go

@@ -0,0 +1,59 @@
+package reflect2
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+type UnsafeStructType struct {
+	unsafeType
+	likePtr bool
+}
+
+func newUnsafeStructType(cfg *frozenConfig, type1 reflect.Type) *UnsafeStructType {
+	return &UnsafeStructType{
+		unsafeType: *newUnsafeType(cfg, type1),
+		likePtr:    likePtrType(type1),
+	}
+}
+
+func (type2 *UnsafeStructType) LikePtr() bool {
+	return type2.likePtr
+}
+
+func (type2 *UnsafeStructType) Indirect(obj interface{}) interface{} {
+	objEFace := unpackEFace(obj)
+	assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype)
+	return type2.UnsafeIndirect(objEFace.data)
+}
+
+func (type2 *UnsafeStructType) UnsafeIndirect(ptr unsafe.Pointer) interface{} {
+	if type2.likePtr {
+		return packEFace(type2.rtype, *(*unsafe.Pointer)(ptr))
+	}
+	return packEFace(type2.rtype, ptr)
+}
+
+func (type2 *UnsafeStructType) FieldByName(name string) StructField {
+	structField, found := type2.Type.FieldByName(name)
+	if !found {
+		return nil
+	}
+	return newUnsafeStructField(type2, structField)
+}
+
+func (type2 *UnsafeStructType) Field(i int) StructField {
+	return newUnsafeStructField(type2, type2.Type.Field(i))
+}
+
+func (type2 *UnsafeStructType) FieldByIndex(index []int) StructField {
+	return newUnsafeStructField(type2, type2.Type.FieldByIndex(index))
+}
+
+func (type2 *UnsafeStructType) FieldByNameFunc(match func(string) bool) StructField {
+	structField, found := type2.Type.FieldByNameFunc(match)
+	if !found {
+		panic("field match condition not found in " + type2.Type.String())
+	}
+	return newUnsafeStructField(type2, structField)
+}

+ 85 - 0
unsafe_type.go

@@ -0,0 +1,85 @@
+package reflect2
+
+import (
+	"unsafe"
+	"reflect"
+)
+
+type unsafeType struct {
+	safeType
+	rtype    unsafe.Pointer
+	ptrRType unsafe.Pointer
+}
+
+func newUnsafeType(cfg *frozenConfig, type1 reflect.Type) *unsafeType {
+	return &unsafeType{
+		safeType: safeType{
+			Type: type1,
+			cfg: cfg,
+		},
+		rtype:    unpackEFace(type1).data,
+		ptrRType: unpackEFace(reflect.PtrTo(type1)).data,
+	}
+}
+
+func (type2 *unsafeType) Set(obj interface{}, val interface{}) {
+	objEFace := unpackEFace(obj)
+	assertType("Type.Set argument 1", type2.ptrRType, objEFace.rtype)
+	valEFace := unpackEFace(val)
+	assertType("Type.Set argument 2", type2.ptrRType, valEFace.rtype)
+	type2.UnsafeSet(objEFace.data, valEFace.data)
+}
+
+func (type2 *unsafeType) UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer) {
+	typedmemmove(type2.rtype, ptr, val)
+}
+
+func (type2 *unsafeType) IsNil(obj interface{}) bool {
+	objEFace := unpackEFace(obj)
+	assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype)
+	return type2.UnsafeIsNil(objEFace.data)
+}
+
+func (type2 *unsafeType) UnsafeIsNil(ptr unsafe.Pointer) bool {
+	return ptr == nil
+}
+
+func (type2 *unsafeType) UnsafeNew() unsafe.Pointer {
+	return unsafe_New(type2.rtype)
+}
+
+func (type2 *unsafeType) New() interface{} {
+	return packEFace(type2.ptrRType, type2.UnsafeNew())
+}
+
+func (type2 *unsafeType) PackEFace(ptr unsafe.Pointer) interface{} {
+	return packEFace(type2.ptrRType, ptr)
+}
+
+func (type2 *unsafeType) RType() uintptr {
+	return uintptr(type2.rtype)
+}
+
+func (type2 *unsafeType) Indirect(obj interface{}) interface{} {
+	objEFace := unpackEFace(obj)
+	assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype)
+	return type2.UnsafeIndirect(objEFace.data)
+}
+
+func (type2 *unsafeType) UnsafeIndirect(obj unsafe.Pointer) interface{} {
+	return packEFace(type2.rtype, obj)
+}
+
+func (type2 *unsafeType) LikePtr() bool {
+	return false
+}
+
+func assertType(where string, expectRType unsafe.Pointer, actualRType unsafe.Pointer) {
+	if expectRType != actualRType {
+		expectType := reflect.TypeOf(0)
+		(*iface)(unsafe.Pointer(&expectType)).data = expectRType
+		actualType := reflect.TypeOf(0)
+		(*iface)(unsafe.Pointer(&actualType)).data = actualRType
+		panic(where + ": expect " + expectType.String() + ", actual " + actualType.String())
+	}
+}