├── .gitignore ├── .travis.yml ├── Gopkg.lock ├── Gopkg.toml ├── LICENSE ├── README.md ├── go.mod ├── go_above_118.go ├── go_above_19.go ├── go_below_118.go ├── reflect2.go ├── reflect2_amd64.s ├── reflect2_kind.go ├── relfect2_386.s ├── relfect2_amd64p32.s ├── relfect2_arm.s ├── relfect2_arm64.s ├── relfect2_mips64x.s ├── relfect2_mipsx.s ├── relfect2_ppc64x.s ├── relfect2_s390x.s ├── safe_field.go ├── safe_map.go ├── safe_slice.go ├── safe_struct.go ├── safe_type.go ├── type_map.go ├── unsafe_array.go ├── unsafe_eface.go ├── unsafe_field.go ├── unsafe_iface.go ├── unsafe_link.go ├── unsafe_map.go ├── unsafe_ptr.go ├── unsafe_slice.go ├── unsafe_struct.go └── unsafe_type.go /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /coverage.txt 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.9.x 5 | - 1.x 6 | 7 | before_install: 8 | - go get -t -v ./... 9 | - go get -t -v github.com/modern-go/reflect2-tests/... 10 | 11 | script: 12 | - ./test.sh 13 | 14 | after_success: 15 | - bash <(curl -s https://codecov.io/bash) 16 | -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [solve-meta] 5 | analyzer-name = "dep" 6 | analyzer-version = 1 7 | input-imports = [] 8 | solver-name = "gps-cdcl" 9 | solver-version = 1 10 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | # Gopkg.toml example 2 | # 3 | # Refer to https://golang.github.io/dep/docs/Gopkg.toml.html 4 | # for detailed Gopkg.toml documentation. 5 | # 6 | # required = ["github.com/user/thing/cmd/thing"] 7 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] 8 | # 9 | # [[constraint]] 10 | # name = "github.com/user/project" 11 | # version = "1.0.0" 12 | # 13 | # [[constraint]] 14 | # name = "github.com/user/project2" 15 | # branch = "dev" 16 | # source = "github.com/myfork/project2" 17 | # 18 | # [[override]] 19 | # name = "github.com/x/y" 20 | # version = "2.4.0" 21 | # 22 | # [prune] 23 | # non-go = false 24 | # go-tests = true 25 | # unused-packages = true 26 | 27 | ignored = [] 28 | 29 | [prune] 30 | go-tests = true 31 | unused-packages = true 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # reflect2 2 | 3 | [![Sourcegraph](https://sourcegraph.com/github.com/modern-go/reflect2/-/badge.svg)](https://sourcegraph.com/github.com/modern-go/reflect2?badge) 4 | [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/modern-go/reflect2) 5 | [![Build Status](https://travis-ci.org/modern-go/reflect2.svg?branch=master)](https://travis-ci.org/modern-go/reflect2) 6 | [![codecov](https://codecov.io/gh/modern-go/reflect2/branch/master/graph/badge.svg)](https://codecov.io/gh/modern-go/reflect2) 7 | [![rcard](https://goreportcard.com/badge/github.com/modern-go/reflect2)](https://goreportcard.com/report/github.com/modern-go/reflect2) 8 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://raw.githubusercontent.com/modern-go/reflect2/master/LICENSE) 9 | 10 | reflect api that avoids runtime reflect.Value cost 11 | 12 | * reflect get/set interface{}, with type checking 13 | * reflect get/set unsafe.Pointer, without type checking 14 | * `reflect2.TypeByName` works like `Class.forName` found in java 15 | 16 | [json-iterator](https://github.com/json-iterator/go) use this package to save runtime dispatching cost. 17 | This package is designed for low level libraries to optimize reflection performance. 18 | General application should still use reflect standard library. 19 | 20 | # reflect2.TypeByName 21 | 22 | ```go 23 | // given package is github.com/your/awesome-package 24 | type MyStruct struct { 25 | // ... 26 | } 27 | 28 | // will return the type 29 | reflect2.TypeByName("awesome-package.MyStruct") 30 | // however, if the type has not been used 31 | // it will be eliminated by compiler, so we can not get it in runtime 32 | ``` 33 | 34 | # reflect2 get/set interface{} 35 | 36 | ```go 37 | valType := reflect2.TypeOf(1) 38 | i := 1 39 | j := 10 40 | valType.Set(&i, &j) 41 | // i will be 10 42 | ``` 43 | 44 | to get set `type`, always use its pointer `*type` 45 | 46 | # reflect2 get/set unsafe.Pointer 47 | 48 | ```go 49 | valType := reflect2.TypeOf(1) 50 | i := 1 51 | j := 10 52 | valType.UnsafeSet(unsafe.Pointer(&i), unsafe.Pointer(&j)) 53 | // i will be 10 54 | ``` 55 | 56 | to get set `type`, always use its pointer `*type` 57 | 58 | # benchmark 59 | 60 | Benchmark is not necessary for this package. It does nothing actually. 61 | As it is just a thin wrapper to make go runtime public. 62 | Both `reflect2` and `reflect` call same function 63 | provided by `runtime` package exposed by go language. 64 | 65 | # unsafe safety 66 | 67 | Instead of casting `[]byte` to `sliceHeader` in your application using unsafe. 68 | We can use reflect2 instead. This way, if `sliceHeader` changes in the future, 69 | only reflect2 need to be upgraded. 70 | 71 | reflect2 tries its best to keep the implementation same as reflect (by testing). -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/modern-go/reflect2 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /go_above_118.go: -------------------------------------------------------------------------------- 1 | //+build go1.18 2 | 3 | package reflect2 4 | 5 | import ( 6 | "unsafe" 7 | ) 8 | 9 | // m escapes into the return value, but the caller of mapiterinit 10 | // doesn't let the return value escape. 11 | //go:noescape 12 | //go:linkname mapiterinit reflect.mapiterinit 13 | func mapiterinit(rtype unsafe.Pointer, m unsafe.Pointer, it *hiter) 14 | 15 | func (type2 *UnsafeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator { 16 | var it hiter 17 | mapiterinit(type2.rtype, *(*unsafe.Pointer)(obj), &it) 18 | return &UnsafeMapIterator{ 19 | hiter: &it, 20 | pKeyRType: type2.pKeyRType, 21 | pElemRType: type2.pElemRType, 22 | } 23 | } -------------------------------------------------------------------------------- /go_above_19.go: -------------------------------------------------------------------------------- 1 | //+build go1.9 2 | 3 | package reflect2 4 | 5 | import ( 6 | "unsafe" 7 | ) 8 | 9 | //go:linkname resolveTypeOff reflect.resolveTypeOff 10 | func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer 11 | 12 | //go:linkname makemap reflect.makemap 13 | func makemap(rtype unsafe.Pointer, cap int) (m unsafe.Pointer) 14 | 15 | func makeMapWithSize(rtype unsafe.Pointer, cap int) unsafe.Pointer { 16 | return makemap(rtype, cap) 17 | } 18 | -------------------------------------------------------------------------------- /go_below_118.go: -------------------------------------------------------------------------------- 1 | //+build !go1.18 2 | 3 | package reflect2 4 | 5 | import ( 6 | "unsafe" 7 | ) 8 | 9 | // m escapes into the return value, but the caller of mapiterinit 10 | // doesn't let the return value escape. 11 | //go:noescape 12 | //go:linkname mapiterinit reflect.mapiterinit 13 | func mapiterinit(rtype unsafe.Pointer, m unsafe.Pointer) (val *hiter) 14 | 15 | func (type2 *UnsafeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator { 16 | return &UnsafeMapIterator{ 17 | hiter: mapiterinit(type2.rtype, *(*unsafe.Pointer)(obj)), 18 | pKeyRType: type2.pKeyRType, 19 | pElemRType: type2.pElemRType, 20 | } 21 | } -------------------------------------------------------------------------------- /reflect2.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | import ( 4 | "reflect" 5 | "runtime" 6 | "sync" 7 | "unsafe" 8 | ) 9 | 10 | type Type interface { 11 | Kind() reflect.Kind 12 | // New return pointer to data of this type 13 | New() interface{} 14 | // UnsafeNew return the allocated space pointed by unsafe.Pointer 15 | UnsafeNew() unsafe.Pointer 16 | // PackEFace cast a unsafe pointer to object represented pointer 17 | PackEFace(ptr unsafe.Pointer) interface{} 18 | // Indirect dereference object represented pointer to this type 19 | Indirect(obj interface{}) interface{} 20 | // UnsafeIndirect dereference pointer to this type 21 | UnsafeIndirect(ptr unsafe.Pointer) interface{} 22 | // Type1 returns reflect.Type 23 | Type1() reflect.Type 24 | Implements(thatType Type) bool 25 | String() string 26 | RType() uintptr 27 | // interface{} of this type has pointer like behavior 28 | LikePtr() bool 29 | IsNullable() bool 30 | IsNil(obj interface{}) bool 31 | UnsafeIsNil(ptr unsafe.Pointer) bool 32 | Set(obj interface{}, val interface{}) 33 | UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer) 34 | AssignableTo(anotherType Type) bool 35 | } 36 | 37 | type ListType interface { 38 | Type 39 | Elem() Type 40 | SetIndex(obj interface{}, index int, elem interface{}) 41 | UnsafeSetIndex(obj unsafe.Pointer, index int, elem unsafe.Pointer) 42 | GetIndex(obj interface{}, index int) interface{} 43 | UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer 44 | } 45 | 46 | type ArrayType interface { 47 | ListType 48 | Len() int 49 | } 50 | 51 | type SliceType interface { 52 | ListType 53 | MakeSlice(length int, cap int) interface{} 54 | UnsafeMakeSlice(length int, cap int) unsafe.Pointer 55 | Grow(obj interface{}, newLength int) 56 | UnsafeGrow(ptr unsafe.Pointer, newLength int) 57 | Append(obj interface{}, elem interface{}) 58 | UnsafeAppend(obj unsafe.Pointer, elem unsafe.Pointer) 59 | LengthOf(obj interface{}) int 60 | UnsafeLengthOf(ptr unsafe.Pointer) int 61 | SetNil(obj interface{}) 62 | UnsafeSetNil(ptr unsafe.Pointer) 63 | Cap(obj interface{}) int 64 | UnsafeCap(ptr unsafe.Pointer) int 65 | } 66 | 67 | type StructType interface { 68 | Type 69 | NumField() int 70 | Field(i int) StructField 71 | FieldByName(name string) StructField 72 | FieldByIndex(index []int) StructField 73 | FieldByNameFunc(match func(string) bool) StructField 74 | } 75 | 76 | type StructField interface { 77 | Offset() uintptr 78 | Name() string 79 | PkgPath() string 80 | Type() Type 81 | Tag() reflect.StructTag 82 | Index() []int 83 | Anonymous() bool 84 | Set(obj interface{}, value interface{}) 85 | UnsafeSet(obj unsafe.Pointer, value unsafe.Pointer) 86 | Get(obj interface{}) interface{} 87 | UnsafeGet(obj unsafe.Pointer) unsafe.Pointer 88 | } 89 | 90 | type MapType interface { 91 | Type 92 | Key() Type 93 | Elem() Type 94 | MakeMap(cap int) interface{} 95 | UnsafeMakeMap(cap int) unsafe.Pointer 96 | SetIndex(obj interface{}, key interface{}, elem interface{}) 97 | UnsafeSetIndex(obj unsafe.Pointer, key unsafe.Pointer, elem unsafe.Pointer) 98 | TryGetIndex(obj interface{}, key interface{}) (interface{}, bool) 99 | GetIndex(obj interface{}, key interface{}) interface{} 100 | UnsafeGetIndex(obj unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer 101 | Iterate(obj interface{}) MapIterator 102 | UnsafeIterate(obj unsafe.Pointer) MapIterator 103 | } 104 | 105 | type MapIterator interface { 106 | HasNext() bool 107 | Next() (key interface{}, elem interface{}) 108 | UnsafeNext() (key unsafe.Pointer, elem unsafe.Pointer) 109 | } 110 | 111 | type PtrType interface { 112 | Type 113 | Elem() Type 114 | } 115 | 116 | type InterfaceType interface { 117 | NumMethod() int 118 | } 119 | 120 | type Config struct { 121 | UseSafeImplementation bool 122 | } 123 | 124 | type API interface { 125 | TypeOf(obj interface{}) Type 126 | Type2(type1 reflect.Type) Type 127 | } 128 | 129 | var ConfigUnsafe = Config{UseSafeImplementation: false}.Froze() 130 | var ConfigSafe = Config{UseSafeImplementation: true}.Froze() 131 | 132 | type frozenConfig struct { 133 | useSafeImplementation bool 134 | cache *sync.Map 135 | } 136 | 137 | func (cfg Config) Froze() *frozenConfig { 138 | return &frozenConfig{ 139 | useSafeImplementation: cfg.UseSafeImplementation, 140 | cache: new(sync.Map), 141 | } 142 | } 143 | 144 | func (cfg *frozenConfig) TypeOf(obj interface{}) Type { 145 | cacheKey := uintptr(unpackEFace(obj).rtype) 146 | typeObj, found := cfg.cache.Load(cacheKey) 147 | if found { 148 | return typeObj.(Type) 149 | } 150 | return cfg.Type2(reflect.TypeOf(obj)) 151 | } 152 | 153 | func (cfg *frozenConfig) Type2(type1 reflect.Type) Type { 154 | if type1 == nil { 155 | return nil 156 | } 157 | cacheKey := uintptr(unpackEFace(type1).data) 158 | typeObj, found := cfg.cache.Load(cacheKey) 159 | if found { 160 | return typeObj.(Type) 161 | } 162 | type2 := cfg.wrapType(type1) 163 | cfg.cache.Store(cacheKey, type2) 164 | return type2 165 | } 166 | 167 | func (cfg *frozenConfig) wrapType(type1 reflect.Type) Type { 168 | safeType := safeType{Type: type1, cfg: cfg} 169 | switch type1.Kind() { 170 | case reflect.Struct: 171 | if cfg.useSafeImplementation { 172 | return &safeStructType{safeType} 173 | } 174 | return newUnsafeStructType(cfg, type1) 175 | case reflect.Array: 176 | if cfg.useSafeImplementation { 177 | return &safeSliceType{safeType} 178 | } 179 | return newUnsafeArrayType(cfg, type1) 180 | case reflect.Slice: 181 | if cfg.useSafeImplementation { 182 | return &safeSliceType{safeType} 183 | } 184 | return newUnsafeSliceType(cfg, type1) 185 | case reflect.Map: 186 | if cfg.useSafeImplementation { 187 | return &safeMapType{safeType} 188 | } 189 | return newUnsafeMapType(cfg, type1) 190 | case reflect.Ptr, reflect.Chan, reflect.Func: 191 | if cfg.useSafeImplementation { 192 | return &safeMapType{safeType} 193 | } 194 | return newUnsafePtrType(cfg, type1) 195 | case reflect.Interface: 196 | if cfg.useSafeImplementation { 197 | return &safeMapType{safeType} 198 | } 199 | if type1.NumMethod() == 0 { 200 | return newUnsafeEFaceType(cfg, type1) 201 | } 202 | return newUnsafeIFaceType(cfg, type1) 203 | default: 204 | if cfg.useSafeImplementation { 205 | return &safeType 206 | } 207 | return newUnsafeType(cfg, type1) 208 | } 209 | } 210 | 211 | func TypeOf(obj interface{}) Type { 212 | return ConfigUnsafe.TypeOf(obj) 213 | } 214 | 215 | func TypeOfPtr(obj interface{}) PtrType { 216 | return TypeOf(obj).(PtrType) 217 | } 218 | 219 | func Type2(type1 reflect.Type) Type { 220 | if type1 == nil { 221 | return nil 222 | } 223 | return ConfigUnsafe.Type2(type1) 224 | } 225 | 226 | func PtrTo(typ Type) Type { 227 | return Type2(reflect.PtrTo(typ.Type1())) 228 | } 229 | 230 | func PtrOf(obj interface{}) unsafe.Pointer { 231 | return unpackEFace(obj).data 232 | } 233 | 234 | func RTypeOf(obj interface{}) uintptr { 235 | return uintptr(unpackEFace(obj).rtype) 236 | } 237 | 238 | func IsNil(obj interface{}) bool { 239 | if obj == nil { 240 | return true 241 | } 242 | return unpackEFace(obj).data == nil 243 | } 244 | 245 | func IsNullable(kind reflect.Kind) bool { 246 | switch kind { 247 | case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func, reflect.Slice, reflect.Interface: 248 | return true 249 | } 250 | return false 251 | } 252 | 253 | func likePtrKind(kind reflect.Kind) bool { 254 | switch kind { 255 | case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func: 256 | return true 257 | } 258 | return false 259 | } 260 | 261 | func likePtrType(typ reflect.Type) bool { 262 | if likePtrKind(typ.Kind()) { 263 | return true 264 | } 265 | if typ.Kind() == reflect.Struct { 266 | if typ.NumField() != 1 { 267 | return false 268 | } 269 | return likePtrType(typ.Field(0).Type) 270 | } 271 | if typ.Kind() == reflect.Array { 272 | if typ.Len() != 1 { 273 | return false 274 | } 275 | return likePtrType(typ.Elem()) 276 | } 277 | return false 278 | } 279 | 280 | // NoEscape hides a pointer from escape analysis. noescape is 281 | // the identity function but escape analysis doesn't think the 282 | // output depends on the input. noescape is inlined and currently 283 | // compiles down to zero instructions. 284 | // USE CAREFULLY! 285 | //go:nosplit 286 | func NoEscape(p unsafe.Pointer) unsafe.Pointer { 287 | x := uintptr(p) 288 | return unsafe.Pointer(x ^ 0) 289 | } 290 | 291 | func UnsafeCastString(str string) []byte { 292 | bytes := make([]byte, 0) 293 | stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&str)) 294 | sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&bytes)) 295 | sliceHeader.Data = stringHeader.Data 296 | sliceHeader.Cap = stringHeader.Len 297 | sliceHeader.Len = stringHeader.Len 298 | runtime.KeepAlive(str) 299 | return bytes 300 | } 301 | -------------------------------------------------------------------------------- /reflect2_amd64.s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modern-go/reflect2/35a7c28c31ee079903db043180532306a621943a/reflect2_amd64.s -------------------------------------------------------------------------------- /reflect2_kind.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | import ( 4 | "reflect" 5 | "unsafe" 6 | ) 7 | 8 | // DefaultTypeOfKind return the non aliased default type for the kind 9 | func DefaultTypeOfKind(kind reflect.Kind) Type { 10 | return kindTypes[kind] 11 | } 12 | 13 | var kindTypes = map[reflect.Kind]Type{ 14 | reflect.Bool: TypeOf(true), 15 | reflect.Uint8: TypeOf(uint8(0)), 16 | reflect.Int8: TypeOf(int8(0)), 17 | reflect.Uint16: TypeOf(uint16(0)), 18 | reflect.Int16: TypeOf(int16(0)), 19 | reflect.Uint32: TypeOf(uint32(0)), 20 | reflect.Int32: TypeOf(int32(0)), 21 | reflect.Uint64: TypeOf(uint64(0)), 22 | reflect.Int64: TypeOf(int64(0)), 23 | reflect.Uint: TypeOf(uint(0)), 24 | reflect.Int: TypeOf(int(0)), 25 | reflect.Float32: TypeOf(float32(0)), 26 | reflect.Float64: TypeOf(float64(0)), 27 | reflect.Uintptr: TypeOf(uintptr(0)), 28 | reflect.String: TypeOf(""), 29 | reflect.UnsafePointer: TypeOf(unsafe.Pointer(nil)), 30 | } 31 | -------------------------------------------------------------------------------- /relfect2_386.s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modern-go/reflect2/35a7c28c31ee079903db043180532306a621943a/relfect2_386.s -------------------------------------------------------------------------------- /relfect2_amd64p32.s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modern-go/reflect2/35a7c28c31ee079903db043180532306a621943a/relfect2_amd64p32.s -------------------------------------------------------------------------------- /relfect2_arm.s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modern-go/reflect2/35a7c28c31ee079903db043180532306a621943a/relfect2_arm.s -------------------------------------------------------------------------------- /relfect2_arm64.s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modern-go/reflect2/35a7c28c31ee079903db043180532306a621943a/relfect2_arm64.s -------------------------------------------------------------------------------- /relfect2_mips64x.s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modern-go/reflect2/35a7c28c31ee079903db043180532306a621943a/relfect2_mips64x.s -------------------------------------------------------------------------------- /relfect2_mipsx.s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modern-go/reflect2/35a7c28c31ee079903db043180532306a621943a/relfect2_mipsx.s -------------------------------------------------------------------------------- /relfect2_ppc64x.s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modern-go/reflect2/35a7c28c31ee079903db043180532306a621943a/relfect2_ppc64x.s -------------------------------------------------------------------------------- /relfect2_s390x.s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modern-go/reflect2/35a7c28c31ee079903db043180532306a621943a/relfect2_s390x.s -------------------------------------------------------------------------------- /safe_field.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | import ( 4 | "reflect" 5 | "unsafe" 6 | ) 7 | 8 | type safeField struct { 9 | reflect.StructField 10 | } 11 | 12 | func (field *safeField) Offset() uintptr { 13 | return field.StructField.Offset 14 | } 15 | 16 | func (field *safeField) Name() string { 17 | return field.StructField.Name 18 | } 19 | 20 | func (field *safeField) PkgPath() string { 21 | return field.StructField.PkgPath 22 | } 23 | 24 | func (field *safeField) Type() Type { 25 | panic("not implemented") 26 | } 27 | 28 | func (field *safeField) Tag() reflect.StructTag { 29 | return field.StructField.Tag 30 | } 31 | 32 | func (field *safeField) Index() []int { 33 | return field.StructField.Index 34 | } 35 | 36 | func (field *safeField) Anonymous() bool { 37 | return field.StructField.Anonymous 38 | } 39 | 40 | func (field *safeField) Set(obj interface{}, value interface{}) { 41 | val := reflect.ValueOf(obj).Elem() 42 | val.FieldByIndex(field.Index()).Set(reflect.ValueOf(value).Elem()) 43 | } 44 | 45 | func (field *safeField) UnsafeSet(obj unsafe.Pointer, value unsafe.Pointer) { 46 | panic("unsafe operation is not supported") 47 | } 48 | 49 | func (field *safeField) Get(obj interface{}) interface{} { 50 | val := reflect.ValueOf(obj).Elem().FieldByIndex(field.Index()) 51 | ptr := reflect.New(val.Type()) 52 | ptr.Elem().Set(val) 53 | return ptr.Interface() 54 | } 55 | 56 | func (field *safeField) UnsafeGet(obj unsafe.Pointer) unsafe.Pointer { 57 | panic("does not support unsafe operation") 58 | } 59 | -------------------------------------------------------------------------------- /safe_map.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | import ( 4 | "reflect" 5 | "unsafe" 6 | ) 7 | 8 | type safeMapType struct { 9 | safeType 10 | } 11 | 12 | func (type2 *safeMapType) Key() Type { 13 | return type2.safeType.cfg.Type2(type2.Type.Key()) 14 | } 15 | 16 | func (type2 *safeMapType) MakeMap(cap int) interface{} { 17 | ptr := reflect.New(type2.Type) 18 | ptr.Elem().Set(reflect.MakeMap(type2.Type)) 19 | return ptr.Interface() 20 | } 21 | 22 | func (type2 *safeMapType) UnsafeMakeMap(cap int) unsafe.Pointer { 23 | panic("does not support unsafe operation") 24 | } 25 | 26 | func (type2 *safeMapType) SetIndex(obj interface{}, key interface{}, elem interface{}) { 27 | keyVal := reflect.ValueOf(key) 28 | elemVal := reflect.ValueOf(elem) 29 | val := reflect.ValueOf(obj) 30 | val.Elem().SetMapIndex(keyVal.Elem(), elemVal.Elem()) 31 | } 32 | 33 | func (type2 *safeMapType) UnsafeSetIndex(obj unsafe.Pointer, key unsafe.Pointer, elem unsafe.Pointer) { 34 | panic("does not support unsafe operation") 35 | } 36 | 37 | func (type2 *safeMapType) TryGetIndex(obj interface{}, key interface{}) (interface{}, bool) { 38 | keyVal := reflect.ValueOf(key) 39 | if key == nil { 40 | keyVal = reflect.New(type2.Type.Key()).Elem() 41 | } 42 | val := reflect.ValueOf(obj).MapIndex(keyVal) 43 | if !val.IsValid() { 44 | return nil, false 45 | } 46 | return val.Interface(), true 47 | } 48 | 49 | func (type2 *safeMapType) GetIndex(obj interface{}, key interface{}) interface{} { 50 | val := reflect.ValueOf(obj).Elem() 51 | keyVal := reflect.ValueOf(key).Elem() 52 | elemVal := val.MapIndex(keyVal) 53 | if !elemVal.IsValid() { 54 | ptr := reflect.New(reflect.PtrTo(val.Type().Elem())) 55 | return ptr.Elem().Interface() 56 | } 57 | ptr := reflect.New(elemVal.Type()) 58 | ptr.Elem().Set(elemVal) 59 | return ptr.Interface() 60 | } 61 | 62 | func (type2 *safeMapType) UnsafeGetIndex(obj unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer { 63 | panic("does not support unsafe operation") 64 | } 65 | 66 | func (type2 *safeMapType) Iterate(obj interface{}) MapIterator { 67 | m := reflect.ValueOf(obj).Elem() 68 | return &safeMapIterator{ 69 | m: m, 70 | keys: m.MapKeys(), 71 | } 72 | } 73 | 74 | func (type2 *safeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator { 75 | panic("does not support unsafe operation") 76 | } 77 | 78 | type safeMapIterator struct { 79 | i int 80 | m reflect.Value 81 | keys []reflect.Value 82 | } 83 | 84 | func (iter *safeMapIterator) HasNext() bool { 85 | return iter.i != len(iter.keys) 86 | } 87 | 88 | func (iter *safeMapIterator) Next() (interface{}, interface{}) { 89 | key := iter.keys[iter.i] 90 | elem := iter.m.MapIndex(key) 91 | iter.i += 1 92 | keyPtr := reflect.New(key.Type()) 93 | keyPtr.Elem().Set(key) 94 | elemPtr := reflect.New(elem.Type()) 95 | elemPtr.Elem().Set(elem) 96 | return keyPtr.Interface(), elemPtr.Interface() 97 | } 98 | 99 | func (iter *safeMapIterator) UnsafeNext() (unsafe.Pointer, unsafe.Pointer) { 100 | panic("does not support unsafe operation") 101 | } 102 | -------------------------------------------------------------------------------- /safe_slice.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | import ( 4 | "reflect" 5 | "unsafe" 6 | ) 7 | 8 | type safeSliceType struct { 9 | safeType 10 | } 11 | 12 | func (type2 *safeSliceType) SetIndex(obj interface{}, index int, value interface{}) { 13 | val := reflect.ValueOf(obj).Elem() 14 | elem := reflect.ValueOf(value).Elem() 15 | val.Index(index).Set(elem) 16 | } 17 | 18 | func (type2 *safeSliceType) UnsafeSetIndex(obj unsafe.Pointer, index int, value unsafe.Pointer) { 19 | panic("does not support unsafe operation") 20 | } 21 | 22 | func (type2 *safeSliceType) GetIndex(obj interface{}, index int) interface{} { 23 | val := reflect.ValueOf(obj).Elem() 24 | elem := val.Index(index) 25 | ptr := reflect.New(elem.Type()) 26 | ptr.Elem().Set(elem) 27 | return ptr.Interface() 28 | } 29 | 30 | func (type2 *safeSliceType) UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer { 31 | panic("does not support unsafe operation") 32 | } 33 | 34 | func (type2 *safeSliceType) MakeSlice(length int, cap int) interface{} { 35 | val := reflect.MakeSlice(type2.Type, length, cap) 36 | ptr := reflect.New(val.Type()) 37 | ptr.Elem().Set(val) 38 | return ptr.Interface() 39 | } 40 | 41 | func (type2 *safeSliceType) UnsafeMakeSlice(length int, cap int) unsafe.Pointer { 42 | panic("does not support unsafe operation") 43 | } 44 | 45 | func (type2 *safeSliceType) Grow(obj interface{}, newLength int) { 46 | oldCap := type2.Cap(obj) 47 | oldSlice := reflect.ValueOf(obj).Elem() 48 | delta := newLength - oldCap 49 | deltaVals := make([]reflect.Value, delta) 50 | newSlice := reflect.Append(oldSlice, deltaVals...) 51 | oldSlice.Set(newSlice) 52 | } 53 | 54 | func (type2 *safeSliceType) UnsafeGrow(ptr unsafe.Pointer, newLength int) { 55 | panic("does not support unsafe operation") 56 | } 57 | 58 | func (type2 *safeSliceType) Append(obj interface{}, elem interface{}) { 59 | val := reflect.ValueOf(obj).Elem() 60 | elemVal := reflect.ValueOf(elem).Elem() 61 | newVal := reflect.Append(val, elemVal) 62 | val.Set(newVal) 63 | } 64 | 65 | func (type2 *safeSliceType) UnsafeAppend(obj unsafe.Pointer, elem unsafe.Pointer) { 66 | panic("does not support unsafe operation") 67 | } 68 | 69 | func (type2 *safeSliceType) SetNil(obj interface{}) { 70 | val := reflect.ValueOf(obj).Elem() 71 | val.Set(reflect.Zero(val.Type())) 72 | } 73 | 74 | func (type2 *safeSliceType) UnsafeSetNil(ptr unsafe.Pointer) { 75 | panic("does not support unsafe operation") 76 | } 77 | 78 | func (type2 *safeSliceType) LengthOf(obj interface{}) int { 79 | return reflect.ValueOf(obj).Elem().Len() 80 | } 81 | 82 | func (type2 *safeSliceType) UnsafeLengthOf(ptr unsafe.Pointer) int { 83 | panic("does not support unsafe operation") 84 | } 85 | 86 | func (type2 *safeSliceType) Cap(obj interface{}) int { 87 | return reflect.ValueOf(obj).Elem().Cap() 88 | } 89 | 90 | func (type2 *safeSliceType) UnsafeCap(ptr unsafe.Pointer) int { 91 | panic("does not support unsafe operation") 92 | } 93 | -------------------------------------------------------------------------------- /safe_struct.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | type safeStructType struct { 4 | safeType 5 | } 6 | 7 | func (type2 *safeStructType) FieldByName(name string) StructField { 8 | field, found := type2.Type.FieldByName(name) 9 | if !found { 10 | panic("field " + name + " not found") 11 | } 12 | return &safeField{StructField: field} 13 | } 14 | 15 | func (type2 *safeStructType) Field(i int) StructField { 16 | return &safeField{StructField: type2.Type.Field(i)} 17 | } 18 | 19 | func (type2 *safeStructType) FieldByIndex(index []int) StructField { 20 | return &safeField{StructField: type2.Type.FieldByIndex(index)} 21 | } 22 | 23 | func (type2 *safeStructType) FieldByNameFunc(match func(string) bool) StructField { 24 | field, found := type2.Type.FieldByNameFunc(match) 25 | if !found { 26 | panic("field match condition not found in " + type2.Type.String()) 27 | } 28 | return &safeField{StructField: field} 29 | } 30 | -------------------------------------------------------------------------------- /safe_type.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | import ( 4 | "reflect" 5 | "unsafe" 6 | ) 7 | 8 | type safeType struct { 9 | Type reflect.Type 10 | cfg *frozenConfig 11 | } 12 | 13 | var _ Type = &safeType{} 14 | 15 | func (type2 *safeType) New() interface{} { 16 | return reflect.New(type2.Type).Interface() 17 | } 18 | 19 | func (type2 *safeType) UnsafeNew() unsafe.Pointer { 20 | panic("does not support unsafe operation") 21 | } 22 | 23 | func (type2 *safeType) Kind() reflect.Kind { 24 | return type2.Type.Kind() 25 | } 26 | 27 | func (type2 *safeType) Len() int { 28 | return type2.Type.Len() 29 | } 30 | 31 | func (type2 *safeType) NumField() int { 32 | return type2.Type.NumField() 33 | } 34 | 35 | func (type2 *safeType) String() string { 36 | return type2.Type.String() 37 | } 38 | 39 | func (type2 *safeType) Elem() Type { 40 | return type2.cfg.Type2(type2.Type.Elem()) 41 | } 42 | 43 | func (type2 *safeType) Type1() reflect.Type { 44 | return type2.Type 45 | } 46 | 47 | func (type2 *safeType) PackEFace(ptr unsafe.Pointer) interface{} { 48 | panic("does not support unsafe operation") 49 | } 50 | 51 | func (type2 *safeType) Implements(thatType Type) bool { 52 | return type2.Type.Implements(thatType.Type1()) 53 | } 54 | 55 | func (type2 *safeType) RType() uintptr { 56 | panic("does not support unsafe operation") 57 | } 58 | 59 | func (type2 *safeType) Indirect(obj interface{}) interface{} { 60 | return reflect.Indirect(reflect.ValueOf(obj)).Interface() 61 | } 62 | 63 | func (type2 *safeType) UnsafeIndirect(ptr unsafe.Pointer) interface{} { 64 | panic("does not support unsafe operation") 65 | } 66 | 67 | func (type2 *safeType) LikePtr() bool { 68 | panic("does not support unsafe operation") 69 | } 70 | 71 | func (type2 *safeType) IsNullable() bool { 72 | return IsNullable(type2.Kind()) 73 | } 74 | 75 | func (type2 *safeType) IsNil(obj interface{}) bool { 76 | if obj == nil { 77 | return true 78 | } 79 | return reflect.ValueOf(obj).Elem().IsNil() 80 | } 81 | 82 | func (type2 *safeType) UnsafeIsNil(ptr unsafe.Pointer) bool { 83 | panic("does not support unsafe operation") 84 | } 85 | 86 | func (type2 *safeType) Set(obj interface{}, val interface{}) { 87 | reflect.ValueOf(obj).Elem().Set(reflect.ValueOf(val).Elem()) 88 | } 89 | 90 | func (type2 *safeType) UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer) { 91 | panic("does not support unsafe operation") 92 | } 93 | 94 | func (type2 *safeType) AssignableTo(anotherType Type) bool { 95 | return type2.Type1().AssignableTo(anotherType.Type1()) 96 | } 97 | -------------------------------------------------------------------------------- /type_map.go: -------------------------------------------------------------------------------- 1 | // +build !gccgo 2 | 3 | package reflect2 4 | 5 | import ( 6 | "reflect" 7 | "sync" 8 | "unsafe" 9 | ) 10 | 11 | // typelinks2 for 1.7 ~ 12 | //go:linkname typelinks2 reflect.typelinks 13 | func typelinks2() (sections []unsafe.Pointer, offset [][]int32) 14 | 15 | // initOnce guards initialization of types and packages 16 | var initOnce sync.Once 17 | 18 | var types map[string]reflect.Type 19 | var packages map[string]map[string]reflect.Type 20 | 21 | // discoverTypes initializes types and packages 22 | func discoverTypes() { 23 | types = make(map[string]reflect.Type) 24 | packages = make(map[string]map[string]reflect.Type) 25 | 26 | loadGoTypes() 27 | } 28 | 29 | func loadGoTypes() { 30 | var obj interface{} = reflect.TypeOf(0) 31 | sections, offset := typelinks2() 32 | for i, offs := range offset { 33 | rodata := sections[i] 34 | for _, off := range offs { 35 | (*emptyInterface)(unsafe.Pointer(&obj)).word = resolveTypeOff(unsafe.Pointer(rodata), off) 36 | typ := obj.(reflect.Type) 37 | if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct { 38 | loadedType := typ.Elem() 39 | pkgTypes := packages[loadedType.PkgPath()] 40 | if pkgTypes == nil { 41 | pkgTypes = map[string]reflect.Type{} 42 | packages[loadedType.PkgPath()] = pkgTypes 43 | } 44 | types[loadedType.String()] = loadedType 45 | pkgTypes[loadedType.Name()] = loadedType 46 | } 47 | } 48 | } 49 | } 50 | 51 | type emptyInterface struct { 52 | typ unsafe.Pointer 53 | word unsafe.Pointer 54 | } 55 | 56 | // TypeByName return the type by its name, just like Class.forName in java 57 | func TypeByName(typeName string) Type { 58 | initOnce.Do(discoverTypes) 59 | return Type2(types[typeName]) 60 | } 61 | 62 | // TypeByPackageName return the type by its package and name 63 | func TypeByPackageName(pkgPath string, name string) Type { 64 | initOnce.Do(discoverTypes) 65 | pkgTypes := packages[pkgPath] 66 | if pkgTypes == nil { 67 | return nil 68 | } 69 | return Type2(pkgTypes[name]) 70 | } 71 | -------------------------------------------------------------------------------- /unsafe_array.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | import ( 4 | "reflect" 5 | "unsafe" 6 | ) 7 | 8 | type UnsafeArrayType struct { 9 | unsafeType 10 | elemRType unsafe.Pointer 11 | pElemRType unsafe.Pointer 12 | elemSize uintptr 13 | likePtr bool 14 | } 15 | 16 | func newUnsafeArrayType(cfg *frozenConfig, type1 reflect.Type) *UnsafeArrayType { 17 | return &UnsafeArrayType{ 18 | unsafeType: *newUnsafeType(cfg, type1), 19 | elemRType: unpackEFace(type1.Elem()).data, 20 | pElemRType: unpackEFace(reflect.PtrTo(type1.Elem())).data, 21 | elemSize: type1.Elem().Size(), 22 | likePtr: likePtrType(type1), 23 | } 24 | } 25 | 26 | func (type2 *UnsafeArrayType) LikePtr() bool { 27 | return type2.likePtr 28 | } 29 | 30 | func (type2 *UnsafeArrayType) Indirect(obj interface{}) interface{} { 31 | objEFace := unpackEFace(obj) 32 | assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype) 33 | return type2.UnsafeIndirect(objEFace.data) 34 | } 35 | 36 | func (type2 *UnsafeArrayType) UnsafeIndirect(ptr unsafe.Pointer) interface{} { 37 | if type2.likePtr { 38 | return packEFace(type2.rtype, *(*unsafe.Pointer)(ptr)) 39 | } 40 | return packEFace(type2.rtype, ptr) 41 | } 42 | 43 | func (type2 *UnsafeArrayType) SetIndex(obj interface{}, index int, elem interface{}) { 44 | objEFace := unpackEFace(obj) 45 | assertType("ArrayType.SetIndex argument 1", type2.ptrRType, objEFace.rtype) 46 | elemEFace := unpackEFace(elem) 47 | assertType("ArrayType.SetIndex argument 3", type2.pElemRType, elemEFace.rtype) 48 | type2.UnsafeSetIndex(objEFace.data, index, elemEFace.data) 49 | } 50 | 51 | func (type2 *UnsafeArrayType) UnsafeSetIndex(obj unsafe.Pointer, index int, elem unsafe.Pointer) { 52 | elemPtr := arrayAt(obj, index, type2.elemSize, "i < s.Len") 53 | typedmemmove(type2.elemRType, elemPtr, elem) 54 | } 55 | 56 | func (type2 *UnsafeArrayType) GetIndex(obj interface{}, index int) interface{} { 57 | objEFace := unpackEFace(obj) 58 | assertType("ArrayType.GetIndex argument 1", type2.ptrRType, objEFace.rtype) 59 | elemPtr := type2.UnsafeGetIndex(objEFace.data, index) 60 | return packEFace(type2.pElemRType, elemPtr) 61 | } 62 | 63 | func (type2 *UnsafeArrayType) UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer { 64 | return arrayAt(obj, index, type2.elemSize, "i < s.Len") 65 | } 66 | -------------------------------------------------------------------------------- /unsafe_eface.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | import ( 4 | "reflect" 5 | "unsafe" 6 | ) 7 | 8 | type eface struct { 9 | rtype unsafe.Pointer 10 | data unsafe.Pointer 11 | } 12 | 13 | func unpackEFace(obj interface{}) *eface { 14 | return (*eface)(unsafe.Pointer(&obj)) 15 | } 16 | 17 | func packEFace(rtype unsafe.Pointer, data unsafe.Pointer) interface{} { 18 | var i interface{} 19 | e := (*eface)(unsafe.Pointer(&i)) 20 | e.rtype = rtype 21 | e.data = data 22 | return i 23 | } 24 | 25 | type UnsafeEFaceType struct { 26 | unsafeType 27 | } 28 | 29 | func newUnsafeEFaceType(cfg *frozenConfig, type1 reflect.Type) *UnsafeEFaceType { 30 | return &UnsafeEFaceType{ 31 | unsafeType: *newUnsafeType(cfg, type1), 32 | } 33 | } 34 | 35 | func (type2 *UnsafeEFaceType) IsNil(obj interface{}) bool { 36 | if obj == nil { 37 | return true 38 | } 39 | objEFace := unpackEFace(obj) 40 | assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype) 41 | return type2.UnsafeIsNil(objEFace.data) 42 | } 43 | 44 | func (type2 *UnsafeEFaceType) UnsafeIsNil(ptr unsafe.Pointer) bool { 45 | if ptr == nil { 46 | return true 47 | } 48 | return unpackEFace(*(*interface{})(ptr)).data == nil 49 | } 50 | 51 | func (type2 *UnsafeEFaceType) Indirect(obj interface{}) interface{} { 52 | objEFace := unpackEFace(obj) 53 | assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype) 54 | return type2.UnsafeIndirect(objEFace.data) 55 | } 56 | 57 | func (type2 *UnsafeEFaceType) UnsafeIndirect(ptr unsafe.Pointer) interface{} { 58 | return *(*interface{})(ptr) 59 | } 60 | -------------------------------------------------------------------------------- /unsafe_field.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | import ( 4 | "reflect" 5 | "unsafe" 6 | ) 7 | 8 | type UnsafeStructField struct { 9 | reflect.StructField 10 | structType *UnsafeStructType 11 | rtype unsafe.Pointer 12 | ptrRType unsafe.Pointer 13 | } 14 | 15 | func newUnsafeStructField(structType *UnsafeStructType, structField reflect.StructField) *UnsafeStructField { 16 | return &UnsafeStructField{ 17 | StructField: structField, 18 | rtype: unpackEFace(structField.Type).data, 19 | ptrRType: unpackEFace(reflect.PtrTo(structField.Type)).data, 20 | structType: structType, 21 | } 22 | } 23 | 24 | func (field *UnsafeStructField) Offset() uintptr { 25 | return field.StructField.Offset 26 | } 27 | 28 | func (field *UnsafeStructField) Name() string { 29 | return field.StructField.Name 30 | } 31 | 32 | func (field *UnsafeStructField) PkgPath() string { 33 | return field.StructField.PkgPath 34 | } 35 | 36 | func (field *UnsafeStructField) Type() Type { 37 | return field.structType.cfg.Type2(field.StructField.Type) 38 | } 39 | 40 | func (field *UnsafeStructField) Tag() reflect.StructTag { 41 | return field.StructField.Tag 42 | } 43 | 44 | func (field *UnsafeStructField) Index() []int { 45 | return field.StructField.Index 46 | } 47 | 48 | func (field *UnsafeStructField) Anonymous() bool { 49 | return field.StructField.Anonymous 50 | } 51 | 52 | func (field *UnsafeStructField) Set(obj interface{}, value interface{}) { 53 | objEFace := unpackEFace(obj) 54 | assertType("StructField.SetIndex argument 1", field.structType.ptrRType, objEFace.rtype) 55 | valueEFace := unpackEFace(value) 56 | assertType("StructField.SetIndex argument 2", field.ptrRType, valueEFace.rtype) 57 | field.UnsafeSet(objEFace.data, valueEFace.data) 58 | } 59 | 60 | func (field *UnsafeStructField) UnsafeSet(obj unsafe.Pointer, value unsafe.Pointer) { 61 | fieldPtr := add(obj, field.StructField.Offset, "same as non-reflect &v.field") 62 | typedmemmove(field.rtype, fieldPtr, value) 63 | } 64 | 65 | func (field *UnsafeStructField) Get(obj interface{}) interface{} { 66 | objEFace := unpackEFace(obj) 67 | assertType("StructField.GetIndex argument 1", field.structType.ptrRType, objEFace.rtype) 68 | value := field.UnsafeGet(objEFace.data) 69 | return packEFace(field.ptrRType, value) 70 | } 71 | 72 | func (field *UnsafeStructField) UnsafeGet(obj unsafe.Pointer) unsafe.Pointer { 73 | return add(obj, field.StructField.Offset, "same as non-reflect &v.field") 74 | } 75 | -------------------------------------------------------------------------------- /unsafe_iface.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | import ( 4 | "reflect" 5 | "unsafe" 6 | ) 7 | 8 | type iface struct { 9 | itab *itab 10 | data unsafe.Pointer 11 | } 12 | 13 | type itab struct { 14 | ignore unsafe.Pointer 15 | rtype unsafe.Pointer 16 | } 17 | 18 | func IFaceToEFace(ptr unsafe.Pointer) interface{} { 19 | iface := (*iface)(ptr) 20 | if iface.itab == nil { 21 | return nil 22 | } 23 | return packEFace(iface.itab.rtype, iface.data) 24 | } 25 | 26 | type UnsafeIFaceType struct { 27 | unsafeType 28 | } 29 | 30 | func newUnsafeIFaceType(cfg *frozenConfig, type1 reflect.Type) *UnsafeIFaceType { 31 | return &UnsafeIFaceType{ 32 | unsafeType: *newUnsafeType(cfg, type1), 33 | } 34 | } 35 | 36 | func (type2 *UnsafeIFaceType) Indirect(obj interface{}) interface{} { 37 | objEFace := unpackEFace(obj) 38 | assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype) 39 | return type2.UnsafeIndirect(objEFace.data) 40 | } 41 | 42 | func (type2 *UnsafeIFaceType) UnsafeIndirect(ptr unsafe.Pointer) interface{} { 43 | return IFaceToEFace(ptr) 44 | } 45 | 46 | func (type2 *UnsafeIFaceType) IsNil(obj interface{}) bool { 47 | if obj == nil { 48 | return true 49 | } 50 | objEFace := unpackEFace(obj) 51 | assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype) 52 | return type2.UnsafeIsNil(objEFace.data) 53 | } 54 | 55 | func (type2 *UnsafeIFaceType) UnsafeIsNil(ptr unsafe.Pointer) bool { 56 | if ptr == nil { 57 | return true 58 | } 59 | iface := (*iface)(ptr) 60 | if iface.itab == nil { 61 | return true 62 | } 63 | return false 64 | } 65 | -------------------------------------------------------------------------------- /unsafe_link.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | import "unsafe" 4 | 5 | //go:linkname unsafe_New reflect.unsafe_New 6 | func unsafe_New(rtype unsafe.Pointer) unsafe.Pointer 7 | 8 | //go:linkname typedmemmove reflect.typedmemmove 9 | func typedmemmove(rtype unsafe.Pointer, dst, src unsafe.Pointer) 10 | 11 | //go:linkname unsafe_NewArray reflect.unsafe_NewArray 12 | func unsafe_NewArray(rtype unsafe.Pointer, length int) unsafe.Pointer 13 | 14 | // typedslicecopy copies a slice of elemType values from src to dst, 15 | // returning the number of elements copied. 16 | //go:linkname typedslicecopy reflect.typedslicecopy 17 | //go:noescape 18 | func typedslicecopy(elemType unsafe.Pointer, dst, src sliceHeader) int 19 | 20 | //go:linkname mapassign reflect.mapassign 21 | //go:noescape 22 | func mapassign(rtype unsafe.Pointer, m unsafe.Pointer, key unsafe.Pointer, val unsafe.Pointer) 23 | 24 | //go:linkname mapaccess reflect.mapaccess 25 | //go:noescape 26 | func mapaccess(rtype unsafe.Pointer, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer) 27 | 28 | //go:noescape 29 | //go:linkname mapiternext reflect.mapiternext 30 | func mapiternext(it *hiter) 31 | 32 | //go:linkname ifaceE2I reflect.ifaceE2I 33 | func ifaceE2I(rtype unsafe.Pointer, src interface{}, dst unsafe.Pointer) 34 | 35 | // A hash iteration structure. 36 | // If you modify hiter, also change cmd/internal/gc/reflect.go to indicate 37 | // the layout of this structure. 38 | type hiter struct { 39 | key unsafe.Pointer 40 | value unsafe.Pointer 41 | t unsafe.Pointer 42 | h unsafe.Pointer 43 | buckets unsafe.Pointer 44 | bptr unsafe.Pointer 45 | overflow *[]unsafe.Pointer 46 | oldoverflow *[]unsafe.Pointer 47 | startBucket uintptr 48 | offset uint8 49 | wrapped bool 50 | B uint8 51 | i uint8 52 | bucket uintptr 53 | checkBucket uintptr 54 | } 55 | 56 | // add returns p+x. 57 | // 58 | // The whySafe string is ignored, so that the function still inlines 59 | // as efficiently as p+x, but all call sites should use the string to 60 | // record why the addition is safe, which is to say why the addition 61 | // does not cause x to advance to the very end of p's allocation 62 | // and therefore point incorrectly at the next block in memory. 63 | func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { 64 | return unsafe.Pointer(uintptr(p) + x) 65 | } 66 | 67 | // arrayAt returns the i-th element of p, 68 | // an array whose elements are eltSize bytes wide. 69 | // The array pointed at by p must have at least i+1 elements: 70 | // it is invalid (but impossible to check here) to pass i >= len, 71 | // because then the result will point outside the array. 72 | // whySafe must explain why i < len. (Passing "i < len" is fine; 73 | // the benefit is to surface this assumption at the call site.) 74 | func arrayAt(p unsafe.Pointer, i int, eltSize uintptr, whySafe string) unsafe.Pointer { 75 | return add(p, uintptr(i)*eltSize, "i < len") 76 | } 77 | -------------------------------------------------------------------------------- /unsafe_map.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | import ( 4 | "reflect" 5 | "unsafe" 6 | ) 7 | 8 | type UnsafeMapType struct { 9 | unsafeType 10 | pKeyRType unsafe.Pointer 11 | pElemRType unsafe.Pointer 12 | } 13 | 14 | func newUnsafeMapType(cfg *frozenConfig, type1 reflect.Type) MapType { 15 | return &UnsafeMapType{ 16 | unsafeType: *newUnsafeType(cfg, type1), 17 | pKeyRType: unpackEFace(reflect.PtrTo(type1.Key())).data, 18 | pElemRType: unpackEFace(reflect.PtrTo(type1.Elem())).data, 19 | } 20 | } 21 | 22 | func (type2 *UnsafeMapType) IsNil(obj interface{}) bool { 23 | if obj == nil { 24 | return true 25 | } 26 | objEFace := unpackEFace(obj) 27 | assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype) 28 | return type2.UnsafeIsNil(objEFace.data) 29 | } 30 | 31 | func (type2 *UnsafeMapType) UnsafeIsNil(ptr unsafe.Pointer) bool { 32 | if ptr == nil { 33 | return true 34 | } 35 | return *(*unsafe.Pointer)(ptr) == nil 36 | } 37 | 38 | func (type2 *UnsafeMapType) LikePtr() bool { 39 | return true 40 | } 41 | 42 | func (type2 *UnsafeMapType) Indirect(obj interface{}) interface{} { 43 | objEFace := unpackEFace(obj) 44 | assertType("MapType.Indirect argument 1", type2.ptrRType, objEFace.rtype) 45 | return type2.UnsafeIndirect(objEFace.data) 46 | } 47 | 48 | func (type2 *UnsafeMapType) UnsafeIndirect(ptr unsafe.Pointer) interface{} { 49 | return packEFace(type2.rtype, *(*unsafe.Pointer)(ptr)) 50 | } 51 | 52 | func (type2 *UnsafeMapType) Key() Type { 53 | return type2.cfg.Type2(type2.Type.Key()) 54 | } 55 | 56 | func (type2 *UnsafeMapType) MakeMap(cap int) interface{} { 57 | return packEFace(type2.ptrRType, type2.UnsafeMakeMap(cap)) 58 | } 59 | 60 | func (type2 *UnsafeMapType) UnsafeMakeMap(cap int) unsafe.Pointer { 61 | m := makeMapWithSize(type2.rtype, cap) 62 | return unsafe.Pointer(&m) 63 | } 64 | 65 | func (type2 *UnsafeMapType) SetIndex(obj interface{}, key interface{}, elem interface{}) { 66 | objEFace := unpackEFace(obj) 67 | assertType("MapType.SetIndex argument 1", type2.ptrRType, objEFace.rtype) 68 | keyEFace := unpackEFace(key) 69 | assertType("MapType.SetIndex argument 2", type2.pKeyRType, keyEFace.rtype) 70 | elemEFace := unpackEFace(elem) 71 | assertType("MapType.SetIndex argument 3", type2.pElemRType, elemEFace.rtype) 72 | type2.UnsafeSetIndex(objEFace.data, keyEFace.data, elemEFace.data) 73 | } 74 | 75 | func (type2 *UnsafeMapType) UnsafeSetIndex(obj unsafe.Pointer, key unsafe.Pointer, elem unsafe.Pointer) { 76 | mapassign(type2.rtype, *(*unsafe.Pointer)(obj), key, elem) 77 | } 78 | 79 | func (type2 *UnsafeMapType) TryGetIndex(obj interface{}, key interface{}) (interface{}, bool) { 80 | objEFace := unpackEFace(obj) 81 | assertType("MapType.TryGetIndex argument 1", type2.ptrRType, objEFace.rtype) 82 | keyEFace := unpackEFace(key) 83 | assertType("MapType.TryGetIndex argument 2", type2.pKeyRType, keyEFace.rtype) 84 | elemPtr := type2.UnsafeGetIndex(objEFace.data, keyEFace.data) 85 | if elemPtr == nil { 86 | return nil, false 87 | } 88 | return packEFace(type2.pElemRType, elemPtr), true 89 | } 90 | 91 | func (type2 *UnsafeMapType) GetIndex(obj interface{}, key interface{}) interface{} { 92 | objEFace := unpackEFace(obj) 93 | assertType("MapType.GetIndex argument 1", type2.ptrRType, objEFace.rtype) 94 | keyEFace := unpackEFace(key) 95 | assertType("MapType.GetIndex argument 2", type2.pKeyRType, keyEFace.rtype) 96 | elemPtr := type2.UnsafeGetIndex(objEFace.data, keyEFace.data) 97 | return packEFace(type2.pElemRType, elemPtr) 98 | } 99 | 100 | func (type2 *UnsafeMapType) UnsafeGetIndex(obj unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer { 101 | return mapaccess(type2.rtype, *(*unsafe.Pointer)(obj), key) 102 | } 103 | 104 | func (type2 *UnsafeMapType) Iterate(obj interface{}) MapIterator { 105 | objEFace := unpackEFace(obj) 106 | assertType("MapType.Iterate argument 1", type2.ptrRType, objEFace.rtype) 107 | return type2.UnsafeIterate(objEFace.data) 108 | } 109 | 110 | type UnsafeMapIterator struct { 111 | *hiter 112 | pKeyRType unsafe.Pointer 113 | pElemRType unsafe.Pointer 114 | } 115 | 116 | func (iter *UnsafeMapIterator) HasNext() bool { 117 | return iter.key != nil 118 | } 119 | 120 | func (iter *UnsafeMapIterator) Next() (interface{}, interface{}) { 121 | key, elem := iter.UnsafeNext() 122 | return packEFace(iter.pKeyRType, key), packEFace(iter.pElemRType, elem) 123 | } 124 | 125 | func (iter *UnsafeMapIterator) UnsafeNext() (unsafe.Pointer, unsafe.Pointer) { 126 | key := iter.key 127 | elem := iter.value 128 | mapiternext(iter.hiter) 129 | return key, elem 130 | } 131 | -------------------------------------------------------------------------------- /unsafe_ptr.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | import ( 4 | "reflect" 5 | "unsafe" 6 | ) 7 | 8 | type UnsafePtrType struct { 9 | unsafeType 10 | } 11 | 12 | func newUnsafePtrType(cfg *frozenConfig, type1 reflect.Type) *UnsafePtrType { 13 | return &UnsafePtrType{ 14 | unsafeType: *newUnsafeType(cfg, type1), 15 | } 16 | } 17 | 18 | func (type2 *UnsafePtrType) IsNil(obj interface{}) bool { 19 | if obj == nil { 20 | return true 21 | } 22 | objEFace := unpackEFace(obj) 23 | assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype) 24 | return type2.UnsafeIsNil(objEFace.data) 25 | } 26 | 27 | func (type2 *UnsafePtrType) UnsafeIsNil(ptr unsafe.Pointer) bool { 28 | if ptr == nil { 29 | return true 30 | } 31 | return *(*unsafe.Pointer)(ptr) == nil 32 | } 33 | 34 | func (type2 *UnsafePtrType) LikePtr() bool { 35 | return true 36 | } 37 | 38 | func (type2 *UnsafePtrType) Indirect(obj interface{}) interface{} { 39 | objEFace := unpackEFace(obj) 40 | assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype) 41 | return type2.UnsafeIndirect(objEFace.data) 42 | } 43 | 44 | func (type2 *UnsafePtrType) UnsafeIndirect(ptr unsafe.Pointer) interface{} { 45 | return packEFace(type2.rtype, *(*unsafe.Pointer)(ptr)) 46 | } 47 | -------------------------------------------------------------------------------- /unsafe_slice.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | import ( 4 | "reflect" 5 | "unsafe" 6 | ) 7 | 8 | // sliceHeader is a safe version of SliceHeader used within this package. 9 | type sliceHeader struct { 10 | Data unsafe.Pointer 11 | Len int 12 | Cap int 13 | } 14 | 15 | type UnsafeSliceType struct { 16 | unsafeType 17 | elemRType unsafe.Pointer 18 | pElemRType unsafe.Pointer 19 | elemSize uintptr 20 | } 21 | 22 | func newUnsafeSliceType(cfg *frozenConfig, type1 reflect.Type) SliceType { 23 | elemType := type1.Elem() 24 | return &UnsafeSliceType{ 25 | unsafeType: *newUnsafeType(cfg, type1), 26 | pElemRType: unpackEFace(reflect.PtrTo(elemType)).data, 27 | elemRType: unpackEFace(elemType).data, 28 | elemSize: elemType.Size(), 29 | } 30 | } 31 | 32 | func (type2 *UnsafeSliceType) Set(obj interface{}, val interface{}) { 33 | objEFace := unpackEFace(obj) 34 | assertType("Type.Set argument 1", type2.ptrRType, objEFace.rtype) 35 | valEFace := unpackEFace(val) 36 | assertType("Type.Set argument 2", type2.ptrRType, valEFace.rtype) 37 | type2.UnsafeSet(objEFace.data, valEFace.data) 38 | } 39 | 40 | func (type2 *UnsafeSliceType) UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer) { 41 | *(*sliceHeader)(ptr) = *(*sliceHeader)(val) 42 | } 43 | 44 | func (type2 *UnsafeSliceType) IsNil(obj interface{}) bool { 45 | if obj == nil { 46 | return true 47 | } 48 | objEFace := unpackEFace(obj) 49 | assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype) 50 | return type2.UnsafeIsNil(objEFace.data) 51 | } 52 | 53 | func (type2 *UnsafeSliceType) UnsafeIsNil(ptr unsafe.Pointer) bool { 54 | if ptr == nil { 55 | return true 56 | } 57 | return (*sliceHeader)(ptr).Data == nil 58 | } 59 | 60 | func (type2 *UnsafeSliceType) SetNil(obj interface{}) { 61 | objEFace := unpackEFace(obj) 62 | assertType("SliceType.SetNil argument 1", type2.ptrRType, objEFace.rtype) 63 | type2.UnsafeSetNil(objEFace.data) 64 | } 65 | 66 | func (type2 *UnsafeSliceType) UnsafeSetNil(ptr unsafe.Pointer) { 67 | header := (*sliceHeader)(ptr) 68 | header.Len = 0 69 | header.Cap = 0 70 | header.Data = nil 71 | } 72 | 73 | func (type2 *UnsafeSliceType) MakeSlice(length int, cap int) interface{} { 74 | return packEFace(type2.ptrRType, type2.UnsafeMakeSlice(length, cap)) 75 | } 76 | 77 | func (type2 *UnsafeSliceType) UnsafeMakeSlice(length int, cap int) unsafe.Pointer { 78 | header := &sliceHeader{unsafe_NewArray(type2.elemRType, cap), length, cap} 79 | return unsafe.Pointer(header) 80 | } 81 | 82 | func (type2 *UnsafeSliceType) LengthOf(obj interface{}) int { 83 | objEFace := unpackEFace(obj) 84 | assertType("SliceType.Len argument 1", type2.ptrRType, objEFace.rtype) 85 | return type2.UnsafeLengthOf(objEFace.data) 86 | } 87 | 88 | func (type2 *UnsafeSliceType) UnsafeLengthOf(obj unsafe.Pointer) int { 89 | header := (*sliceHeader)(obj) 90 | return header.Len 91 | } 92 | 93 | func (type2 *UnsafeSliceType) SetIndex(obj interface{}, index int, elem interface{}) { 94 | objEFace := unpackEFace(obj) 95 | assertType("SliceType.SetIndex argument 1", type2.ptrRType, objEFace.rtype) 96 | elemEFace := unpackEFace(elem) 97 | assertType("SliceType.SetIndex argument 3", type2.pElemRType, elemEFace.rtype) 98 | type2.UnsafeSetIndex(objEFace.data, index, elemEFace.data) 99 | } 100 | 101 | func (type2 *UnsafeSliceType) UnsafeSetIndex(obj unsafe.Pointer, index int, elem unsafe.Pointer) { 102 | header := (*sliceHeader)(obj) 103 | elemPtr := arrayAt(header.Data, index, type2.elemSize, "i < s.Len") 104 | typedmemmove(type2.elemRType, elemPtr, elem) 105 | } 106 | 107 | func (type2 *UnsafeSliceType) GetIndex(obj interface{}, index int) interface{} { 108 | objEFace := unpackEFace(obj) 109 | assertType("SliceType.GetIndex argument 1", type2.ptrRType, objEFace.rtype) 110 | elemPtr := type2.UnsafeGetIndex(objEFace.data, index) 111 | return packEFace(type2.pElemRType, elemPtr) 112 | } 113 | 114 | func (type2 *UnsafeSliceType) UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer { 115 | header := (*sliceHeader)(obj) 116 | return arrayAt(header.Data, index, type2.elemSize, "i < s.Len") 117 | } 118 | 119 | func (type2 *UnsafeSliceType) Append(obj interface{}, elem interface{}) { 120 | objEFace := unpackEFace(obj) 121 | assertType("SliceType.Append argument 1", type2.ptrRType, objEFace.rtype) 122 | elemEFace := unpackEFace(elem) 123 | assertType("SliceType.Append argument 2", type2.pElemRType, elemEFace.rtype) 124 | type2.UnsafeAppend(objEFace.data, elemEFace.data) 125 | } 126 | 127 | func (type2 *UnsafeSliceType) UnsafeAppend(obj unsafe.Pointer, elem unsafe.Pointer) { 128 | header := (*sliceHeader)(obj) 129 | oldLen := header.Len 130 | type2.UnsafeGrow(obj, oldLen+1) 131 | type2.UnsafeSetIndex(obj, oldLen, elem) 132 | } 133 | 134 | func (type2 *UnsafeSliceType) Cap(obj interface{}) int { 135 | objEFace := unpackEFace(obj) 136 | assertType("SliceType.Cap argument 1", type2.ptrRType, objEFace.rtype) 137 | return type2.UnsafeCap(objEFace.data) 138 | } 139 | 140 | func (type2 *UnsafeSliceType) UnsafeCap(ptr unsafe.Pointer) int { 141 | return (*sliceHeader)(ptr).Cap 142 | } 143 | 144 | func (type2 *UnsafeSliceType) Grow(obj interface{}, newLength int) { 145 | objEFace := unpackEFace(obj) 146 | assertType("SliceType.Grow argument 1", type2.ptrRType, objEFace.rtype) 147 | type2.UnsafeGrow(objEFace.data, newLength) 148 | } 149 | 150 | func (type2 *UnsafeSliceType) UnsafeGrow(obj unsafe.Pointer, newLength int) { 151 | header := (*sliceHeader)(obj) 152 | if newLength <= header.Cap { 153 | header.Len = newLength 154 | return 155 | } 156 | newCap := calcNewCap(header.Cap, newLength) 157 | newHeader := (*sliceHeader)(type2.UnsafeMakeSlice(header.Len, newCap)) 158 | typedslicecopy(type2.elemRType, *newHeader, *header) 159 | header.Data = newHeader.Data 160 | header.Cap = newHeader.Cap 161 | header.Len = newLength 162 | } 163 | 164 | func calcNewCap(cap int, expectedCap int) int { 165 | if cap == 0 { 166 | cap = expectedCap 167 | } else { 168 | for cap < expectedCap { 169 | if cap < 1024 { 170 | cap += cap 171 | } else { 172 | cap += cap / 4 173 | } 174 | } 175 | } 176 | return cap 177 | } 178 | -------------------------------------------------------------------------------- /unsafe_struct.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | import ( 4 | "reflect" 5 | "unsafe" 6 | ) 7 | 8 | type UnsafeStructType struct { 9 | unsafeType 10 | likePtr bool 11 | } 12 | 13 | func newUnsafeStructType(cfg *frozenConfig, type1 reflect.Type) *UnsafeStructType { 14 | return &UnsafeStructType{ 15 | unsafeType: *newUnsafeType(cfg, type1), 16 | likePtr: likePtrType(type1), 17 | } 18 | } 19 | 20 | func (type2 *UnsafeStructType) LikePtr() bool { 21 | return type2.likePtr 22 | } 23 | 24 | func (type2 *UnsafeStructType) Indirect(obj interface{}) interface{} { 25 | objEFace := unpackEFace(obj) 26 | assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype) 27 | return type2.UnsafeIndirect(objEFace.data) 28 | } 29 | 30 | func (type2 *UnsafeStructType) UnsafeIndirect(ptr unsafe.Pointer) interface{} { 31 | if type2.likePtr { 32 | return packEFace(type2.rtype, *(*unsafe.Pointer)(ptr)) 33 | } 34 | return packEFace(type2.rtype, ptr) 35 | } 36 | 37 | func (type2 *UnsafeStructType) FieldByName(name string) StructField { 38 | structField, found := type2.Type.FieldByName(name) 39 | if !found { 40 | return nil 41 | } 42 | return newUnsafeStructField(type2, structField) 43 | } 44 | 45 | func (type2 *UnsafeStructType) Field(i int) StructField { 46 | return newUnsafeStructField(type2, type2.Type.Field(i)) 47 | } 48 | 49 | func (type2 *UnsafeStructType) FieldByIndex(index []int) StructField { 50 | return newUnsafeStructField(type2, type2.Type.FieldByIndex(index)) 51 | } 52 | 53 | func (type2 *UnsafeStructType) FieldByNameFunc(match func(string) bool) StructField { 54 | structField, found := type2.Type.FieldByNameFunc(match) 55 | if !found { 56 | panic("field match condition not found in " + type2.Type.String()) 57 | } 58 | return newUnsafeStructField(type2, structField) 59 | } 60 | -------------------------------------------------------------------------------- /unsafe_type.go: -------------------------------------------------------------------------------- 1 | package reflect2 2 | 3 | import ( 4 | "reflect" 5 | "unsafe" 6 | ) 7 | 8 | type unsafeType struct { 9 | safeType 10 | rtype unsafe.Pointer 11 | ptrRType unsafe.Pointer 12 | } 13 | 14 | func newUnsafeType(cfg *frozenConfig, type1 reflect.Type) *unsafeType { 15 | return &unsafeType{ 16 | safeType: safeType{ 17 | Type: type1, 18 | cfg: cfg, 19 | }, 20 | rtype: unpackEFace(type1).data, 21 | ptrRType: unpackEFace(reflect.PtrTo(type1)).data, 22 | } 23 | } 24 | 25 | func (type2 *unsafeType) Set(obj interface{}, val interface{}) { 26 | objEFace := unpackEFace(obj) 27 | assertType("Type.Set argument 1", type2.ptrRType, objEFace.rtype) 28 | valEFace := unpackEFace(val) 29 | assertType("Type.Set argument 2", type2.ptrRType, valEFace.rtype) 30 | type2.UnsafeSet(objEFace.data, valEFace.data) 31 | } 32 | 33 | func (type2 *unsafeType) UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer) { 34 | typedmemmove(type2.rtype, ptr, val) 35 | } 36 | 37 | func (type2 *unsafeType) IsNil(obj interface{}) bool { 38 | objEFace := unpackEFace(obj) 39 | assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype) 40 | return type2.UnsafeIsNil(objEFace.data) 41 | } 42 | 43 | func (type2 *unsafeType) UnsafeIsNil(ptr unsafe.Pointer) bool { 44 | return ptr == nil 45 | } 46 | 47 | func (type2 *unsafeType) UnsafeNew() unsafe.Pointer { 48 | return unsafe_New(type2.rtype) 49 | } 50 | 51 | func (type2 *unsafeType) New() interface{} { 52 | return packEFace(type2.ptrRType, type2.UnsafeNew()) 53 | } 54 | 55 | func (type2 *unsafeType) PackEFace(ptr unsafe.Pointer) interface{} { 56 | return packEFace(type2.ptrRType, ptr) 57 | } 58 | 59 | func (type2 *unsafeType) RType() uintptr { 60 | return uintptr(type2.rtype) 61 | } 62 | 63 | func (type2 *unsafeType) Indirect(obj interface{}) interface{} { 64 | objEFace := unpackEFace(obj) 65 | assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype) 66 | return type2.UnsafeIndirect(objEFace.data) 67 | } 68 | 69 | func (type2 *unsafeType) UnsafeIndirect(obj unsafe.Pointer) interface{} { 70 | return packEFace(type2.rtype, obj) 71 | } 72 | 73 | func (type2 *unsafeType) LikePtr() bool { 74 | return false 75 | } 76 | 77 | func assertType(where string, expectRType unsafe.Pointer, actualRType unsafe.Pointer) { 78 | if expectRType != actualRType { 79 | expectType := reflect.TypeOf(0) 80 | (*iface)(unsafe.Pointer(&expectType)).data = expectRType 81 | actualType := reflect.TypeOf(0) 82 | (*iface)(unsafe.Pointer(&actualType)).data = actualRType 83 | panic(where + ": expect " + expectType.String() + ", actual " + actualType.String()) 84 | } 85 | } 86 | --------------------------------------------------------------------------------