github.com/hedzr/evendeep@v0.4.8/structiterator.go (about) 1 package evendeep 2 3 import ( 4 "reflect" 5 "strings" 6 "sync" 7 8 "github.com/hedzr/log" 9 10 "github.com/hedzr/evendeep/dbglog" 11 "github.com/hedzr/evendeep/flags/cms" 12 "github.com/hedzr/evendeep/internal" 13 "github.com/hedzr/evendeep/internal/cl" 14 "github.com/hedzr/evendeep/internal/tool" 15 ) 16 17 // 18 19 // fieldsTableT is an accessor to struct fields. 20 type fieldsTableT struct { 21 tableRecordsT 22 autoExpandStruct bool 23 typ reflect.Type // struct type 24 val reflect.Value // struct value 25 fastIndices map[string]*tableRecT 26 } 27 28 type tableRecordsT []*tableRecT 29 30 type tableRecT struct { 31 names []string // the path from root struct, in reverse order 32 indexes []int 33 structFieldValue *reflect.Value 34 structField *reflect.StructField 35 } 36 37 func (rec tableRecT) FieldValue() *reflect.Value { return rec.structFieldValue } 38 func (rec tableRecT) StructField() *reflect.StructField { return rec.structField } 39 func (rec tableRecT) FieldName() string { 40 // return strings.Join(reverseStringSlice(rec.names), ".") 41 var sb strings.Builder 42 for i := len(rec.names) - 1; i >= 0; i-- { 43 if sb.Len() > 0 { 44 sb.WriteRune('.') 45 } 46 sb.WriteString(rec.names[i]) 47 } 48 return sb.String() 49 } 50 func (rec tableRecT) ShortFieldName() string { 51 if len(rec.names) > 0 { 52 return rec.names[0] 53 } 54 return "" 55 } 56 func (rec tableRecT) ShouldIgnore() bool { 57 if rec.structField != nil { 58 ft := parseFieldTags(rec.structField.Tag, "") 59 return ft.flags.IsGroupedFlagOK(cms.Ignore) 60 } 61 return false 62 } 63 64 func (table *fieldsTableT) isReservedPackage(field *reflect.StructField, typ reflect.Type, kind reflect.Kind) bool { 65 n := typ.PkgPath() 66 return packageisreserved(n) // ignore golang stdlib, such as "io", "runtime", ... 67 } 68 69 func (table *fieldsTableT) getAllFields(structValue reflect.Value, autoexpandstruct bool) fieldsTableT { 70 table.autoExpandStruct = autoexpandstruct 71 72 structValue, _ = tool.Rdecode(structValue) 73 if structValue.Kind() != reflect.Struct { 74 return *table 75 } 76 77 styp := structValue.Type() 78 ret := table.getFields(&structValue, styp, "", -1) 79 table.tableRecordsT = append(table.tableRecordsT, ret...) 80 81 table.typ = styp 82 table.val = structValue 83 84 table.fastIndices = make(map[string]*tableRecT) 85 for _, ni := range table.tableRecordsT { 86 if internal.VerboseStructIterating { 87 dbglog.Log(" - ni: %v", ni.ShortFieldName()) 88 } 89 table.fastIndices[ni.ShortFieldName()] = ni 90 } 91 92 return *table 93 } 94 95 func (table *fieldsTableT) safeGetStructFieldValueInd(structValue *reflect.Value, i int) *reflect.Value { 96 if structValue != nil && structValue.IsValid() { 97 for structValue.Kind() == reflect.Ptr { 98 v := structValue.Elem() 99 structValue = &v 100 } 101 if structValue != nil && structValue.IsValid() { 102 sv := structValue.Field(i) 103 return &sv 104 } 105 } 106 return nil 107 } 108 109 //nolint:lll //keep it 110 func (table *fieldsTableT) getFields(structValue *reflect.Value, structType reflect.Type, fieldName string, fi int) (ret tableRecordsT) { 111 st := tool.Rdecodetypesimple(structType) 112 if st.Kind() != reflect.Struct { 113 return 114 } 115 116 var i, amount int 117 for i, amount = 0, st.NumField(); i < amount; i++ { 118 var tr *tableRecT 119 120 sf := structType.Field(i) 121 sftyp := sf.Type 122 sftypind := tool.RindirectType(sftyp) 123 svind := table.safeGetStructFieldValueInd(structValue, i) 124 sftypindKind := sftypind.Kind() 125 isStruct := sftypindKind == reflect.Struct 126 isReservedPackage := table.isReservedPackage(&sf, sftypind, sftypindKind) 127 128 tr = table.tableRec(svind, &sf, i, fi, fieldName) 129 130 if isStruct && table.autoExpandStruct && !isReservedPackage { 131 if internal.VerboseStructIterating { 132 // only printed on `-tags="structiterating,verbose" 133 dbglog.Log(" field %d: %v (%v) (%v) || %v", i, sf.Name, 134 tool.Typfmt(sftyp), tool.Typfmt(sftypind), tr.FieldValue()) 135 } 136 137 if !tr.ShouldIgnore() { 138 // struct, or pointer to struct has been found and we will get into it 139 n := table.getFields(svind, sftypind, sf.Name, i) 140 if len(n) > 0 { 141 ret = append(ret, n...) 142 } else { 143 // add empty struct 144 tr = table.tableRec(svind, &sf, sf.Index[0], 0, "") 145 ret = append(ret, tr) 146 } 147 continue 148 } 149 } else if internal.VerboseStructIterating { 150 dbglog.Log(" field %d: %v (%v) (%v) || %v", i, sf.Name, 151 tool.Typfmt(sftyp), tool.Typfmt(sftypind), tool.Valfmtptr(tr.FieldValue())) 152 } 153 154 ret = append(ret, tr) 155 } 156 return 157 } 158 159 //nolint:lll //keep it 160 func (table *fieldsTableT) tableRec(svind *reflect.Value, sf *reflect.StructField, index, parentIndex int, parentFieldName string) (tr *tableRecT) { 161 tr = new(tableRecT) 162 163 tr.structField = sf 164 if tool.IsExported(sf) { 165 tr.structFieldValue = svind 166 } else if svind.CanAddr() { 167 val := cl.GetUnexportedField(*svind) 168 tr.structFieldValue = &val 169 } 170 tr.names = append(tr.names, sf.Name) 171 if parentFieldName != "" { 172 tr.names = append(tr.names, parentFieldName) 173 } 174 tr.indexes = append(tr.indexes, index) 175 if parentIndex >= 0 { 176 tr.indexes = append(tr.indexes, parentIndex) 177 } 178 return 179 } 180 181 // 182 183 // 184 185 // structIterable provides a struct fields iterable interface. 186 type structIterable interface { 187 // Next returns the next field as an accessor. 188 // 189 // Next iterates all fields by ordinal, and enter any 190 // inner struct for the children, expect empty struct. 191 // 192 // For an empty struct, Next return it exactly rather than 193 // field since it has nothing to iterate. 194 Next(params *Params, byName bool) (accessor accessor, ok bool) 195 196 // SourceFieldShouldBeIgnored _. 197 SourceFieldShouldBeIgnored(ignoredNames []string) (yes bool) 198 // ShouldBeIgnored _. 199 ShouldBeIgnored(name string, ignoredNames []string) (yes bool) 200 } 201 202 type structIterableOpt func(s *structIteratorT) 203 204 // 205 206 // newStructIterator return a deep recursive iterator for the given 207 // struct value. 208 // 209 // The structIterable.Next() will enumerate all children fields. 210 func newStructIterator(structValue reflect.Value, opts ...structIterableOpt) structIterable { 211 s := &structIteratorT{ 212 dstStruct: structValue, 213 stack: nil, 214 } 215 for _, opt := range opts { 216 opt(s) 217 } 218 return s 219 } 220 221 // withStructPtrAutoExpand allows auto-expanding the struct or its pointer 222 // in iterating a parent struct. 223 func withStructPtrAutoExpand(expand bool) structIterableOpt { 224 return func(s *structIteratorT) { 225 s.autoExpandStruct = expand 226 } 227 } 228 229 // withStructFieldPtrAutoNew allows auto-expanding the struct or its pointer 230 // in iterating a parent struct. 231 func withStructFieldPtrAutoNew(create bool) structIterableOpt { 232 return func(s *structIteratorT) { 233 s.autoNew = create 234 } 235 } 236 237 // withStructSource _. 238 func withStructSource(srcstructval *reflect.Value, autoexpand bool) structIterableOpt { 239 return func(s *structIteratorT) { 240 if srcstructval != nil { 241 s.srcFields = s.srcFields.getAllFields(*srcstructval, autoexpand) 242 s.withSourceIteratorIndexIncrease(-10000) // reset srcIndex to 0 243 } 244 } 245 } 246 247 // 248 249 type structIteratorT struct { 250 srcFields fieldsTableT // source struct fields accessors 251 srcIndex int // source field index 252 dstStruct reflect.Value // target struct 253 dstIndex int // counter for Next() 254 stack []*fieldAccessorT // target fields accessors 255 autoExpandStruct bool // Next() will expand *struct to struct and get inside loop deeply 256 noExpandIfSrcFieldIsFunc bool // 257 autoNew bool // create new inner objects for the child ptr,map,chan,..., if necessary 258 } 259 260 // accessor represents a struct field accessor which can be used for getting or setting. 261 // Before you can operate it, do verify on ValueValid(). 262 type accessor interface { 263 Set(v reflect.Value) 264 265 IsStruct() bool 266 267 Type() reflect.Type 268 ValueValid() bool 269 FieldValue() *reflect.Value 270 FieldType() *reflect.Type 271 StructField() *reflect.StructField // return target struct field type 272 StructFieldName() string // return target struct field name 273 NumField() int 274 275 SourceField() *tableRecT // return source struct (or others types) 276 // SourceFieldShouldBeIgnored(ignoredNames []string) bool 277 278 IsFlagOK(f cms.CopyMergeStrategy) bool 279 IsGroupedFlagOK(f ...cms.CopyMergeStrategy) bool 280 IsAnyFlagsOK(f ...cms.CopyMergeStrategy) bool 281 IsAllFlagsOK(f ...cms.CopyMergeStrategy) bool 282 } 283 284 type fieldAccessorT struct { 285 structValue *reflect.Value 286 structType reflect.Type 287 index int 288 structField *reflect.StructField 289 isStruct bool 290 291 sourceTableRec *tableRecT // a copy of structIteratorT.sourcefields 292 srcStructField *reflect.StructField // source field type 293 fieldTags *fieldTags // tag of source field 294 } 295 296 func setToZero(fieldValue *reflect.Value) { 297 setToZeroAs(fieldValue, fieldValue.Type(), fieldValue.Kind()) 298 } 299 300 func setToZeroAs(fieldValue *reflect.Value, typ reflect.Type, kind reflect.Kind) { 301 if fieldValue.CanSet() { 302 setToZeroAsImpl(fieldValue, typ, kind) 303 } 304 } 305 306 func setToZeroAsImpl(fieldValue *reflect.Value, typ reflect.Type, kind reflect.Kind) { 307 switch kind { //nolint:exhaustive //no need 308 case reflect.Bool: 309 fieldValue.SetBool(false) 310 case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8: 311 fieldValue.SetInt(0) 312 case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uintptr: 313 fieldValue.SetUint(0) 314 case reflect.Float64, reflect.Float32: 315 fieldValue.SetFloat(0) 316 case reflect.Complex128, reflect.Complex64: 317 fieldValue.SetComplex(0 + 0i) 318 case reflect.String: 319 fieldValue.SetString("") 320 case reflect.Slice: 321 v := reflect.New(reflect.SliceOf(fieldValue.Type().Elem())).Elem() 322 fieldValue.Set(v) 323 case reflect.Array: 324 setToZeroForArray(fieldValue, typ, kind) 325 case reflect.Map: 326 v := reflect.MakeMap(fieldValue.Type()) // .Elem() 327 fieldValue.Set(v) 328 case reflect.Ptr: 329 fieldValue.Set(reflect.Zero(typ)) 330 // fieldValue.SetPointer(unsafe.Pointer(uintptr(0))) 331 case reflect.Interface: 332 ind := fieldValue.Elem().Type() 333 fieldValue.Set(reflect.Zero(ind)) 334 335 case reflect.Struct: 336 setToZeroForStruct(fieldValue, typ, kind) 337 default: 338 // Array, Chan, Func, Interface, Invalid, Struct, UnsafePointer 339 dbglog.Log(" NOT SUPPORTED (kind: %v), cannot set to zero value.", kind) 340 } 341 } 342 343 func setToZeroForArray(arrayValue *reflect.Value, typ reflect.Type, kind reflect.Kind) { 344 for i, amount := 0, arrayValue.Len(); i < amount; i++ { 345 v := arrayValue.Index(i) 346 vt, vk := v.Type(), v.Kind() 347 setToZeroAs(&v, vt, vk) 348 } 349 } 350 351 func setToZeroForStruct(structValue *reflect.Value, typ reflect.Type, kind reflect.Kind) { 352 for i, amount := 0, structValue.NumField(); i < amount; i++ { 353 fv := structValue.Field(i) 354 setToZero(&fv) 355 } 356 } 357 358 func (s *fieldAccessorT) Set(v reflect.Value) { 359 if !s.ValueValid() { 360 return 361 } 362 363 if s.isStruct { 364 // dbglog.Log(" target struct type: %v", tool.Typfmt(s.structType)) 365 dbglog.Log(" setting struct.%q", s.structType.Field(s.index).Name) 366 // if !tool.IsZero(*s.structValue) { 367 sv := tool.Rindirect(*s.structValue) 368 fv := sv.Field(s.index) 369 dbglog.Log(" set %v (%v) -> struct.%q", tool.Valfmt(&v), tool.Typfmtv(&v), s.structType.Field(s.index).Name) 370 if v.IsValid() && !tool.IsZero(v) { 371 dbglog.Log(" set to v : %v", tool.Valfmt(&v)) 372 fv.Set(v) 373 } else { 374 dbglog.Log(" setToZero") 375 setToZero(&fv) 376 } 377 // } else { 378 // dbglog.Wrn(` setting struct.%q, but struct is zero (typ = %v).`, s.structType.Field(s.index).Name, tool.Typfmt(s.structType)) 379 // } 380 } else if s.structType.Kind() == reflect.Map { 381 key := s.mapkey() 382 dbglog.Log(" set %v (%v) -> map[%v]", tool.Valfmt(&v), tool.Typfmtv(&v), tool.Valfmt(&key)) 383 s.structValue.SetMapIndex(key, v) 384 } else { 385 dbglog.Wrn(` setting struct field value, but the container has type: %v`, tool.Typfmt(s.structType)) 386 } 387 } 388 func (s *fieldAccessorT) SourceField() *tableRecT { return s.sourceTableRec } 389 func (s *fieldAccessorT) IsFlagOK(f cms.CopyMergeStrategy) bool { 390 if s.fieldTags != nil { 391 return s.fieldTags.flags.IsFlagOK(f) 392 } 393 return false 394 } 395 func (s *fieldAccessorT) IsGroupedFlagOK(f ...cms.CopyMergeStrategy) bool { 396 if s.fieldTags != nil { 397 return s.fieldTags.flags.IsGroupedFlagOK(f...) 398 } 399 return false 400 } 401 func (s *fieldAccessorT) IsAnyFlagsOK(f ...cms.CopyMergeStrategy) bool { 402 if s.fieldTags != nil { 403 return s.fieldTags.flags.IsAnyFlagsOK(f...) 404 } 405 return false 406 } 407 func (s *fieldAccessorT) IsAllFlagsOK(f ...cms.CopyMergeStrategy) bool { 408 if s.fieldTags != nil { 409 return s.fieldTags.flags.IsAllFlagsOK(f...) 410 } 411 return false 412 } 413 func (s *fieldAccessorT) IsStruct() bool { 414 return s.isStruct // s.structType != nil && s.structType.Kind() == reflect.Struct 415 } 416 func (s *fieldAccessorT) Type() reflect.Type { return s.structType } 417 func (s *fieldAccessorT) ValueValid() bool { return s.structValue != nil && s.structValue.IsValid() } 418 func (s *fieldAccessorT) FieldValue() *reflect.Value { 419 if s == nil { 420 return nil 421 } 422 423 if s.isStruct { 424 if s.ValueValid() { 425 vind := tool.Rindirect(*s.structValue) 426 if vind.IsValid() && s.index < vind.NumField() { 427 r := vind.Field(s.index) 428 return &r 429 } 430 } 431 } else { // if s.structType != nil && s.structType.Kind() == reflect.Map { 432 key := s.mapkey() 433 val := s.structValue.MapIndex(key) 434 return &val 435 } 436 return nil 437 } 438 439 //nolint:lll //keep it 440 func (s *fieldAccessorT) FieldType() *reflect.Type { //nolint:gocritic //ptrToRefParam: consider to make non-pointer type for `*reflect.Type` 441 if s != nil { 442 if s.isStruct { 443 sf := s.StructField() 444 if sf != nil { 445 return &sf.Type 446 } 447 } else if s.structType.Kind() == reflect.Map { 448 // name := s.sourceTableRec.FieldName() 449 vt := s.structType.Elem() 450 return &vt 451 } 452 } 453 return nil 454 } 455 func (s *fieldAccessorT) NumField() int { 456 if s.isStruct { 457 sf := s.structType 458 return sf.NumField() 459 // if s.ValueValid() { 460 // return s.structValue.NumField() 461 // } 462 } 463 return 0 464 } 465 func (s *fieldAccessorT) StructField() *reflect.StructField { 466 // if s.ValueValid() { 467 // r := s.structValue.Type().Field(s.index) 468 // s.structField = &r 469 // } 470 // return s.structField 471 return s.getStructField() 472 } 473 func (s *fieldAccessorT) getStructField() *reflect.StructField { 474 if s.isStruct { 475 if s.structField == nil && s.index >= 0 && s.index < s.structType.NumField() { 476 r := s.structType.Field(s.index) 477 s.structField = &r 478 } 479 // if s.ValueValid() { 480 // r := s.structValue.Type().Field(s.index) 481 // s.structField = &r 482 // } 483 return s.structField 484 } 485 return nil 486 } 487 func (s *fieldAccessorT) StructFieldName() string { 488 if s.isStruct { 489 if fld := s.StructField(); fld != nil { 490 return fld.Name 491 } 492 } else if keys := s.structValue.MapKeys(); s.index < len(keys) { 493 ck := keys[s.index] 494 if target, err := rToString(ck, ck.Type()); err == nil { 495 return target.String() 496 } 497 } 498 return "" 499 } 500 func (s *fieldAccessorT) incr() *fieldAccessorT { 501 s.index++ 502 s.structField = nil 503 return s 504 } 505 func (s *fieldAccessorT) ensurePtrField() (newed bool) { 506 if s.isStruct && s.index < s.structType.NumField() { 507 if s.structValue != nil { 508 sf := s.structType.Field(s.index) 509 vind := tool.Rindirect(*s.structValue) 510 // if tool.IsZero(vind) { 511 // fv := vind.Field(s.index) 512 // dbglog.Wrn(`zero value struct cannot .Field(): typ = %v, vind = %v | fv: %v`, tool.Typfmtv(&vind), tool.Valfmt(&vind), tool.Valfmt(&fv)) 513 // return 514 // } 515 if vind.Kind() != reflect.Struct { 516 dbglog.Wrn(`vind isn't struct, cannot .Field(): typ = %v, vind = %v`, tool.Typfmtv(&vind), tool.Valfmt(&vind)) 517 return 518 } 519 fv := vind.Field(s.index) 520 521 switch kind := sf.Type.Kind(); kind { //nolint:exhaustive //no need 522 case reflect.Ptr: 523 if tool.IsNil(fv) { 524 dbglog.Log(" autoNew") 525 if settable := fv.CanSet(); settable || !tool.IsExported(&sf) { // unexported field, try new it 526 typ := sf.Type.Elem() 527 nv := reflect.New(typ) 528 if settable { 529 fv.Set(nv) 530 } else { 531 cl.SetUnexportedField(fv, nv) 532 } 533 newed = true 534 } else { 535 log.Warnf(" gave up since fv.CanSet is false. fv.typ: %v", tool.Typfmtv(&fv)) 536 } 537 } 538 default: 539 } 540 } 541 } 542 return 543 } 544 545 func (s *fieldAccessorT) mapkey() reflect.Value { 546 if s.sourceTableRec == nil { 547 var ck reflect.Value 548 if keys := s.structValue.MapKeys(); s.index < len(keys) { 549 ck = keys[s.index] 550 } 551 return ck 552 } 553 554 name := s.sourceTableRec.ShortFieldName() 555 kt := s.structType.Key() // , s.structType.Elem() 556 var key reflect.Value 557 if kk := kt.Kind(); kk == reflect.String || kk == reflect.Interface { 558 key = reflect.ValueOf(name) 559 } else { 560 // namev := reflect.ValueOf(name) 561 // kp := reflect.New(kt) 562 // fsc := &fromStringConverter{} 563 // if err := fsc.CopyTo(nil, namev, kp.Elem()); err == nil { 564 // key = kp.Elem() 565 // } 566 log.Panicf(`unexpected type of key '%v': %v`, name, kk) 567 } 568 return key 569 } 570 571 // 572 573 // 574 575 func (s *structIteratorT) iipush(structvalue *reflect.Value, structtype reflect.Type, index int) *fieldAccessorT { 576 //nolint:lll //keep it 577 s.stack = append(s.stack, &fieldAccessorT{isStruct: true, structValue: structvalue, structType: structtype, index: index}) 578 return s.iitop() 579 } 580 func (s *structIteratorT) iiempty() bool { return len(s.stack) == 0 } 581 func (s *structIteratorT) iipop() { 582 if len(s.stack) > 0 { 583 s.stack = s.stack[0 : len(s.stack)-1] 584 } 585 } 586 func (s *structIteratorT) iitop() *fieldAccessorT { 587 if len(s.stack) == 0 { 588 log.Panicf(`unexpected iitop() on an empty stack`) 589 // return nil 590 } 591 return s.stack[len(s.stack)-1] 592 } 593 594 // func (s *structIteratorT) iiprev() *fieldAccessorT { 595 // if len(s.stack) <= 1 { 596 // return nil 597 // } 598 // return s.stack[len(s.stack)-1-1] 599 // } 600 601 // func (s *structIteratorT) iiSafegetFieldType() (sf *reflect.StructField) { 602 // 603 // var reprev func(position int) (sf *reflect.StructField) 604 // reprev = func(position int) (sf *reflect.StructField) { 605 // if position >= 0 { 606 // prev := s.stack[position] 607 // var st reflect.Type 608 // if prev.ValueValid() == false { 609 // // try retrieve the field type from previous element in stack (i.e. the 610 // // parent struct of the current field) 611 // sf2 := reprev(position - 1) 612 // if sf2 != nil { 613 // //log.Printf("prev.index = %v, prev.sv.valid = %v, sf = %v", prev.index, prev.ValueValid(), sf2) 614 // st = rdecodetypesimple(sf2.Type) 615 // //log.Printf("sf2.Type/st = %v", st) 616 // if prev.index < st.NumField() { 617 // fld := st.Field(prev.index) 618 // sf = &fld 619 // //log.Printf("typ: %v, name: %v | %v", typfmt(sf.Type), sf.Name, sf) 620 // } 621 // } 622 // } else { 623 // st = prev.Type() 624 // if prev.index < st.NumField() { 625 // fld := st.Field(prev.index) 626 // sf = &fld 627 // } 628 // } 629 // } 630 // return 631 // } 632 // 633 // sf = reprev(len(s.stack) - 1) 634 // return nil 635 // } 636 // 637 // func (s *structIteratorT) iiCheckNilPtr(lastone *fieldAccessorT, field *reflect.StructField) { 638 // lastone.ensurePtrField() 639 // } 640 641 // sourceStructFieldsTable _. 642 type sourceStructFieldsTable interface { 643 TableRecords() tableRecordsT 644 CurrRecord() *tableRecT 645 TableRecord(index int) *tableRecT 646 Step(delta int) 647 RecordByName(name string) *reflect.Value 648 MethodCallByName(name string) (mtd reflect.Method, v *reflect.Value) 649 } 650 651 func (s *structIteratorT) TableRecords() tableRecordsT { return s.srcFields.tableRecordsT } 652 func (s *structIteratorT) CurrRecord() *tableRecT { return s.srcFields.tableRecordsT[s.srcIndex] } 653 func (s *structIteratorT) TableRecord(index int) *tableRecT { return s.srcFields.tableRecordsT[index] } 654 func (s *structIteratorT) Step(delta int) { s.withSourceIteratorIndexIncrease(delta) } 655 656 func (s *structIteratorT) RecordByName(name string) (v *reflect.Value) { 657 if tr, ok := s.srcFields.fastIndices[name]; ok { 658 v = tr.FieldValue() 659 } 660 return 661 } 662 663 func (s *structIteratorT) MethodCallByName(name string) (mtd reflect.Method, v *reflect.Value) { 664 var exists bool 665 if mtd, exists = s.srcFields.typ.MethodByName(name); exists { //nolint:nestif //keep it 666 mtdv := s.srcFields.val.MethodByName(name) 667 retv := mtdv.Call([]reflect.Value{}) 668 if len(retv) > 0 { 669 if len(retv) > 1 { 670 errv := retv[len(retv)-1] 671 if tool.IsNil(errv) && tool.Iserrortype(mtd.Type.Out(len(retv)-1)) { 672 v = &retv[0] 673 } 674 } else { 675 v = &retv[0] 676 } 677 } 678 } 679 return 680 } 681 682 // 683 684 func (s *structIteratorT) withSourceIteratorIndexIncrease(srcIndexDelta int) (sourcefield *tableRecT, ok bool) { 685 if s.srcIndex < 0 { 686 s.srcIndex = 0 687 } 688 689 // if i < params.srcType.NumField() { 690 // t := params.srcType.Field(i) 691 // params.fieldType = &t 692 // params.fieldTags = parseFieldTags(t.Tag) 693 // } 694 695 if s.srcIndex < len(s.srcFields.tableRecordsT) { 696 sourcefield, ok = s.srcFields.tableRecordsT[s.srcIndex], true 697 } 698 699 s.srcIndex += srcIndexDelta 700 if s.srcIndex < 0 { 701 s.srcIndex = 0 702 } 703 704 return 705 } 706 707 func (s *structIteratorT) Next(params *Params, byName bool) (acc accessor, ok bool) { 708 var sourceTableRec *tableRecT 709 var accessorTmp *fieldAccessorT 710 sourceTableRec, ok = s.withSourceIteratorIndexIncrease(+1) 711 if ok { //nolint:nestif //keep it 712 srcStructField := sourceTableRec.StructField() 713 srcIsFunc := srcStructField.Type.Kind() == reflect.Func 714 kind := s.dstStruct.Kind() 715 716 if kind == reflect.Map { 717 return s.doNextMapItem(params, sourceTableRec, srcStructField) 718 } 719 720 if params != nil && byName { 721 return s.doNextFieldByName(sourceTableRec, srcStructField) 722 } 723 724 accessorTmp, ok = s.doNext(srcIsFunc && !s.noExpandIfSrcFieldIsFunc) 725 if ok { 726 accessorTmp.sourceTableRec = sourceTableRec 727 accessorTmp.srcStructField = srcStructField 728 accessorTmp.fieldTags = parseFieldTags(accessorTmp.srcStructField.Tag, "") 729 730 dbglog.Log(" | Next %d | src field: %v (%v) -> %v (%v) | autoexpd: (%v, %v)", 731 s.srcIndex, accessorTmp.sourceTableRec.FieldName(), 732 tool.Typfmt(accessorTmp.srcStructField.Type), 733 accessorTmp.StructFieldName(), tool.Typfmt(accessorTmp.Type()), 734 s.srcFields.autoExpandStruct, s.autoExpandStruct, 735 ) 736 s.dstIndex++ 737 } 738 } else { 739 kind := s.dstStruct.Kind() 740 741 if kind == reflect.Map { 742 return s.doNextMapItem(params, sourceTableRec, nil) 743 } 744 745 accessorTmp, ok = s.doNext(false) 746 if ok { 747 dbglog.Log(" | Next %d | -> %v (%v)", 748 s.dstIndex, 749 accessorTmp.StructFieldName(), tool.Typfmt(accessorTmp.Type())) 750 s.dstIndex++ 751 } 752 } 753 acc = accessorTmp 754 return 755 } 756 757 //nolint:lll //keep it 758 func (s *structIteratorT) doNextMapItem(params *Params, sourceTableRec *tableRecT, srcStructField *reflect.StructField) (acc accessor, ok bool) { 759 checkSourceTypeIsSettable := func(srcStructField *reflect.StructField) (tk reflect.Kind, ok bool) { 760 if srcStructField == nil { 761 return reflect.Invalid, true 762 } 763 st := srcStructField.Type 764 elTyp := s.dstStruct.Type().Elem() 765 tk = elTyp.Kind() 766 ok = st.ConvertibleTo(elTyp) || st.AssignableTo(elTyp) || 767 tk == reflect.String || tk == reflect.Interface 768 return 769 } 770 771 if _, ok = checkSourceTypeIsSettable(srcStructField); ok { 772 acc = &fieldAccessorT{ 773 structValue: &s.dstStruct, 774 structType: s.dstStruct.Type(), 775 index: s.dstIndex, 776 structField: nil, 777 isStruct: false, 778 sourceTableRec: sourceTableRec, 779 srcStructField: srcStructField, 780 fieldTags: nil, 781 } 782 ok = srcStructField != nil || s.dstIndex < len(s.dstStruct.MapKeys()) 783 s.dstIndex++ 784 } 785 return 786 } 787 788 //nolint:lll //keep it 789 func (s *structIteratorT) doNextFieldByName(sourceTableRec *tableRecT, srcStructField *reflect.StructField) (acc accessor, ok bool) { 790 dbglog.Log(" looking for src field: %v", srcStructField) 791 dstFieldName, ignored := s.getTargetFieldNameBySourceField(srcStructField, "") 792 793 ok = true 794 if ignored { 795 return // return ok = true so that caller can continue to the next field, rather than stop looping. 796 } 797 798 dbglog.Log(" looking for field %q (src field: %q)", dstFieldName, srcStructField.Name) 799 var tsf reflect.StructField 800 ts := tool.Rindirect(s.dstStruct) 801 tsf, ok = ts.Type().FieldByName(dstFieldName) 802 if ok { 803 dbglog.Log(" tsf: %v", tsf) 804 // tv := ts.FieldByName(dstFieldName) 805 s.dstIndex = tsf.Index[0] 806 acc = &fieldAccessorT{ 807 structValue: &ts, 808 structType: ts.Type(), 809 index: s.dstIndex, 810 structField: &tsf, 811 isStruct: true, 812 sourceTableRec: sourceTableRec, 813 srcStructField: srcStructField, 814 fieldTags: parseFieldTags(srcStructField.Tag, ""), 815 } 816 } else { 817 log.Warnf(" [WARN] dstFieldName %q NOT FOUND, it'll be ignored", dstFieldName) 818 s.dstIndex = -1 819 acc = &fieldAccessorT{ 820 structValue: &ts, 821 structType: ts.Type(), 822 index: s.dstIndex, // return an empty accessor 823 structField: nil, // return an empty accessor 824 isStruct: true, 825 sourceTableRec: sourceTableRec, 826 srcStructField: srcStructField, 827 fieldTags: parseFieldTags(srcStructField.Tag, ""), 828 } 829 ok = true // return ok = true so caller can keep going to next field 830 } 831 // no need: dstIndex++ 832 return // return ok = false, the caller loop will be broken. 833 } 834 835 //nolint:gocognit //keep it 836 func (s *structIteratorT) doNext(srcFieldIsFuncAndTargetShouldNotExpand bool) (accessor *fieldAccessorT, ok bool) { 837 var lastone *fieldAccessorT 838 var inretry bool 839 840 if s.iiempty() { 841 vind := tool.Rindirect(s.dstStruct) 842 tind := vind.Type() 843 lastone = s.iipush(&vind, tind, 0) 844 } else { 845 uplevel: 846 lastone = s.iitop().incr() 847 if lastone.index >= lastone.NumField() { 848 if len(s.stack) <= 1 { 849 return // no more fields or children can be iterated 850 } 851 s.iipop() 852 goto uplevel 853 } 854 } 855 856 retryExpand: 857 field := lastone.getStructField() 858 if field != nil { //nolint:nestif //keep it 859 // tind := field.Type // rindirectType(field.Type) 860 if s.autoExpandStruct { 861 tind := tool.RindirectType(field.Type) 862 k1 := tind.Kind() 863 dbglog.Log(" typ: %v, name: %v | %v", tool.Typfmt(tind), field.Name, field) 864 if s.autoNew { 865 var did = lastone.ensurePtrField() 866 if did { 867 dbglog.Log(" lastone.ensurePtrField() made ptr field newed.") 868 } 869 } 870 if k1 == reflect.Struct && 871 !srcFieldIsFuncAndTargetShouldNotExpand && 872 !s.typShouldBeIgnored(tind) { 873 fvp := lastone.FieldValue() 874 lastone = s.iipush(fvp, tind, 0) 875 dbglog.Log(" -- (retry) -> filed is struct, typ: %v", tool.Typfmt(tind)) 876 inretry = true 877 goto retryExpand 878 } 879 } else if s.autoNew { 880 lastone.ensurePtrField() 881 } 882 } else { 883 if inretry && lastone.NumField() == 0 { 884 // for an empty struct, go back and up to parent level and 885 // iterate it instead of iterating its fields since there's 886 // no longer fields. 887 // 888 // NOTE that should be cared to prevent endless loop at this 889 // point. 890 s.iipop() 891 lastone = s.iitop() 892 } else { 893 log.Warnf("cannot fetching field, empty struct ? ") 894 } 895 } 896 897 ok, accessor = true, lastone 898 return 899 } 900 901 // func (s *structIteratorT) getTargetFieldName(knownSrcName, tagKeyName string) (dstFieldName string, ignored bool) { 902 // dstFieldName = knownSrcName 903 // 904 // // var flagsInTag *fieldTags 905 // // var ok bool 906 // if sf := s.CurrRecord().StructField(); sf != nil { 907 // dstFieldName, ignored = s.getTargetFieldNameBySourceField(sf, tagKeyName) 908 // // flagsInTag = parseFieldTags(sf.Tag, tagKeyName) 909 // // if ignored = flagsInTag.isFlagExists(cms.Ignore); ignored { 910 // // return 911 // // } 912 // // ctx := &NameConverterContext{Params: nil} 913 // // dstFieldName, ok = flagsInTag.CalcTargetName(sf.Name, ctx) 914 // // if !ok { 915 // // if tr := s.dstStruct.FieldByName(knownSrcName); !tool.IsNil(tr) { 916 // // dstFieldName = knownSrcName 917 // // dbglog.Log(" dstName: %v, ok: %v [pre 2, fld: %v, tag: %v]", dstFieldName, ok, sf.Name, sf.Tag) 918 // // } 919 // // } 920 // } 921 // return 922 // } 923 924 //nolint:lll //keep it 925 func (s *structIteratorT) getTargetFieldNameBySourceField(knownSrcField *reflect.StructField, tagName string) (dstFieldName string, ignored bool) { 926 var flagsInTag *fieldTags 927 var ok bool 928 929 flagsInTag = parseFieldTags(knownSrcField.Tag, tagName) 930 if ignored = flagsInTag.isFlagIgnored(); ignored { 931 dbglog.Log(" [i] field %q (%v) was been ignored", knownSrcField.Name, knownSrcField.Type) 932 return 933 } 934 935 ctx := &NameConverterContext{Params: nil} 936 dstFieldName, ok = flagsInTag.CalcTargetName(knownSrcField.Name, ctx) 937 if !ok { 938 if tr := s.dstStruct.FieldByName(knownSrcField.Name); !tool.IsNil(tr) { 939 dstFieldName = knownSrcField.Name 940 dbglog.Log(" dstName: %v, ok: %v [pre 2, fld: %v, tag: %v]", dstFieldName, ok, knownSrcField.Name, knownSrcField.Tag) 941 } 942 } 943 return 944 } 945 946 func (s *structIteratorT) typShouldBeIgnored(typ reflect.Type) bool { 947 n := typ.PkgPath() 948 return packageisreserved(n) // ignore golang stdlib, such as "io", "runtime", ... 949 } 950 951 func (s *structIteratorT) SourceFieldShouldBeIgnored(ignoredNames []string) (yes bool) { 952 rec := s.srcFields.tableRecordsT[s.srcIndex] 953 if yes = rec.ShouldIgnore(); yes { 954 return 955 } 956 shortName := rec.ShortFieldName() 957 return s.ShouldBeIgnored(shortName, ignoredNames) 958 } 959 960 func (s *structIteratorT) ShouldBeIgnored(name string, ignoredNames []string) (yes bool) { 961 for _, x := range ignoredNames { 962 if yes = isWildMatch(name, x); yes { 963 break 964 } 965 } 966 return 967 } 968 969 var onceinitignoredpackages sync.Once //nolint:gochecknoglobals //keep it 970 var _ignoredpackages ignoredpackages //nolint:gochecknoglobals //keep it 971 var _ignoredpackageprefixes ignoredpackageprefixes //nolint:gochecknoglobals //keep it 972 973 type ignoredpackages map[string]bool 974 type ignoredpackageprefixes []string 975 976 func (a ignoredpackages) contains(packageName string) (yes bool) { 977 // for _, s := range a { 978 // if yes = s == packageName; yes { 979 // break 980 // } 981 // } 982 _, yes = a[packageName] 983 return 984 } 985 func (a ignoredpackageprefixes) contains(packageName string) (yes bool) { 986 for _, s := range a { 987 if yes = strings.HasPrefix(packageName, s); yes { 988 break 989 } 990 } 991 return 992 }