github.com/lxt1045/json@v0.0.0-20231013032136-54d6b1d6e525/struct_tag.go (about) 1 // MIT License 2 // 3 // Copyright (c) 2021 Xiantu Li 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be included in all 13 // copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 // SOFTWARE. 22 23 package json 24 25 import ( 26 "fmt" 27 "reflect" 28 "strings" 29 "sync" 30 "unsafe" 31 32 lxterrs "github.com/lxt1045/errors" 33 ) 34 35 // TagInfo 拥有tag的struct的成员的解析结果 36 type TagInfo struct { 37 // 常用的放前面,在缓存的概率大 38 TagName string // 39 fUnm unmFunc 40 fM mFunc 41 sliceCache *BatchObj 42 tireTree *tireTree 43 44 BaseType reflect.Type // 45 BaseKind reflect.Kind // 次成员可能是 **string,[]int 等这种复杂类型,这个 用来指示 "最里层" 的类型 46 Offset uintptr //偏移量 47 TypeSize int // 48 StringTag bool // `json:"field,string"`: 此情形下,需要把struct的int转成json的string 49 OmitemptyTag bool // `json:"some_field,omitempty"` 50 51 Children map[string]*TagInfo // 支持快速获取子节点 52 ChildList []*TagInfo // 支持遍历的顺序;加快遍历速度 53 54 ptrCacheType reflect.Type // pointer 的 cache 55 ptrCache *BatchObj // ptrCacheType 类型的 pool 56 57 slicePoolType reflect.Type // 除 cdynamicPool 以外的 slice 缓存; slice 动态增长,与 pointer 不一样 58 sliceElemGoType *GoType 59 idxSliceObjPool uintptr 60 idxSlicePointerPool uintptr // ptrDeep > 1 时,需要使用 61 62 SPool sync.Pool // TODO:slice pool 和 store.pool 放在一起吧,通过 id 来获取获取 pool,并把剩余的”垃圾“放回 sync.Pool 中共下次复用 63 SPoolN int32 64 SPool2 *BatchObj // 新的 slice cache 65 66 sPooloffset int32 // slice pool 在 PoolStore的偏移量; TODO 67 psPooloffset int32 // pointer slice pool 在 PoolStore的偏移量 68 bsMarshalLen int32 // 缓存上次 生成的 bs 的大小,如果 cache 小于这个值,则丢弃 69 bsHaftCount int32 // 记录上次低于 bsMarshalLen/2 的次数 70 71 } 72 73 const SPoolN = 1024 // * 1024 74 75 func (t *TagInfo) GetChildFromMap(key string) *TagInfo { 76 return t.Children[string(key)] 77 } 78 79 // AddChild 添加下级子节点 80 func (t *TagInfo) AddChild(c *TagInfo) (err error) { 81 if len(t.Children) == 0 { 82 t.Children = make(map[string]*TagInfo) 83 } 84 if _, ok := t.Children[c.TagName]; ok { 85 err = fmt.Errorf("error, type[%s].tag[%s]类型配置出错,字段重复", t.TagName, c.TagName) 86 return 87 } 88 t.ChildList = append(t.ChildList, c) 89 t.Children[c.TagName] = c 90 return 91 } 92 93 // []byte 是一种特殊的底层数据类型,需要 base64 编码 94 func isBytes(typ reflect.Type) bool { 95 bsType := reflect.TypeOf(&[]byte{}) 96 return UnpackType(bsType).Hash == UnpackType(typ).Hash 97 } 98 func isStrings(typ reflect.Type) bool { 99 bsType := reflect.TypeOf([]string{}) 100 return UnpackType(bsType).Hash == UnpackType(typ).Hash 101 } 102 103 type ancestor struct { 104 hash uint32 105 tag *TagInfo 106 } 107 108 func (ti *TagInfo) setFuncs(ptrBuilder, sliceBuilder *TypeBuilder, typ reflect.Type, anonymous bool, ancestors []ancestor) (son *TagInfo, err error) { 109 son = ti 110 ptrDeep, baseType := 0, typ 111 var pidx *uintptr 112 for ; ; typ = typ.Elem() { 113 if typ.Kind() == reflect.Ptr { 114 ptrDeep++ 115 continue 116 } 117 baseType = typ 118 break 119 } 120 son.BaseType = baseType 121 if ptrDeep > 0 { 122 pidx = &[]uintptr{0}[0] 123 ptrBuilder.AppendTagField(baseType, pidx) 124 } 125 126 // 先从最后一个基础类型开始处理 127 switch baseType.Kind() { 128 case reflect.Bool: 129 ti.fUnm, ti.fM = boolMFuncs(pidx) 130 case reflect.Uint, reflect.Uint64, reflect.Uintptr: 131 ti.fUnm, ti.fM = uint64MFuncs(pidx) 132 case reflect.Int, reflect.Int64: 133 ti.fUnm, ti.fM = int64MFuncs(pidx) 134 case reflect.Uint32: 135 ti.fUnm, ti.fM = uint32MFuncs(pidx) 136 case reflect.Int32: 137 ti.fUnm, ti.fM = int32MFuncs(pidx) 138 case reflect.Uint16: 139 ti.fUnm, ti.fM = uint16MFuncs(pidx) 140 case reflect.Int16: 141 ti.fUnm, ti.fM = int16MFuncs(pidx) 142 case reflect.Uint8: 143 ti.fUnm, ti.fM = uint8MFuncs(pidx) 144 case reflect.Int8: 145 ti.fUnm, ti.fM = int8MFuncs(pidx) 146 case reflect.Float64: 147 ti.fUnm, ti.fM = float64MFuncs(pidx) 148 case reflect.Float32: 149 ti.fUnm, ti.fM = float32MFuncs(pidx) 150 case reflect.String: 151 ti.fUnm, ti.fM = stringMFuncs(pidx) 152 case reflect.Slice: // &[]byte; Array 153 if isBytes(baseType) { 154 ti.fUnm, ti.fM = bytesMFuncs(pidx) 155 } else { 156 ti.BaseType = baseType 157 sliceType := baseType.Elem() 158 ti.sliceElemGoType = UnpackType(sliceType) 159 sliceBuilder.AppendTagField(ti.BaseType, &ti.idxSliceObjPool) 160 if ptrDeep > 0 { 161 typ := reflect.TypeOf([]unsafe.Pointer{}) 162 sliceBuilder.AppendTagField(typ, &ti.idxSlicePointerPool) 163 } 164 if isStrings(baseType) { 165 // 字符串数组 166 ti.fUnm, ti.fM = sliceStringsMFuncs() 167 // ti.fUnm, ti.fM = sliceMFuncs(pidx) 168 } else if ptrDeep > 0 { 169 //指针数组 170 ti.fUnm, ti.fM = sliceNoscanMFuncs(pidx) 171 } else if UnpackType(sliceType).Hash == UnpackType(reflect.TypeOf(int(0))).Hash && ptrDeep == 0 { 172 // int 数组 173 ti.fUnm, ti.fM = sliceIntsMFuncs(pidx) 174 // ti.fUnm, ti.fM = sliceNoscanMFuncs(pidx) 175 } else if UnpackType(sliceType).PtrData == 0 && ptrDeep == 0 { 176 ti.fUnm, ti.fM = sliceNoscanMFuncs(pidx) 177 } else if UnpackType(sliceType).Hash == UnpackType(reflect.TypeOf(interface{}(0))).Hash && ptrDeep == 0 { 178 // interface{} 数组 179 ti.fUnm, ti.fM = sliceMFuncs(pidx) 180 } else { 181 ti.fUnm, ti.fM = sliceMFuncs(pidx) 182 } 183 son = &TagInfo{ 184 TagName: `"son"`, 185 BaseType: sliceType, 186 TypeSize: int(sliceType.Size()), 187 } 188 189 subSon, err := son.setFuncs(ptrBuilder, sliceBuilder, sliceType, false /*anonymous*/, ancestors) 190 if err != nil { 191 return nil, lxterrs.Wrap(err, "Struct") 192 } 193 subSon.sliceCache = NewBatchObj(sliceType) 194 195 err = ti.AddChild(subSon) //TODO: err = ti.AddChild(son) ? 196 // err = ti.AddChild(son) 197 if err != nil { 198 return nil, lxterrs.Wrap(err, "Struct") 199 } 200 201 ti.SPoolN = (1 << 20) / int32(ti.BaseType.Size()) 202 ti.SPool.New = func() any { 203 v := reflect.MakeSlice(ti.BaseType, 0, int(ti.SPoolN)) // SPoolN) 204 p := reflectValueToPointer(&v) 205 pH := (*SliceHeader)(p) 206 pH.Cap = pH.Cap * int(sliceType.Size()) 207 return (*[]uint8)(p) 208 } 209 ti.SPool2 = NewBatchObj(subSon.BaseType) 210 } 211 case reflect.Struct: 212 var sonIdx uintptr = 0 213 ti.fUnm, ti.fM = structMFuncs(pidx, &sonIdx) 214 215 son, err = NewStructTagInfo(baseType, ancestors) 216 // goType := UnpackType(baseType) 217 // son, err = LoadTagNodeByType(baseType, goType.Hash) 218 if err != nil { 219 return nil, lxterrs.Wrap(err, "Struct") 220 } 221 son.fUnm, son.fM = ti.fUnm, ti.fM 222 if son != nil && son.ptrCacheType != nil { 223 ptrBuilder.AppendTagField(son.ptrCacheType, &sonIdx) //TODO: 如果是 slice 这里需要处理成 slice 模式 224 } 225 if son == nil { 226 // TODO: fUnm中需要重建 store.pool,并从 227 // tag, err := LoadTagNode(vi, goType.Hash) 获取 tag,需要延后处理? 228 ti.fUnm, ti.fM = structMFuncs(pidx, &sonIdx) 229 } 230 // 匿名成员的处理; 这里只能处理费指针嵌入,指针嵌入逻辑在上一层 231 if !anonymous { 232 if son.slicePoolType != nil { 233 sliceBuilder.AppendTagField(son.slicePoolType, &ti.idxSliceObjPool) 234 // ti.slicePool.New = son.slicePool.New 235 // ti.slicePoolType = son.slicePoolType 236 // ti.ptrCache = son.ptrCache 237 // ti.ptrCacheType = son.ptrCacheType 238 } 239 for _, c := range son.ChildList { 240 err = ti.AddChild(c) 241 if err != nil { 242 return nil, lxterrs.Wrap(err, "AddChild") 243 } 244 } 245 // ti.buildChildMap() 246 } else { 247 for _, c := range son.ChildList { 248 if ptrDeep == 0 { 249 c.Offset += ti.Offset 250 } else { 251 fUnm, fM := c.fUnm, c.fM 252 c.fM = func(store Store, in []byte) (out []byte) { 253 store.obj = *(*unsafe.Pointer)(store.obj) 254 if store.obj != nil { 255 return fM(store, in) 256 } 257 out = append(in, "null"...) 258 return 259 } 260 c.fUnm = func(idxSlash int, store PoolStore, stream string) (i, iSlash int) { 261 store.obj = *(*unsafe.Pointer)(store.obj) 262 if store.obj == nil { 263 store.obj = store.Idx(*pidx) 264 } 265 return fUnm(idxSlash, store, stream) 266 } 267 } 268 err = ti.AddChild(c) 269 if err != nil { 270 return nil, lxterrs.Wrap(err, "AddChild") 271 } 272 } 273 } 274 case reflect.Interface: 275 // Interface 需要根据实际类型创建 276 ti.fUnm, ti.fM = interfaceMFuncs(pidx) 277 278 case reflect.Map: 279 ti.fUnm, ti.fM = mapMFuncs(pidx) 280 valueType := baseType.Elem() 281 son = &TagInfo{ 282 TagName: `"son"`, 283 TypeSize: int(valueType.Size()), // TODO 284 // Builder: ti.Builder, 285 } 286 err = ti.AddChild(son) 287 if err != nil { 288 return nil, lxterrs.Wrap(err, "Struct") 289 } 290 subSon, err := son.setFuncs(ptrBuilder, sliceBuilder, valueType, false /*anonymous*/, ancestors) 291 if err != nil { 292 return nil, lxterrs.Wrap(err, "Struct") 293 } 294 _ = subSon 295 default: 296 return nil, lxterrs.New("errors type:%s", baseType) 297 } 298 299 // 处理一下指针 300 for i := 1; i < ptrDeep; i++ { 301 var idxP *uintptr = &[]uintptr{0}[0] 302 ptrBuilder.AppendPointer(fmt.Sprintf("%s_%d", ti.TagName, i), idxP) 303 fUnm, fM := ti.fUnm, ti.fM 304 ti.fUnm = func(idxSlash int, store PoolStore, stream string) (i, iSlash int) { 305 store.obj = store.Idx(*idxP) 306 return fUnm(idxSlash, store, stream) 307 } 308 ti.fM = func(store Store, in []byte) (out []byte) { 309 store.obj = *(*unsafe.Pointer)(store.obj) 310 return fM(store, in) 311 } 312 } 313 314 return 315 } 316 317 //NewStructTagInfo 解析struct的tag字段,并返回解析的结果 318 /* 319 每个 struct 都搞一个 pointerCacheType,在使用的时候直接获取; 再搞一个 slicePool 在是 slice 时使用; 320 二者不会同一时刻出现,是不是可以合并为同一个值? 321 */ 322 func NewStructTagInfo(typIn reflect.Type, ancestors []ancestor) (ti *TagInfo, err error) { 323 if typIn.Kind() != reflect.Struct { 324 err = lxterrs.New("NewStructTagInfo only accepts structs; got %v", typIn.Kind()) 325 return 326 } 327 328 ptrBuilder := NewTypeBuilder() 329 sliceBuilder := NewTypeBuilder() 330 ti = &TagInfo{ 331 BaseType: typIn, 332 TagName: typIn.String(), 333 BaseKind: typIn.Kind(), // 解析出最内层类型 334 TypeSize: int(typIn.Size()), 335 } 336 337 // 通过 ancestors 避免死循环 338 goType := UnpackType(typIn) 339 isNestedLoop := false // 是否嵌套循环 340 for _, a := range ancestors { 341 if a.hash == goType.Hash { 342 ti = nil // 以返回 nil 来处理后续逻辑 343 344 // TODO: 暂时不支持嵌套循环类型 345 panic("Nested loops are not yet supported") 346 return // 避免嵌套循环 347 isNestedLoop = true 348 _ = isNestedLoop 349 break 350 /* 351 // TODO: 针对循环类型 352 // fUnm 和 fM 里重新创建缓存和对象,再获取 tag 继续往下执行 353 store := PoolStore{ 354 tag: tag, 355 obj: prv.ptr, // eface.Value, 356 pointerPool: tag.ptrCache.Get(), 357 } 358 //slice 才需要的缓存 359 if tag.slicePool.New != nil { 360 store.slicePool = tag.slicePool.Get().(unsafe.Pointer) 361 store.dynPool = dynPool.Get().(*dynamicPool) 362 363 err = parseRoot(bs[i:], store) 364 365 tag.slicePool.Put(store.slicePool) 366 dynPool.Put(store.dynPool) 367 } else { 368 err = parseRoot(bs[i:], store) 369 } 370 */ 371 } 372 } 373 ancestors = append(ancestors, ancestor{goType.Hash, ti}) 374 375 // 解析 struct 成员类型 376 for i := 0; i < typIn.NumField(); i++ { 377 field := typIn.Field(i) 378 son := &TagInfo{ 379 BaseType: field.Type, 380 Offset: field.Offset, 381 BaseKind: field.Type.Kind(), 382 TypeSize: int(field.Type.Size()), 383 TagName: field.Name, 384 // TagName: `"` + field.Name + `"`, 385 } 386 387 if !field.IsExported() { 388 continue // 非导出成员不处理 389 } 390 fieldTag := newtag(field.Tag.Get("json")) //从tag列表中取出下标为i的tag //json:"field,string" 391 if fieldTag.negligible() { 392 continue 393 } 394 if !fieldTag.empty() { 395 son.TagName, son.StringTag, son.OmitemptyTag = fieldTag.parse() 396 } 397 398 // 最复杂的一部分,处理不同类型的 Handler 399 _, err = son.setFuncs(ptrBuilder, sliceBuilder, field.Type, field.Anonymous, ancestors) 400 if err != nil { 401 err = lxterrs.Wrap(err, "son.setFuncs") 402 return 403 } 404 if !field.Anonymous { 405 if len(son.ChildList) > 0 { 406 son.tireTree, err = NewTireTree(son.ChildList) 407 if err != nil { 408 return 409 } 410 } 411 err = ti.AddChild(son) 412 if err != nil { 413 return 414 } 415 } else { 416 // 如果是匿名成员类型,需要将其子成员插入为父节点的子成员; 417 // 此外,get set 函数也要做相应修改 418 for _, c := range son.ChildList { 419 err = ti.AddChild(c) 420 if err != nil { 421 return 422 } 423 } 424 } 425 } 426 if len(ti.ChildList) > 0 { 427 ti.tireTree, err = NewTireTree(ti.ChildList) 428 if err != nil { 429 return 430 } 431 } 432 433 // 缓存处理 434 if len(ptrBuilder.fields) > 0 { 435 ti.ptrCacheType = ptrBuilder.Build() 436 ti.ptrCache = NewBatchObj(ti.ptrCacheType) 437 } 438 439 ti.slicePoolType = sliceBuilder.Build() 440 441 return 442 } 443 444 type tag string 445 446 func newtag(tagv string) tag { 447 tagv = strings.TrimSpace(tagv) 448 return tag(tagv) 449 } 450 451 // 应该忽视的 452 func (t tag) negligible() bool { 453 if t == "-" { 454 return true 455 } 456 return false 457 } 458 459 func (t tag) empty() bool { 460 if t == "" { 461 return true 462 } 463 return false 464 } 465 466 func (t tag) parse() (name string, bString, bOmitempty bool) { 467 tvs := strings.Split(string(t), ",") 468 // name = `"` + strings.TrimSpace(tvs[0]) + `"` // 此处加上 双引号 是为了方便使用 改进后的 hash map 469 name = strings.TrimSpace(tvs[0]) // 此处加上 双引号 是为了方便使用 改进后的 hash map 470 471 for i := 1; i < len(tvs); i++ { 472 v := strings.TrimSpace(tvs[i]) 473 if v == "string" { 474 bString = true 475 continue 476 } 477 if v == "omitempty" { 478 bOmitempty = true 479 continue 480 } 481 } 482 return 483 }