github.com/goplus/reflectx@v1.2.2/name_go117.go (about) 1 //go:build go1.17 && (!js || (js && wasm)) 2 // +build go1.17 3 // +build !js js,wasm 4 5 package reflectx 6 7 import "unsafe" 8 9 // name is an encoded type name with optional extra data. 10 // 11 // The first byte is a bit field containing: 12 // 13 // 1<<0 the name is exported 14 // 1<<1 tag data follows the name 15 // 1<<2 pkgPath nameOff follows the name and tag 16 // 17 // Following that, there is a varint-encoded length of the name, 18 // followed by the name itself. 19 // 20 // If tag data is present, it also has a varint-encoded length 21 // followed by the tag itself. 22 // 23 // If the import path follows, then 4 bytes at the end of 24 // the data form a nameOff. The import path is only set for concrete 25 // methods that are defined in a different package than their type. 26 // 27 // If a name starts with "*", then the exported bit represents 28 // whether the pointed to type is exported. 29 // 30 // Note: this encoding must match here and in: 31 // cmd/compile/internal/reflectdata/reflect.go 32 // runtime/type.go 33 // internal/reflectlite/type.go 34 // cmd/link/internal/ld/decodesym.go 35 36 type name struct { 37 bytes *byte 38 } 39 40 func (n name) data(off int, whySafe string) *byte { 41 return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off), whySafe)) 42 } 43 44 func (n name) isExported() bool { 45 return (*n.bytes)&(1<<0) != 0 46 } 47 48 // go1.19 49 func (n name) embedded() bool { 50 return (*n.bytes)&(1<<3) != 0 51 } 52 53 // go1.19 54 func (n name) setEmbedded() { 55 (*n.bytes) |= 1 << 3 56 } 57 58 func (n name) hasTag() bool { 59 return (*n.bytes)&(1<<1) != 0 60 } 61 62 // readVarint parses a varint as encoded by encoding/binary. 63 // It returns the number of encoded bytes and the encoded value. 64 func (n name) readVarint(off int) (int, int) { 65 v := 0 66 for i := 0; ; i++ { 67 x := *n.data(off+i, "read varint") 68 v += int(x&0x7f) << (7 * i) 69 if x&0x80 == 0 { 70 return i + 1, v 71 } 72 } 73 } 74 75 // writeVarint writes n to buf in varint form. Returns the 76 // number of bytes written. n must be nonnegative. 77 // Writes at most 10 bytes. 78 func writeVarint(buf []byte, n int) int { 79 for i := 0; ; i++ { 80 b := byte(n & 0x7f) 81 n >>= 7 82 if n == 0 { 83 buf[i] = b 84 return i + 1 85 } 86 buf[i] = b | 0x80 87 } 88 } 89 90 func (n name) name() (s string) { 91 if n.bytes == nil { 92 return 93 } 94 i, l := n.readVarint(1) 95 hdr := (*stringHeader)(unsafe.Pointer(&s)) 96 hdr.Data = unsafe.Pointer(n.data(1+i, "non-empty string")) 97 hdr.Len = l 98 return 99 } 100 101 func (n name) tag() (s string) { 102 if !n.hasTag() { 103 return "" 104 } 105 i, l := n.readVarint(1) 106 i2, l2 := n.readVarint(1 + i + l) 107 hdr := (*stringHeader)(unsafe.Pointer(&s)) 108 hdr.Data = unsafe.Pointer(n.data(1+i+l+i2, "non-empty string")) 109 hdr.Len = l2 110 return 111 } 112 113 func (n name) pkgPath() string { 114 if n.bytes == nil || *n.data(0, "name flag field")&(1<<2) == 0 { 115 return "" 116 } 117 i, l := n.readVarint(1) 118 off := 1 + i + l 119 if n.hasTag() { 120 i2, l2 := n.readVarint(off) 121 off += i2 + l2 122 } 123 var nameOff int32 124 // Note that this field may not be aligned in memory, 125 // so we cannot use a direct int32 assignment here. 126 copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off, "name offset field")))[:]) 127 pkgPathName := name{(*byte)(resolveTypeOff(unsafe.Pointer(n.bytes), nameOff))} 128 return pkgPathName.name() 129 } 130 131 func (n name) setPkgPath(pkgpath string) { 132 if n.bytes == nil || *n.data(0, "name flag pkgPath")&(1<<2) == 0 { 133 return 134 } 135 i, l := n.readVarint(1) 136 off := 1 + i + l 137 if n.hasTag() { 138 i2, l2 := n.readVarint(off) 139 off += i2 + l2 140 } 141 v := resolveReflectName(newName(pkgpath, "", false)) 142 copy((*[4]byte)(unsafe.Pointer(n.data(off, "name offset pkgPath")))[:], (*[4]byte)(unsafe.Pointer(&v))[:]) 143 } 144 145 func newNameEx(n, tag string, exported bool, pkgpath bool) name { 146 if len(n) >= 1<<29 { 147 panic("reflect.nameFrom: name too long: " + n[:1024] + "...") 148 } 149 if len(tag) >= 1<<29 { 150 panic("reflect.nameFrom: tag too long: " + tag[:1024] + "...") 151 } 152 var nameLen [10]byte 153 var tagLen [10]byte 154 nameLenLen := writeVarint(nameLen[:], len(n)) 155 tagLenLen := writeVarint(tagLen[:], len(tag)) 156 157 var bits byte 158 l := 1 + nameLenLen + len(n) 159 if exported { 160 bits |= 1 << 0 161 } 162 if len(tag) > 0 { 163 l += tagLenLen + len(tag) 164 bits |= 1 << 1 165 } 166 if !exported && pkgpath { 167 bits |= 1 << 2 168 l += 4 169 } 170 171 b := make([]byte, l) 172 b[0] = bits 173 copy(b[1:], nameLen[:nameLenLen]) 174 copy(b[1+nameLenLen:], n) 175 if len(tag) > 0 { 176 tb := b[1+nameLenLen+len(n):] 177 copy(tb, tagLen[:tagLenLen]) 178 copy(tb[tagLenLen:], tag) 179 } 180 181 return name{bytes: &b[0]} 182 }