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  }