github.com/hedzr/evendeep@v0.4.8/params.go (about)

     1  package evendeep
     2  
     3  import (
     4  	"github.com/hedzr/log"
     5  
     6  	"github.com/hedzr/evendeep/dbglog"
     7  	"github.com/hedzr/evendeep/flags"
     8  	"github.com/hedzr/evendeep/flags/cms"
     9  	"github.com/hedzr/evendeep/internal/cl"
    10  	"github.com/hedzr/evendeep/internal/tool"
    11  
    12  	"reflect"
    13  	"unsafe"
    14  )
    15  
    16  // Params is params package.
    17  type Params struct {
    18  	srcOwner   *reflect.Value // srcOwner of source slice or struct, or any others
    19  	dstOwner   *reflect.Value // dstOwner of destination slice or struct, or any others
    20  	srcDecoded *reflect.Value //
    21  	dstDecoded *reflect.Value //
    22  	srcType    reflect.Type   // = field(i+parent.srcOffset).type, or srcOwner.type for non-struct
    23  	dstType    reflect.Type   // = field(i+parent.dstOffset).type, or dstOwner.type for non-struct
    24  
    25  	// index     int // struct field or slice index,
    26  	// srcOffset int // -1, or an offset of the embedded struct fields
    27  	// dstOffset int // -1, or an offset of the embedded struct fields
    28  
    29  	// srcFieldType *reflect.StructField //
    30  	// dstFieldType *reflect.StructField //
    31  	// srcAnonymous bool                 //
    32  	// dstAnonymous bool                 //
    33  	// mergingMode    bool                 // base state
    34  
    35  	visited           map[visit]visiteddestination
    36  	visiting          visit
    37  	resultForNewSlice *reflect.Value
    38  
    39  	targetIterator structIterable //
    40  	accessor       accessor       //
    41  	// srcIndex       int                  //
    42  	// field     *reflect.StructField // source field type
    43  	// fieldTags *fieldTags           // tag of source field
    44  
    45  	flags flags.Flags
    46  
    47  	children          map[string]*Params // children of struct fields
    48  	childrenAnonymous []*Params          // or children without name (non-struct)
    49  	owner             *Params            //
    50  	controller        *cpController      //
    51  }
    52  
    53  type visit struct {
    54  	addr1, addr2 unsafe.Pointer
    55  	typ          reflect.Type
    56  }
    57  
    58  type visiteddestination struct {
    59  	dst reflect.Value
    60  }
    61  
    62  type paramsOpt func(p *Params)
    63  
    64  func newParams(opts ...paramsOpt) *Params {
    65  	p := &Params{}
    66  	for _, opt := range opts {
    67  		opt(p)
    68  	}
    69  	return p
    70  }
    71  
    72  func withFlags(flagsList ...cms.CopyMergeStrategy) paramsOpt { //nolint:unused //future code
    73  	return func(p *Params) {
    74  		p.flags = flags.New(flagsList...)
    75  	}
    76  }
    77  
    78  func withOwnersSimple(c *cpController, ownerParams *Params) paramsOpt { //nolint:unused //future code
    79  	return func(p *Params) {
    80  		p.controller = c
    81  		ownerParams.addChildParams(p)
    82  	}
    83  }
    84  
    85  func withOwners(c *cpController, ownerParams *Params, ownerSource, ownerTarget, osDecoded, otDecoded *reflect.Value) paramsOpt { //nolint:lll,gocognit //future
    86  	return func(p *Params) {
    87  		p.srcOwner = ownerSource
    88  		p.dstOwner = ownerTarget
    89  		p.srcDecoded = osDecoded
    90  		p.dstDecoded = otDecoded
    91  
    92  		var st, tt reflect.Type
    93  
    94  		if p.srcDecoded == nil && p.srcOwner != nil {
    95  			d, _ := tool.Rdecode(*p.srcOwner)
    96  			p.srcDecoded = &d
    97  			if p.srcOwner.IsValid() {
    98  				p.srcType = p.srcOwner.Type()
    99  			}
   100  		}
   101  
   102  		if p.srcDecoded != nil && p.srcDecoded.IsValid() {
   103  			st = p.srcDecoded.Type()
   104  			p.parseSourceStruct(ownerParams, st)
   105  			p.dstType = p.dstOwner.Type()
   106  		} else if p.srcOwner != nil {
   107  			st = p.srcOwner.Type()
   108  			st = tool.RindirectType(st)
   109  			p.parseSourceStruct(ownerParams, st)
   110  			p.dstType = st
   111  		}
   112  
   113  		if p.dstDecoded == nil && p.dstOwner != nil {
   114  			d, _ := tool.Rdecode(*p.dstOwner)
   115  			p.dstDecoded = &d
   116  		}
   117  
   118  		if p.dstDecoded != nil && p.dstDecoded.IsValid() {
   119  			tt = p.dstDecoded.Type()
   120  			p.parseTargetStruct(ownerParams, tt)
   121  		} else if p.dstOwner != nil {
   122  			tt = p.dstOwner.Type()
   123  			tt = tool.RindirectType(tt)
   124  			p.parseTargetStruct(ownerParams, tt)
   125  		}
   126  
   127  		//
   128  
   129  		// p.mergingMode = c.flags.isAnyFlagsOK(SliceMerge, MapMerge) || ownerParams.isAnyFlagsOK(SliceMerge, MapMerge)
   130  
   131  		if p.dstDecoded != nil {
   132  			t := *p.dstDecoded
   133  			p.targetIterator = newStructIterator(t,
   134  				withStructPtrAutoExpand(c.autoExpandStruct),
   135  				withStructFieldPtrAutoNew(c.autoNewStruct),
   136  				withStructSource(p.srcDecoded, c.autoExpandStruct),
   137  			)
   138  		}
   139  
   140  		//
   141  
   142  		p.controller = c
   143  		ownerParams.addChildParams(p)
   144  	}
   145  }
   146  
   147  // func (params *Params) withIteratorIndex(srcIndex int) (sourcefield tableRecT) {
   148  //	params.srcIndex = srcIndex
   149  //
   150  //	//if i < params.srcType.NumField() {
   151  //	//	t := params.srcType.Field(i)
   152  //	//	params.fieldType = &t
   153  //	//	params.fieldTags = parseFieldTags(t.Tag)
   154  //	//}
   155  //
   156  //	if srcIndex < len(params.sourcefields.tableRecordsT) {
   157  //		sourcefield = params.sourcefields.tableRecordsT[srcIndex]
   158  //		params.field = sourcefield.StructField()
   159  //		params.fieldTags = parseFieldTags(params.field.Tag)
   160  //	}
   161  //	return
   162  // }
   163  
   164  func (params *Params) sourceFieldShouldBeIgnored() (yes bool) {
   165  	if params.targetIterator != nil {
   166  		yes = params.targetIterator.SourceFieldShouldBeIgnored(params.controller.ignoreNames)
   167  	}
   168  	return
   169  }
   170  
   171  func (params *Params) shouldBeIgnored(name string) (yes bool) {
   172  	if name == "" {
   173  		return true
   174  	}
   175  	if params.targetIterator != nil {
   176  		yes = params.targetIterator.ShouldBeIgnored(name, params.controller.ignoreNames)
   177  	}
   178  	return
   179  }
   180  
   181  func (params *Params) nextTargetField() (sourceField *tableRecT, ok bool) {
   182  	if params.targetIterator != nil {
   183  		byName := params.isGroupedFlagOKDeeply(cms.ByName)
   184  		params.accessor, ok = params.targetIterator.Next(params, byName)
   185  		if ok {
   186  			sourceField = params.accessor.SourceField()
   187  			_, isIgnored := params.parseFieldTags(sourceField.structField.Tag)
   188  			ok = !isIgnored
   189  		}
   190  	}
   191  	return
   192  }
   193  
   194  func (params *Params) nextTargetFieldLite() (ok bool) {
   195  	if params.targetIterator != nil {
   196  		byName := params.isGroupedFlagOKDeeply(cms.ByName)
   197  		params.accessor, ok = params.targetIterator.Next(params, byName)
   198  	}
   199  	return
   200  }
   201  
   202  func (params *Params) inMergeMode() bool {
   203  	return params.controller.flags.IsAnyFlagsOK(cms.SliceMerge, cms.MapMerge) ||
   204  		params.owner.isAnyFlagsOK(cms.SliceMerge, cms.MapMerge) ||
   205  		params.flags.IsAnyFlagsOK(cms.SliceMerge, cms.MapMerge)
   206  }
   207  
   208  func (params *Params) dstFieldIsExportedR() (copyUnexportedFields, isExported bool) {
   209  	k := reflect.Invalid
   210  	if params != nil && params.dstDecoded != nil {
   211  		k = params.dstDecoded.Kind()
   212  	}
   213  	if k != reflect.Struct || params.accessor == nil {
   214  		return false, true // non-struct-field target, treat it as exported
   215  	}
   216  
   217  	isExported, copyUnexportedFields = tool.IsExported(params.accessor.StructField()), params.controller.copyUnexportedFields
   218  	if isExported && params.owner != nil {
   219  		copyUnexportedFields, isExported = params.owner.dstFieldIsExportedR()
   220  	}
   221  	return
   222  }
   223  
   224  // processUnexportedField try to set newval into target if it's an unexported field.
   225  func (params *Params) processUnexportedField(target, newval reflect.Value) (processed bool) {
   226  	if params == nil || params.controller == nil || params.accessor == nil {
   227  		return
   228  	}
   229  	if !params.controller.copyUnexportedFields {
   230  		return
   231  	}
   232  	if fld := params.accessor.StructField(); fld != nil {
   233  		// in a struct
   234  		if !tool.IsExported(fld) {
   235  			dbglog.Log("    unexported field %q (typ: %v): old(%v) -> new(%v)",
   236  				fld.Name, tool.Typfmt(fld.Type), tool.Valfmt(&target), tool.Valfmt(&newval))
   237  			cl.SetUnexportedField(target, newval)
   238  			processed = true
   239  		}
   240  	}
   241  	return
   242  }
   243  
   244  // func (params *Params) parseSourceFieldTag(i int) {
   245  //	params.index = i
   246  // }
   247  
   248  func (params *Params) parseSourceStruct(ownerParams *Params, st reflect.Type) {
   249  	params.srcType = st
   250  	// if kind := st.Kind(); kind == reflect.Struct {
   251  	// 	// idx := index
   252  	// 	// if ownerParams != nil {
   253  	// 	//	idx += ownerParams.srcOffset
   254  	// 	// }
   255  	// 	// params.withIteratorIndex(idx)
   256  	// 	// //if idx < st.NumField() {
   257  	// 	// //	t := st.Field(idx)
   258  	// 	// //	p.srcFieldType = &t
   259  	// 	// //	p.fieldTags = parseFieldTags(t.Tag)
   260  	// 	// //	p.srcType = t.Type
   261  	// 	// //}
   262  	// 	// //if ownerParams != nil {
   263  	// 	// //	if oft := ownerParams.srcFieldType; oft != nil && oft.Anonymous && oft.Type.Kind() == reflect.Struct {
   264  	// 	// //		p.srcAnonymous = true
   265  	// 	// //		p.srcOffset = p.index
   266  	// 	// //	}
   267  	// 	// //}
   268  	// }
   269  }
   270  
   271  func (params *Params) parseTargetStruct(ownerParams *Params, tt reflect.Type) {
   272  	params.dstType = tt
   273  	// if kind := tt.Kind(); kind == reflect.Struct {
   274  	// 	// idx := index
   275  	// 	// if ownerParams != nil {
   276  	// 	//	idx += ownerParams.dstOffset
   277  	// 	// }
   278  	// 	// //if idx < tt.NumField() {
   279  	// 	// //	t := tt.Field(idx)
   280  	// 	// //	p.dstFieldType = &t
   281  	// 	// //	p.dstType = t.Type
   282  	// 	// //}
   283  	// 	// //if ownerParams != nil {
   284  	// 	// //	if oft := ownerParams.dstFieldType; oft != nil && oft.Anonymous && oft.Type.Kind() == reflect.Struct {
   285  	// 	// //		p.dstAnonymous = true
   286  	// 	// //		p.dstOffset = p.index
   287  	// 	// //	}
   288  	// 	// //}
   289  	// 	// //} else if ownerParams != nil && ownerParams.dstFieldType != nil {
   290  	// }
   291  }
   292  
   293  // addChildParams does link this params into parent params.
   294  func (params *Params) addChildParams(ppChild *Params) {
   295  	if params == nil || ppChild == nil {
   296  		return
   297  	}
   298  
   299  	// if struct
   300  	if ppChild.accessor != nil && ppChild.accessor.StructField() != nil {
   301  		fieldName := ppChild.accessor.StructFieldName()
   302  
   303  		if ppChild.children == nil {
   304  			ppChild.children = make(map[string]*Params)
   305  		}
   306  		if params.children == nil {
   307  			params.children = make(map[string]*Params)
   308  		}
   309  		if _, ok := ppChild.children[fieldName]; ok {
   310  			log.Panicf("field %q exists, cannot iterate another field on the same name", fieldName)
   311  		}
   312  		// if ppChild == nil {
   313  		//	log.Panicf("setting nil Params for field %q, r u kidding me?", fieldName)
   314  		// }
   315  
   316  		params.children[fieldName] = ppChild
   317  	} else {
   318  		params.childrenAnonymous = append(params.childrenAnonymous, ppChild)
   319  	}
   320  
   321  	ppChild.owner = params
   322  }
   323  
   324  // revoke does revoke itself from parent params if necessary.
   325  func (params *Params) revoke() {
   326  	if pp := params.owner; pp != nil {
   327  		if pp.accessor != nil && pp.accessor.StructField() != nil {
   328  			fieldName := pp.accessor.StructFieldName()
   329  			delete(pp.children, fieldName)
   330  		} else {
   331  			for i := 0; i < len(pp.childrenAnonymous); i++ {
   332  				if child := pp.childrenAnonymous[i]; child == params {
   333  					pp.childrenAnonymous = append(pp.childrenAnonymous[0:i], pp.childrenAnonymous[i+1:]...)
   334  					break
   335  				}
   336  			}
   337  		}
   338  	}
   339  }
   340  
   341  // // ValueOfSource _
   342  // func (params *Params) ValueOfSource() reflect.Value {
   343  //	if params.srcFieldType != nil {
   344  //		return params.srcDecoded.Field(params.index + params.srcOffset)
   345  //	}
   346  //	return *params.srcOwner
   347  // }
   348  //
   349  // // ValueOfDestination _
   350  // func (params *Params) ValueOfDestination() reflect.Value {
   351  //	if params.dstFieldType != nil {
   352  //		return params.dstDecoded.Field(params.index + params.dstOffset)
   353  //	}
   354  //	return *params.dstOwner
   355  // }
   356  
   357  func (params *Params) isStruct() bool { //nolint:unused //future
   358  	return params != nil && params.accessor != nil && params.accessor.IsStruct() && params.dstOwner != nil
   359  }
   360  
   361  func (params *Params) parseFieldTags(tag reflect.StructTag) (flagsInTag *fieldTags, isIgnored bool) {
   362  	var tagName string
   363  	if params.controller != nil {
   364  		tagName = params.controller.tagKeyName
   365  	}
   366  	flagsInTag = parseFieldTags(tag, tagName)
   367  	isIgnored = flagsInTag.isFlagIgnored()
   368  	return
   369  }
   370  
   371  func (params *Params) isFlagExists(ftf cms.CopyMergeStrategy) (ret bool) {
   372  	if params == nil {
   373  		return
   374  	}
   375  	if params.controller != nil {
   376  		ret = params.controller.flags.IsFlagOK(ftf)
   377  	}
   378  	if !ret && params.flags != nil {
   379  		ret = params.flags.IsFlagOK(ftf)
   380  	}
   381  	if !ret && params.accessor != nil {
   382  		ret = params.accessor.IsFlagOK(ftf)
   383  	}
   384  	return
   385  }
   386  
   387  // isGroupedFlagOK tests if the given flag is exists or valid.
   388  //
   389  // Different with isGroupedFlagOKDeeply is, isGroupedFlagOK will return
   390  // false simply while Params.fieldTags is empty or unset.
   391  //
   392  // When Params.fieldTags is valid, the actual testing will be forwarded
   393  // to Params.fieldTags.flags.isGroupedFlagOK().
   394  func (params *Params) isGroupedFlagOK(ftf ...cms.CopyMergeStrategy) (ret bool) { //nolint:unused //future
   395  	if params == nil {
   396  		return flags.New().IsGroupedFlagOK(ftf...)
   397  	}
   398  	if params.controller != nil {
   399  		ret = params.controller.flags.IsGroupedFlagOK(ftf...)
   400  	}
   401  	if !ret && params.flags != nil {
   402  		ret = params.flags.IsGroupedFlagOK(ftf...)
   403  	}
   404  	if !ret && params.accessor != nil {
   405  		ret = params.accessor.IsGroupedFlagOK(ftf...)
   406  	}
   407  	return
   408  }
   409  
   410  // isGroupedFlagOKDeeply tests if the given flag is exists or valid.
   411  //
   412  // Different with isGroupedFlagOK is, isGroupedFlagOKDeeply will check
   413  // whether the given flag is a leader (i.e. default choice) in a group
   414  // or not, even if Params.fieldTags is empty or unset. And too, we run
   415  // the same logical on these sources:
   416  //
   417  //  1. params.controller.flags
   418  //  2. params.flags
   419  //  3. params.accessor.fieldTags.flags if present
   420  //
   421  // When Params.fieldTags is valid, the actual testing will be forwarded
   422  // to Params.fieldTags.flags.isGroupedFlagOK().
   423  func (params *Params) isGroupedFlagOKDeeply(ftf ...cms.CopyMergeStrategy) (ret bool) {
   424  	if params == nil {
   425  		return flags.New().IsGroupedFlagOK(ftf...)
   426  	}
   427  	if params.controller != nil {
   428  		ret = params.controller.flags.IsGroupedFlagOK(ftf...)
   429  	}
   430  	if !ret && params.flags != nil {
   431  		ret = params.flags.IsGroupedFlagOK(ftf...)
   432  	}
   433  	if !ret && params.accessor != nil {
   434  		ret = params.accessor.IsGroupedFlagOK(ftf...)
   435  	}
   436  	return
   437  }
   438  
   439  func (params *Params) isAnyFlagsOK(ftf ...cms.CopyMergeStrategy) (ret bool) {
   440  	if params == nil {
   441  		return
   442  	}
   443  	if params.controller != nil {
   444  		ret = params.controller.flags.IsAnyFlagsOK(ftf...)
   445  	}
   446  	if !ret && params.flags != nil {
   447  		ret = params.flags.IsAnyFlagsOK(ftf...)
   448  	}
   449  	if !ret && params.accessor != nil {
   450  		ret = params.accessor.IsAnyFlagsOK(ftf...)
   451  	}
   452  	return
   453  }
   454  
   455  func (params *Params) isAllFlagsOK(ftf ...cms.CopyMergeStrategy) (ret bool) { //nolint:unused //future
   456  	if params == nil {
   457  		return
   458  	}
   459  	if params.controller != nil {
   460  		ret = params.controller.flags.IsAllFlagsOK(ftf...)
   461  	}
   462  	if !ret && params.flags != nil {
   463  		ret = params.flags.IsAllFlagsOK(ftf...)
   464  	}
   465  	if !ret && params.accessor != nil {
   466  		ret = params.accessor.IsAllFlagsOK(ftf...)
   467  	}
   468  	return
   469  }
   470  
   471  func (params *Params) depth() (depth int) {
   472  	p := params
   473  	for p != nil {
   474  		depth++
   475  		p = p.owner
   476  	}
   477  	return
   478  }