github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/reflector/reflector.go (about) 1 package reflector 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 "sync" 8 ) 9 10 type fieldListingType int 11 12 const ( 13 fieldsAll fieldListingType = iota 14 fieldsAnonymous 15 fieldsFlattenAnonymous 16 fieldsNoFlattenAnonymous 17 ) 18 19 var ( 20 metadataCache = map[reflect.Type]*ObjMetadata{} 21 metadataCacheMutex sync.RWMutex 22 ) 23 24 func updateCache(ty reflect.Type, o *Obj) { 25 metadataCacheMutex.Lock() 26 defer metadataCacheMutex.Unlock() 27 28 metadataCache[ty] = o.ObjMetadata 29 } 30 31 // ObjMetadata contains data which is always unique per Type. 32 type ObjMetadata struct { 33 isStruct bool 34 isPtrToStruct bool 35 36 // If ptr to struct, this field will contain the type of that struct 37 underlyingType reflect.Type 38 39 objType reflect.Type 40 objKind reflect.Kind 41 42 fields map[string]*ObjFieldMetadata 43 44 fieldNamesAll []string 45 fieldNamesAnonymous []string 46 fieldNamesFlattenAnonymous []string 47 fieldNamesNoFlattenAnonymous []string 48 49 methods map[string]*ObjMethodMetadata 50 methodNames []string 51 } 52 53 func newObjMetadata(ty reflect.Type) *ObjMetadata { 54 res := new(ObjMetadata) 55 if ty == nil { 56 res.objKind = reflect.Invalid 57 return res 58 } 59 60 res.objType = ty 61 res.objKind = res.objType.Kind() 62 63 if ty.Kind() == reflect.Struct { 64 res.isStruct = true 65 } else if ty.Kind() == reflect.Ptr && ty.Elem().Kind() == reflect.Struct { 66 ty = ty.Elem() 67 res.isPtrToStruct = true 68 } 69 res.underlyingType = ty 70 71 allFields := res.getFields(res.objType, fieldsAll) 72 73 res.fieldNamesAll = allFields 74 res.fieldNamesAnonymous = res.getFields(res.objType, fieldsAnonymous) 75 res.fieldNamesFlattenAnonymous = res.getFields(res.objType, fieldsFlattenAnonymous) 76 res.fieldNamesNoFlattenAnonymous = res.getFields(res.objType, fieldsNoFlattenAnonymous) 77 78 res.methods = map[string]*ObjMethodMetadata{} 79 res.methodNames = []string{} 80 81 if res.objKind != reflect.Invalid { 82 res.fields = map[string]*ObjFieldMetadata{} 83 for _, fieldName := range allFields { 84 metadata := newObjFieldMetadata(fieldName, res) 85 res.fields[fieldName] = metadata 86 res.fields[strings.ToLower(fieldName)] = metadata 87 } 88 for i := 0; i < res.objType.NumMethod(); i++ { 89 method := res.objType.Method(i) 90 res.methodNames = append(res.methodNames, method.Name) 91 metadata := newObjMethodMetadata(method.Name, res) 92 res.methods[method.Name] = metadata 93 res.methods[strings.ToLower(method.Name)] = metadata 94 } 95 } 96 97 return res 98 } 99 100 // IsStructOrPtrToStruct checks if the value is a struct or a pointer to a struct. 101 func (om *ObjMetadata) IsStructOrPtrToStruct() bool { 102 return om.isStruct || om.isPtrToStruct 103 } 104 105 func (om *ObjMetadata) appendFields(fields []string, field reflect.StructField, listingType fieldListingType) []string { 106 if k := field.Type.Kind(); listingType == fieldsAnonymous { 107 if field.Anonymous { 108 fields = append(fields, field.Name) 109 } 110 } else if listingType == fieldsAll { 111 fields = append(fields, field.Name) 112 if k == reflect.Struct && field.Anonymous { 113 fields = append(fields, om.getFields(field.Type, listingType)...) 114 } 115 } else if listingType == fieldsFlattenAnonymous && k == reflect.Struct && field.Anonymous { 116 fields = append(fields, om.getFields(field.Type, listingType)...) 117 } else { 118 fields = append(fields, field.Name) 119 } 120 return fields 121 } 122 123 func (om *ObjMetadata) getFields(ty reflect.Type, listingType fieldListingType) []string { 124 var fields []string 125 126 if ty.Kind() == reflect.Ptr { 127 ty = ty.Elem() 128 } 129 130 if ty.Kind() != reflect.Struct { 131 return fields // No need to populate nonstructs 132 } 133 134 for i := 0; i < ty.NumField(); i++ { 135 f := ty.Field(i) 136 fields = om.appendFields(fields, f, listingType) 137 } 138 139 return fields 140 } 141 142 // ObjFieldMetadata contains data which is always unique per Type/Field. 143 type ObjFieldMetadata struct { 144 name string 145 146 structField reflect.StructField 147 148 // Valid here is not yet the final info about an actual field validity, 149 // because value field still have .IsValid() 150 valid bool 151 152 fieldKind reflect.Kind 153 fieldType reflect.Type 154 } 155 156 func newObjFieldMetadata(name string, objMetadata *ObjMetadata) *ObjFieldMetadata { 157 res := &ObjFieldMetadata{} 158 res.fieldKind = reflect.Invalid 159 res.name = name 160 if objMetadata.IsStructOrPtrToStruct() { 161 var found bool 162 var structField reflect.StructField 163 if objMetadata.isPtrToStruct { 164 structField, found = objMetadata.objType.Elem().FieldByName(res.name) 165 } else { 166 structField, found = objMetadata.objType.FieldByName(res.name) 167 } 168 res.structField = structField 169 res.fieldType = structField.Type 170 if res.fieldType == nil { 171 res.valid = false 172 } else { 173 res.fieldKind = structField.Type.Kind() 174 res.valid = found 175 } 176 } 177 return res 178 } 179 180 // ObjMethodMetadata contains data 181 // which is always unique per Type/Method. 182 type ObjMethodMetadata struct { 183 name string 184 method reflect.Method 185 valid bool 186 } 187 188 func newObjMethodMetadata(name string, objMetadata *ObjMetadata) *ObjMethodMetadata { 189 res := &ObjMethodMetadata{name: name} 190 191 if objMetadata.objKind == reflect.Invalid { 192 res.valid = false 193 } else { 194 if method, found := objMetadata.objType.MethodByName(name); found { 195 res.method = method 196 res.valid = res.method.Func.IsValid() 197 } else { 198 res.valid = false 199 } 200 } 201 202 return res 203 } 204 205 // Obj is a wrapper for golang values which need to be reflected. 206 // The value can be of any kind and any type. 207 type Obj struct { 208 iface interface{} 209 // Value used to work with fields. The only special case is when iface is a pointer to a struct, in 210 // that case this is the value of that struct: 211 fieldsValue reflect.Value 212 *ObjMetadata 213 } 214 215 // NewFromType creates a new Obj but using reflect.Type. 216 func NewFromType(ty reflect.Type) *Obj { 217 if ty == nil { 218 return New(nil) 219 } 220 return New(reflect.New(ty).Interface()) 221 } 222 223 // New initializes a new Obj wrapper. 224 func New(obj interface{}) *Obj { 225 o := &Obj{iface: obj} 226 227 ty := reflect.TypeOf(obj) 228 metadataCacheMutex.RLock() 229 metadata, found := metadataCache[ty] 230 metadataCacheMutex.RUnlock() 231 if found { 232 o.ObjMetadata = metadata 233 } else { 234 o.ObjMetadata = newObjMetadata(reflect.TypeOf(obj)) 235 updateCache(ty, o) 236 } 237 238 o.fieldsValue = reflect.Indirect(reflect.ValueOf(obj)) 239 240 return o 241 } 242 243 // IsValid checks if the underlying objects is valid. 244 // Nil is an invalid value, for example. 245 func (o *Obj) IsValid() bool { return o.objKind != reflect.Invalid } 246 247 // Len returns object length. Works for arrays, channels, maps, slices and strings. 248 // 249 // It doesn't panic for other types, returns 0 instead. 250 // 251 // In case the value is a pointer, len checks the underlying value. 252 func (o *Obj) Len() int { 253 switch o.fieldsValue.Kind() { 254 case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String: 255 return o.fieldsValue.Len() 256 } 257 return 0 258 } 259 260 // IsGettableByIndex returns true if underlying type is array, slice or string 261 func (o *Obj) IsGettableByIndex() bool { 262 switch o.fieldsValue.Kind() { 263 case reflect.Array, reflect.Slice, reflect.String: 264 return true 265 default: 266 return false 267 } 268 } 269 270 // IsSettableByIndex returns true if underlying type is array, slice (but not string, since they are immutable) 271 func (o *Obj) IsSettableByIndex() bool { 272 switch o.fieldsValue.Kind() { 273 case reflect.Array, reflect.Slice: 274 return true 275 default: 276 return false 277 } 278 } 279 280 // IsMap returns true if underlying type is map or a pointer to a map 281 func (o *Obj) IsMap() bool { 282 switch o.fieldsValue.Kind() { 283 case reflect.Map: 284 return true 285 default: 286 return false 287 } 288 } 289 290 // GetByIndex returns a value by int index. 291 // 292 // Works for arrays, slices and strins. Won't panic when index or kind is invalid. 293 func (o *Obj) GetByIndex(index int) (value interface{}, found bool) { 294 defer func() { 295 if err := recover(); err != nil { 296 value = nil 297 found = false 298 } 299 }() 300 301 if o.IsGettableByIndex() { 302 if 0 <= index && index < o.fieldsValue.Len() { 303 value = o.fieldsValue.Index(index).Interface() 304 found = true 305 return 306 } 307 } 308 309 return 310 } 311 312 // SetByIndex sets a slice value by key. 313 func (o *Obj) SetByIndex(index int, val interface{}) error { 314 if index < 0 || o.Len() <= index { 315 return fmt.Errorf("cannot set element %d", index) 316 } 317 318 if o.IsSettableByIndex() { 319 elem := o.fieldsValue.Index(index) 320 elem.Set(reflect.ValueOf(val)) 321 return nil 322 } 323 324 return fmt.Errorf("cannot set element %d of %s", index, o.fieldsValue.String()) 325 } 326 327 // Keys return map keys in unspecified order. 328 func (o *Obj) Keys() ([]interface{}, error) { 329 if o.IsMap() { 330 keys := o.fieldsValue.MapKeys() 331 res := make([]interface{}, len(keys)) 332 for n := range keys { 333 res[n] = keys[n].Interface() 334 } 335 return res, nil 336 } 337 return nil, fmt.Errorf("invalid type %s", o.Type().String()) 338 } 339 340 // SetByKey sets a map value by key. 341 func (o *Obj) SetByKey(key interface{}, val interface{}) (err error) { 342 defer func() { 343 if e := recover(); e != nil { 344 err = fmt.Errorf("cannot set key %s: %v", key, e) 345 } 346 }() 347 348 if o.IsMap() { 349 o.fieldsValue.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(val)) 350 return 351 } 352 err = fmt.Errorf("cannot set key %s: %w", key, err) 353 return 354 } 355 356 // GetByKey returns a value by map key. 357 // 358 // Won't panic when key is invalid or kind is not map. 359 func (o *Obj) GetByKey(key interface{}) (value interface{}, found bool) { 360 defer func() { 361 if err := recover(); err != nil { 362 value = nil 363 found = false 364 } 365 }() 366 367 if o.IsMap() { 368 v := o.fieldsValue.MapIndex(reflect.ValueOf(key)) 369 if !v.IsValid() { 370 found = false 371 return 372 } 373 value = v.Interface() 374 found = true 375 return 376 } 377 return 378 } 379 380 // Fields returns fields. 381 // Don't list fields inside Anonymous fields as distinct fields. 382 func (o *Obj) Fields() []ObjField { return o.getFields(fieldsNoFlattenAnonymous) } 383 384 // FieldsFlattened returns fields. 385 // Will not list Anonymous fields but it will list fields declared in those anonymous fields. 386 func (o Obj) FieldsFlattened() []ObjField { return o.getFields(fieldsFlattenAnonymous) } 387 388 // FieldsAll returns fields. 389 // List both anonymous fields and fields declared inside anonymous fields. 390 func (o Obj) FieldsAll() []ObjField { return o.getFields(fieldsAll) } 391 392 // FieldsAnonymous returns only anonymous fields. 393 func (o Obj) FieldsAnonymous() []ObjField { return o.getFields(fieldsAnonymous) } 394 395 func (o *Obj) getFields(listingType fieldListingType) []ObjField { 396 var fieldNames []string 397 switch listingType { 398 case fieldsAll: 399 fieldNames = o.fieldNamesAll 400 case fieldsAnonymous: 401 fieldNames = o.fieldNamesAnonymous 402 case fieldsFlattenAnonymous: 403 fieldNames = o.fieldNamesFlattenAnonymous 404 case fieldsNoFlattenAnonymous: 405 fieldNames = o.fieldNamesNoFlattenAnonymous 406 default: 407 panic(fmt.Sprintf("Invalid field listing type %d", listingType)) 408 } 409 410 res := make([]ObjField, len(fieldNames)) 411 for n, fieldName := range fieldNames { 412 res[n] = *o.Field(fieldName) 413 } 414 415 return res 416 } 417 418 // FindDoubleFields checks if this object has declared 419 // multiple fields with a same name. 420 // (by checking recursively Anonymous fields and their fields) 421 func (o Obj) FindDoubleFields() []string { 422 fields := map[string]int{} 423 var res []string 424 for _, f := range o.FieldsAll() { 425 counter := fields[f.name] 426 if counter == 1 { 427 res = append(res, f.name) 428 } 429 fields[f.name] = counter + 1 430 } 431 return res 432 } 433 434 // IsPtr checks if the value is a pointer. 435 func (o Obj) IsPtr() bool { return o.objKind == reflect.Ptr } 436 437 // FieldByTag get a field by tag=value. 438 // Note that the field name can be invalid. 439 // You can check the field validity using ObjField.IsValid(). 440 func (o *Obj) FieldByTag(tag, fieldName string) *ObjField { 441 for _, v := range o.fields { 442 if v.structField.Tag.Get(tag) == fieldName { 443 return newObjField(o, v) 444 } 445 } 446 447 return newObjField(o, &ObjFieldMetadata{name: fieldName, valid: false, fieldKind: reflect.Invalid}) 448 } 449 450 // Field get a field wrapper. 451 // Note that the field name can be invalid. 452 // You can check the field validity using ObjField.IsValid(). 453 func (o *Obj) Field(fieldName string) *ObjField { 454 if o.fieldsValue.IsValid() { 455 if metadata, found := o.fields[fieldName]; found { 456 return newObjField(o, metadata) 457 } 458 } 459 return newObjField(o, &ObjFieldMetadata{name: fieldName, valid: false, fieldKind: reflect.Invalid}) 460 } 461 462 // Type returns the value type. 463 // If kind is invalid, this will return a zero filled reflect.Type. 464 func (o Obj) Type() reflect.Type { return o.objType } 465 466 // Kind returns the value's kind. 467 func (o Obj) Kind() reflect.Kind { return o.objKind } 468 469 func (o Obj) String() string { 470 if o.objType == nil { 471 return "nil" 472 } 473 return o.objType.String() 474 } 475 476 // Method returns a new method wrapper. 477 // The method name can be invalid, check the method validity with ObjMethod.IsValid(). 478 func (o *Obj) Method(name string) *ObjMethod { 479 if metadata, found := o.methods[name]; found { 480 return newObjMethod(o, metadata) 481 } 482 return newObjMethod(o, &ObjMethodMetadata{name: name, valid: false}) 483 } 484 485 // Methods returns the list of all methods. 486 func (o *Obj) Methods() []ObjMethod { 487 res := make([]ObjMethod, 0, len(o.methodNames)) 488 for _, name := range o.methodNames { 489 res = append(res, *o.Method(name)) 490 } 491 return res 492 } 493 494 // ObjField is a wrapper for the object's field. 495 type ObjField struct { 496 obj *Obj 497 value reflect.Value 498 499 *ObjFieldMetadata 500 } 501 502 func newObjField(obj *Obj, metadata *ObjFieldMetadata) *ObjField { 503 res := &ObjField{ 504 obj: obj, 505 ObjFieldMetadata: metadata, 506 } 507 508 if metadata.valid && res.obj.IsStructOrPtrToStruct() { 509 res.value = obj.fieldsValue.FieldByName(res.name) 510 } 511 512 return res 513 } 514 515 func (of *ObjField) assertValid() error { 516 if !of.IsValid() { 517 return fmt.Errorf("invalid field %s", of.name) 518 } 519 return nil 520 } 521 522 // IsValid checks if the fields is valid. 523 func (of *ObjField) IsValid() bool { return of.valid && of.value.IsValid() } 524 525 // Name returns the field's name. 526 func (of *ObjField) Name() string { return of.name } 527 528 // Kind returns the field's kind. 529 func (of *ObjField) Kind() reflect.Kind { return of.fieldKind } 530 531 // Type returns the field's type. 532 func (of *ObjField) Type() reflect.Type { return of.fieldType } 533 534 // Tag returns the value of this specific tag 535 // or error if the field is invalid. 536 func (of *ObjField) Tag(tag string) (string, error) { 537 if err := of.assertValid(); err != nil { 538 return "", err 539 } 540 return of.structField.Tag.Get(tag), nil 541 } 542 543 // Tags returns the map of all fields or error for invalid field. 544 func (of *ObjField) Tags() (Tags, error) { 545 if err := of.assertValid(); err != nil { 546 return nil, err 547 } 548 549 tag := of.structField.Tag 550 return ParseTags(string(tag)) 551 } 552 553 // TagExpanded returns the tag value "expanded" with commas. 554 func (of *ObjField) TagExpanded(tag string) ([]string, error) { 555 if err := of.assertValid(); err != nil { 556 return nil, err 557 } 558 return strings.Split(of.structField.Tag.Get(tag), ","), nil 559 } 560 561 // IsAnonymous checks if this is an anonymous (embedded) field. 562 func (of *ObjField) IsAnonymous() bool { 563 if err := of.assertValid(); err != nil { 564 return false 565 } 566 field, found := of.obj.underlyingType.FieldByName(of.name) 567 return found && field.Anonymous 568 } 569 570 // IsExported returns true if the name starts with uppercase (i.e. field is public). 571 func (of *ObjField) IsExported() bool { return of.structField.PkgPath == "" } 572 573 // IsSettable checks if this field is settable. 574 func (of *ObjField) IsSettable() bool { return of.value.CanSet() } 575 576 // Set sets a value for this field or error if field is invalid (or not settable). 577 func (of *ObjField) Set(value interface{}) error { 578 if err := of.assertValid(); err != nil { 579 return err 580 } 581 582 if !of.IsSettable() { 583 return fmt.Errorf("field %s in %T not settable", of.name, of.obj.iface) 584 } 585 586 of.value.Set(reflect.ValueOf(value)) 587 588 return nil 589 } 590 591 // Get gets the field value of error if field is invalid). 592 func (of *ObjField) Get() (interface{}, error) { 593 if err := of.assertValid(); err != nil { 594 return nil, err 595 } 596 if !of.IsExported() { 597 return nil, fmt.Errorf("cannot read unexported field %T.%s", of.obj.iface, of.name) 598 } 599 600 return of.value.Interface(), nil 601 } 602 603 // ObjMethod is a wrapper for an object method. 604 // The name of the method can be invalid. 605 type ObjMethod struct { 606 obj *Obj 607 *ObjMethodMetadata 608 } 609 610 func newObjMethod(obj *Obj, objMethodMetadata *ObjMethodMetadata) *ObjMethod { 611 return &ObjMethod{ 612 obj: obj, 613 ObjMethodMetadata: objMethodMetadata, 614 } 615 } 616 617 // Name returns the method's name. 618 func (om *ObjMethod) Name() string { return om.name } 619 620 const ( 621 onlyInTypes = 0 622 onlyOutTypes = 1 623 ) 624 625 func (om *ObjMethod) methodTypes(kind int) []reflect.Type { 626 m := reflect.ValueOf(om.obj.iface).MethodByName(om.name) 627 if !m.IsValid() { 628 return []reflect.Type{} 629 } 630 ty := m.Type() 631 632 // inTypes are default 633 tyNum := ty.NumIn() 634 tyFn := ty.In 635 if kind == onlyOutTypes { 636 tyNum = ty.NumOut() 637 tyFn = ty.Out 638 } 639 640 out := make([]reflect.Type, tyNum) 641 for i := 0; i < tyNum; i++ { 642 out[i] = tyFn(i) 643 } 644 return out 645 } 646 647 // InTypes returns a slice with this method's input types. 648 func (om *ObjMethod) InTypes() []reflect.Type { return om.methodTypes(onlyInTypes) } 649 650 // OutTypes returns a slice with this method's output types. 651 func (om *ObjMethod) OutTypes() []reflect.Type { return om.methodTypes(onlyOutTypes) } 652 653 // IsValid returns this method's validity. 654 func (om *ObjMethod) IsValid() bool { return om.valid } 655 656 // Call calls this method. 657 // Note that in the error returning value is not the error from the method call. 658 func (om *ObjMethod) Call(args ...interface{}) (*CallResult, error) { 659 if !om.obj.IsValid() { 660 return nil, fmt.Errorf("invalid object type %T for method %s", om.obj.iface, om.name) 661 } 662 if !om.IsValid() { 663 return nil, fmt.Errorf("invalid method %s in %T", om.name, om.obj.iface) 664 } 665 in := make([]reflect.Value, len(args)+1) 666 in[0] = reflect.ValueOf(om.obj.iface) 667 for n := range args { 668 in[n+1] = reflect.ValueOf(args[n]) 669 } 670 out := om.method.Func.Call(in) 671 res := make([]interface{}, len(out)) 672 for n := range out { 673 res[n] = out[n].Interface() 674 } 675 return newCallResult(res), nil 676 } 677 678 // CallResult is a wrapper of a method call result. 679 type CallResult struct { 680 Result []interface{} 681 Error error 682 } 683 684 func newCallResult(res []interface{}) *CallResult { 685 cr := &CallResult{Result: res} 686 if len(res) == 0 { 687 return cr 688 } 689 errorCandidate := res[len(res)-1] 690 if errorCandidate != nil { 691 if err, is := errorCandidate.(error); is { 692 cr.Error = err 693 } 694 } 695 return cr 696 } 697 698 // IsError checks if the last value is a non-nil error. 699 func (cr *CallResult) IsError() bool { return cr.Error != nil }