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

     1  package evendeep
     2  
     3  // ftor.go - functors
     4  //
     5  
     6  import (
     7  	"github.com/hedzr/log"
     8  	"github.com/hedzr/log/color"
     9  
    10  	"github.com/hedzr/evendeep/dbglog"
    11  	"github.com/hedzr/evendeep/flags/cms"
    12  	"github.com/hedzr/evendeep/internal/cl"
    13  	"github.com/hedzr/evendeep/internal/tool"
    14  	"github.com/hedzr/evendeep/typ"
    15  
    16  	"gopkg.in/hedzr/errors.v3"
    17  
    18  	"reflect"
    19  	"strconv"
    20  	"strings"
    21  	"unsafe"
    22  )
    23  
    24  func copyPointer(c *cpController, params *Params, from, to reflect.Value) (err error) {
    25  	// from is a pointer
    26  	fromType := from.Type()
    27  
    28  	if fromType == to.Type() {
    29  		if params.isFlagExists(cms.Flat) {
    30  			to.Set(from)
    31  			return
    32  		}
    33  	}
    34  
    35  	src := tool.Rindirect(from)
    36  	tgt := tool.Rindirect(to)
    37  
    38  	paramsChild := newParams(withOwners(c, params, &from, &to, nil, nil))
    39  	defer paramsChild.revoke()
    40  
    41  	//nolint:lll //keep it
    42  	if tgt.CanSet() {
    43  		if src.IsValid() {
    44  			err = c.copyTo(paramsChild, src, to)
    45  		} else if paramsChild.isGroupedFlagOKDeeply(cms.ClearIfInvalid) {
    46  			// pointer - src is nil - set tgt to nil too
    47  			newtyp := to.Type()
    48  			zv := reflect.Zero(newtyp)
    49  			dbglog.Log("    pointer - zv: %v (%v), to: %v (%v)", tool.Valfmt(&zv), tool.Typfmt(newtyp), tool.Valfmt(&to), tool.Typfmtv(&to))
    50  			to.Set(zv)
    51  			// err = newobj(c, params, src, to, tgt)
    52  		}
    53  	} else {
    54  		dbglog.Log("    pointer - tgt is invalid/cannot-be-set/ignored: src: (%v) -> tgt: (%v)", tool.Typfmtv(&src), tool.Typfmtv(&to))
    55  		err = newObj(c, paramsChild, fromType, src, to, tgt)
    56  	}
    57  	return
    58  }
    59  
    60  func newObj(c *cpController, params *Params, fromType reflect.Type, src, to, tgt reflect.Value) (err error) {
    61  	newtyp := to.Type()
    62  	if to.Type() == fromType {
    63  		newtyp = newtyp.Elem() // is pointer and its same
    64  	}
    65  	// create new object and pointer
    66  	toobjcopyptrv := reflect.New(newtyp)
    67  	dbglog.Log("    toobjcopyptrv: %v", tool.Typfmtv(&toobjcopyptrv))
    68  	if err = c.copyTo(params, src, toobjcopyptrv.Elem()); err == nil {
    69  		val := toobjcopyptrv
    70  		if to.Type() == fromType {
    71  			val = val.Elem()
    72  		}
    73  		err = setTargetValue1(params.owner, to, tgt, val)
    74  		// to.Set(toobjcopyptrv)
    75  	}
    76  	return
    77  }
    78  
    79  func copyInterface(c *cpController, params *Params, from, to reflect.Value) (err error) {
    80  	if tool.IsNil(from) {
    81  		if params.isGroupedFlagOKDeeply(cms.OmitIfNil, cms.OmitIfEmpty) {
    82  			return
    83  		}
    84  		if to.CanSet() {
    85  			to.Set(reflect.Zero(to.Type()))
    86  			return
    87  		} else if to.Kind() == reflect.Ptr {
    88  			if to.Elem().CanSet() {
    89  				to.Elem().Set(reflect.Zero(to.Elem().Type()))
    90  				return
    91  			}
    92  		}
    93  		goto badReturn
    94  	}
    95  
    96  	if tool.IsZero(from) {
    97  		if params.isGroupedFlagOKDeeply(cms.OmitIfZero, cms.OmitIfEmpty) {
    98  			return
    99  		}
   100  		if to.CanSet() {
   101  			to.Set(reflect.Zero(to.Type()))
   102  			return
   103  		} else if to.Kind() == reflect.Ptr {
   104  			if to.Elem().CanSet() {
   105  				to.Elem().Set(reflect.Zero(to.Elem().Type()))
   106  				return
   107  			}
   108  		}
   109  		goto badReturn
   110  	}
   111  	err = copyInterfaceImpl(c, params, from, to)
   112  	return
   113  
   114  badReturn:
   115  	err = ErrCannotSet.FormatWith(tool.Valfmt(&from), tool.Typfmtv(&from), tool.Valfmt(&to), tool.Typfmtv(&to))
   116  	return
   117  }
   118  
   119  func copyInterfaceImpl(c *cpController, params *Params, from, to reflect.Value) (err error) {
   120  	paramsChild := newParams(withOwners(c, params, &from, &to, nil, nil))
   121  	defer paramsChild.revoke()
   122  
   123  	// unbox the interface{} to original data type
   124  	toind, toptr := tool.Rdecode(to) // c.skip(to, reflect.Interface, reflect.Pointer)
   125  
   126  	dbglog.Log("from.type: %v, decode to: %v", from.Type().Kind(), paramsChild.srcDecoded.Kind())
   127  	dbglog.Log("  to.type: %v, decode to: %v (ptr: %v) | CanSet: %v/%v, CanAddr: %v",
   128  		to.Type().Kind(), toind.Kind(), toptr.Kind(), toind.CanSet(), toptr.CanSet(), toind.CanAddr())
   129  
   130  	if !tool.KindIs(toind.Kind(), reflect.Map, reflect.Slice, reflect.Chan) {
   131  		if !toind.CanSet() && !toptr.CanSet() {
   132  			// log.Panicf("[copyInterface] toind.CanSet() is false!")
   133  
   134  			// valid ptr pointed to an invalid source object,
   135  			// valid ptr pointed to an invalid target object:
   136  			//nolint:lll //keep it
   137  			err = errors.New("[copyInterface] target pointer cannot be set, toind.Kind: %v, toptr.Kind: %v", toind.Kind(), toptr.Kind())
   138  			return
   139  		}
   140  	}
   141  
   142  	// var merging = c.flags.isAnyFlagsOK(SliceMerge, MapMerge) || params.isAnyFlagsOK(SliceMerge, MapMerge)
   143  	if paramsChild.inMergeMode() || !c.makeNewClone {
   144  		err = c.copyTo(paramsChild, *paramsChild.srcDecoded, toptr)
   145  		return
   146  	}
   147  	if to.CanSet() {
   148  		copyValue := reflect.New(paramsChild.srcDecoded.Type()).Elem()
   149  		if err = c.copyTo(paramsChild, *paramsChild.srcDecoded, copyValue); err == nil {
   150  			to.Set(copyValue)
   151  		}
   152  	}
   153  	return
   154  }
   155  
   156  func copyStruct(c *cpController, params *Params, from, to reflect.Value) (err error) {
   157  	// default is cms.ByOrdinal:
   158  	//   loops all source fields and copy its value to the corresponding target field.
   159  	cb := forEachSourceField
   160  	if c.targetOriented || params.isGroupedFlagOKDeeply(cms.ByName) {
   161  		// cmd.ByName strategy:
   162  		//   loops all target fields and try copying value from source field by its name.
   163  		cb = forEachTargetField
   164  	}
   165  	err = copyStructInternal(c, params, from, to, cb)
   166  	return
   167  }
   168  
   169  func copyStructInternal( //nolint:gocognit //keep it
   170  	c *cpController, params *Params,
   171  	from, to reflect.Value,
   172  	fn func(paramsChild *Params, ec errors.Error, i, amount *int, padding string) (err error),
   173  ) (err error) {
   174  	var (
   175  		i, amount   int
   176  		padding     string
   177  		ec          = errors.New("copyStructInternal errors")
   178  		paramsChild = newParams(withOwners(c, params, &from, &to, nil, nil))
   179  	)
   180  
   181  	defer func() {
   182  		if e := recover(); e != nil {
   183  			sst := paramsChild.targetIterator.(sourceStructFieldsTable) //nolint:errcheck //no need
   184  
   185  			ff := sst.TableRecord(i).FieldValue()
   186  			var tf = paramsChild.dstOwner
   187  			var tft = &paramsChild.dstType
   188  			if paramsChild.accessor != nil {
   189  				tf = paramsChild.accessor.FieldValue()
   190  				tft = paramsChild.accessor.FieldType()
   191  			}
   192  
   193  			// .WithData(e) will collect e if it's an error object else store it simply
   194  			ec.Attach(errors.New("[recovered] copyStruct unsatisfied ([%v] -> [%v]), causes: %v",
   195  				tool.Typfmtv(ff), tool.Typfmtptr(tft), e).
   196  				WithMaxObjectStringLength(maxObjectStringLen).
   197  				WithData(e).
   198  				WithTaggedData(errors.TaggedData{ // record the sites
   199  					"source-field": ff,
   200  					"target-field": tf,
   201  					"source":       tool.Valfmt(ff),
   202  					"target":       tool.Valfmt(tf),
   203  				}))
   204  			// n := log.CalcStackFrames(1)   // skip defer-recover frame at first
   205  			// log.Skip(n).Errorf("%v", err) // skip golib frames and defer-recover frame, back to the point throwing panic
   206  			// if c.rethrow {
   207  			//	log.Panicf("%+v", ec)
   208  			// } else {
   209  			// dbglog.Err("copyStructInternal will return error: %+v", ec)
   210  			// }
   211  		}
   212  
   213  		ec.Defer(&err)
   214  		paramsChild.revoke()
   215  		if err != nil {
   216  			dbglog.Err("copyStructInternal will return error: %+v", err)
   217  		}
   218  	}()
   219  
   220  	if dbglog.LogValid {
   221  		// dbgFrontOfStruct(params, paramsChild, padding, func(msg string, args ...interface{}) { dbglog.Log(msg, args...) })
   222  		dbgFrontOfStruct(paramsChild, padding, dbglog.Log)
   223  	}
   224  
   225  	var processed bool
   226  	if processed, err = tryConverters(c, paramsChild, &from, paramsChild.dstDecoded, &paramsChild.dstType, true); processed { //nolint:lll //keep it
   227  		return
   228  	}
   229  
   230  	switch k := paramsChild.dstDecoded.Kind(); k { //nolint:exhaustive //no need
   231  	case reflect.Slice:
   232  		dbglog.Log("     * struct -> slice case, ...")
   233  		if paramsChild.dstDecoded.Len() > 0 { //nolint:gocritic // no need to switch to 'switch' clause
   234  			err = c.copyTo(paramsChild, *paramsChild.srcOwner, paramsChild.dstDecoded.Index(0))
   235  		} else if paramsChild.isGroupedFlagOKDeeply(cms.SliceCopyAppend, cms.SliceMerge) {
   236  			err = cpStructToNewSliceElem0(paramsChild)
   237  		} else {
   238  			err = ErrCannotCopy.FormatWith(tool.Valfmt(&from), tool.Typfmtv(&from), tool.Valfmt(&to), tool.Typfmtv(&to))
   239  		}
   240  		ec.Attach(err)
   241  		return
   242  
   243  	case reflect.Array:
   244  		dbglog.Log("     * struct -> array case, ...")
   245  		if paramsChild.dstDecoded.Len() > 0 {
   246  			err = c.copyTo(paramsChild, *paramsChild.srcOwner, paramsChild.dstDecoded.Index(0))
   247  		} else {
   248  			err = ErrCannotCopy.FormatWith(tool.Valfmt(&from), tool.Typfmtv(&from), tool.Valfmt(&to), tool.Typfmtv(&to))
   249  		}
   250  		ec.Attach(err)
   251  		return
   252  
   253  	case reflect.String:
   254  		dbglog.Log("     * struct -> string case, ...")
   255  		var str string
   256  		if str, err = doMarshalling(*paramsChild.srcOwner); err == nil {
   257  			target := reflect.ValueOf(str)
   258  			if paramsChild.dstDecoded.CanSet() {
   259  				paramsChild.dstDecoded.Set(target)
   260  			} else {
   261  				err = ErrCannotSet.FormatWith(
   262  					tool.Valfmt(paramsChild.srcDecoded),
   263  					tool.Typfmtv(paramsChild.srcDecoded),
   264  					tool.Valfmt(paramsChild.dstDecoded),
   265  					tool.Typfmtv(paramsChild.dstDecoded))
   266  			}
   267  		}
   268  		return
   269  	}
   270  
   271  	err = fn(paramsChild, ec, &i, &amount, padding)
   272  	ec.Attach(err)
   273  	return
   274  }
   275  
   276  func cpStructToNewSliceElem0(params *Params) (err error) {
   277  	eltyp := params.dstType.Elem()
   278  	et, _ := tool.Rdecodetype(eltyp)
   279  	elnew := reflect.New(et)
   280  	slice, tgtptr, el := *params.dstDecoded, params.dstOwner, elnew.Elem()
   281  	if eltyp != et {
   282  		tgtptr, el = params.dstOwner, elnew
   283  	}
   284  	if err = params.controller.copyTo(params, *params.srcOwner, elnew); err == nil {
   285  		result := reflect.Append(slice, el)
   286  		if tk := tgtptr.Kind(); tk == reflect.Slice || tk == reflect.Interface {
   287  			tgtptr.Set(result)
   288  		} else {
   289  			tgtptr.Elem().Set(result)
   290  		}
   291  	}
   292  	return
   293  }
   294  
   295  //nolint:lll //keep it
   296  func getSourceFieldName(knownDestName string, params *Params) (srcFieldName string, flagsInTag *fieldTags, ignored bool) {
   297  	srcFieldName = knownDestName
   298  	// var flagsInTag *fieldTags
   299  	var ok bool
   300  	if sf := params.accessor.StructField(); sf != nil { //nolint:nestif //keep it
   301  		flagsInTag, ignored = params.parseFieldTags(sf.Tag)
   302  		if ignored {
   303  			return
   304  		}
   305  		srcFieldName, ok = flagsInTag.CalcSourceName(sf.Name)
   306  		// dbglog.Log("     srcName: %v, ok: %v [pre 1, fld: %v, tag: %v]", srcFieldName, ok, sf.Name, sf.Tag)
   307  		if !ok {
   308  			if tr := params.accessor.SourceField(); tr != nil {
   309  				if sf = tr.structField; sf != nil {
   310  					flagsInTag, ignored = params.parseFieldTags(sf.Tag)
   311  					if ignored {
   312  						return
   313  					}
   314  					srcFieldName, ok = flagsInTag.CalcSourceName(sf.Name)
   315  					// dbglog.Log("     srcName: %v, ok: %v [pre 2, fld: %v, tag: %v]", srcFieldName, ok, sf.Name, sf.Tag)
   316  				}
   317  			}
   318  		}
   319  	}
   320  	dbglog.Log("     srcName: %v, ok: %v | dstName: %v", srcFieldName, ok, knownDestName)
   321  	return
   322  }
   323  
   324  // func getTargetFieldName(knownSrcName string, params *Params) (dstFieldName string, ignored bool) {
   325  // 	dstFieldName = knownSrcName
   326  // 	var flagsInTag *fieldTags
   327  // 	var ok bool
   328  // 	if sf := params.accessor.StructField(); sf != nil {
   329  // 		flagsInTag, ignored = params.parseFieldTags(sf.Tag)
   330  // 		if ignored {
   331  // 			return
   332  // 		}
   333  // 		ctx := &NameConverterContext{Params: params}
   334  // 		dstFieldName, ok = flagsInTag.CalcTargetName(sf.Name, ctx)
   335  // 		if !ok {
   336  // 			if tr := params.accessor.SourceField(); tr != nil {
   337  // 				if sf = tr.structField; sf != nil {
   338  // 					flagsInTag, ignored = params.parseFieldTags(sf.Tag)
   339  // 					if ignored {
   340  // 						return
   341  // 					}
   342  // 					dstFieldName, ok = flagsInTag.CalcTargetName(sf.Name, ctx)
   343  // 					dbglog.Log("     dstName: %v, ok: %v [pre 2, fld: %v, tag: %v]", dstFieldName, ok, sf.Name, sf.Tag)
   344  // 				}
   345  // 			}
   346  // 		}
   347  // 	}
   348  // 	return
   349  // }
   350  
   351  // forEachTargetField works for cms.ByName mode enabled.
   352  func forEachTargetField(params *Params, ec errors.Error, i, amount *int, padding string) (err error) {
   353  	c := params.controller
   354  
   355  	var sst = params.targetIterator.(sourceStructFieldsTable)
   356  	var val reflect.Value
   357  	var fcz = params.isGroupedFlagOKDeeply(cms.ClearIfMissed)
   358  	var aun = c.autoNewStruct // autoNew mode:
   359  	var cfrtt = c.copyFunctionResultToTarget
   360  	// We will do new(field) for each target field if it's invalid.
   361  	//
   362  	// It's not cms.ClearIfInvalid - which will detect if the source
   363  	// field is invalid or not, but target one.
   364  	//
   365  	//nolint:lll //keep it
   366  	dbglog.Log("     c.autoNewStruct = %v, c.copyFunctionResultToTarget = %v, cms.ClearIfMissed is set: %v", aun, cfrtt, fcz)
   367  
   368  	for *i, *amount = 0, len(sst.TableRecords()); params.nextTargetFieldLite(); *i++ {
   369  		name := params.accessor.StructFieldName() // get target field name
   370  		if params.shouldBeIgnored(name) {
   371  			continue
   372  		}
   373  
   374  		if extractor := c.sourceExtractor; extractor != nil { //nolint:nestif //keep it
   375  			v := extractor(name)
   376  			val = reflect.ValueOf(v)
   377  			params.accessor.Set(val)
   378  			continue
   379  		}
   380  
   381  		srcFieldName, _, ignored := getSourceFieldName(name, params)
   382  		if ignored {
   383  			dbglog.Log(`     > source field ignored (flag found in struct tag): %v.`, srcFieldName)
   384  			continue
   385  		}
   386  
   387  		ind := sst.RecordByName(srcFieldName)
   388  		switch {
   389  		case ind != nil:
   390  			val = *ind
   391  		case cfrtt:
   392  			if _, ind = sst.MethodCallByName(srcFieldName); ind != nil {
   393  				val = *ind
   394  			} else if _, ind = sst.MethodCallByName(name); ind != nil {
   395  				val = *ind
   396  			} else {
   397  				continue // skip the field
   398  			}
   399  		case fcz || (aun && !params.accessor.ValueValid()):
   400  			tt := params.accessor.FieldType()
   401  			val = reflect.Zero(*tt)
   402  			dbglog.Log("     target is invalid: %v, autoNewStruct: %v", params.accessor.ValueValid(), aun)
   403  		default:
   404  			continue
   405  		}
   406  		params.accessor.Set(val)
   407  	}
   408  	return
   409  }
   410  
   411  //nolint:gocognit //unify scene
   412  func forEachSourceField(params *Params, ec errors.Error, i, amount *int, padding string) (err error) {
   413  	sst := params.targetIterator.(sourceStructFieldsTable) //nolint:errcheck //no need
   414  	c := params.controller
   415  
   416  	for *i, *amount = 0, len(sst.TableRecords()); *i < *amount; *i++ {
   417  		if params.sourceFieldShouldBeIgnored() {
   418  			dbglog.Log("%d. %s : IGNORED", *i, sst.CurrRecord().FieldName())
   419  			if c.advanceTargetFieldPointerEvenIfSourceIgnored {
   420  				_ = params.nextTargetFieldLite()
   421  			} else {
   422  				sst.Step(1) // step the source field index subscription
   423  			}
   424  			continue
   425  		}
   426  
   427  		var goon bool
   428  		if goon, err = forEachSourceFieldCheckTargetSetter(params, sst); goon {
   429  			continue
   430  		}
   431  
   432  		var sourceField *tableRecT
   433  		if sourceField, goon = params.nextTargetField(); !goon {
   434  			continue
   435  		}
   436  
   437  		fn, srcval, dstval := sourceField.FieldName(), sourceField.FieldValue(), params.accessor.FieldValue()
   438  
   439  		dstfieldname := params.accessor.StructFieldName()
   440  		// log.VDebugf will be tuned and stripped off in normal build.
   441  		dbglog.Colored(color.LightMagenta, "%d. fld %q (%v) -> %s (%v) | (%v) -> (%v)", *i,
   442  			fn, tool.Typfmtv(srcval), dstfieldname, tool.Typfmt(*params.accessor.FieldType()),
   443  			tool.Valfmt(srcval), tool.Valfmt(dstval))
   444  
   445  		// The following if clause will be stripped off completely
   446  		// in normal build.
   447  		// It's only available when using `-tags=verbose`.
   448  		// The first condition 'log.VerboseEnabled' do circuit to
   449  		// be optimized by compiler.
   450  		if log.VerboseEnabled && !ec.IsEmpty() {
   451  			log.Warnf("    ERR-CONTAINER NOT EMPTY: %+v", ec.Error())
   452  		}
   453  
   454  		if srcval != nil && dstval != nil {
   455  			typ := params.accessor.FieldType() // target type
   456  			if typ != nil && !tool.KindIs((*typ).Kind(), reflect.Chan, reflect.Func, reflect.Interface, reflect.UnsafePointer, reflect.Ptr, reflect.Slice) {
   457  				if tool.IsNil(*dstval) || !(*dstval).IsValid() {
   458  					if !tool.IsNil(*srcval) {
   459  						dbglog.Log("      create new: dstval = nil/invalid, type: %v (%v -> nil/inalid)", tool.Typfmt(*typ), tool.Valfmt(srcval))
   460  						_, elem := newFromTypeEspSlice(*typ)
   461  						dstval.Set(elem)
   462  						dbglog.Log("      create new: dstval created: %v", tool.Typfmtv(dstval))
   463  					}
   464  				}
   465  			}
   466  
   467  			if srcval.IsValid() {
   468  				if err = invokeStructFieldTransformer(c, params, srcval, dstval, typ, padding); err != nil {
   469  					ec.Attach(err)
   470  					dbglog.Err("    %d. fld %q error: %v", *i, fn, err)
   471  				} else {
   472  					dbglog.Log("    %d. fld %q copied. from-to: %v -> %v", *i, fn, tool.Valfmt(srcval), tool.Valfmt(dstval))
   473  				}
   474  			}
   475  			continue
   476  		}
   477  
   478  		if goon = forEachSourceFieldCheckMergeMode(params, srcval, ec, padding); goon {
   479  			continue
   480  		}
   481  
   482  		dbglog.Wrn("   %d. fld %q: ignore nil/zero/invalid source or nil target", *i, fn)
   483  	}
   484  	return
   485  }
   486  
   487  func forEachSourceFieldCheckTargetSetter(params *Params, sst sourceStructFieldsTable) (goon bool, err error) {
   488  	c := params.controller
   489  	if c.targetSetter == nil {
   490  		return
   491  	}
   492  
   493  	currec := sst.CurrRecord()
   494  	srcval := currec.FieldValue()
   495  	if err = c.targetSetter(srcval, currec.names...); err == nil {
   496  		if c.advanceTargetFieldPointerEvenIfSourceIgnored {
   497  			_ = params.nextTargetFieldLite()
   498  		} else {
   499  			sst.Step(1) // step the source field index
   500  		}
   501  		goon = true
   502  		return // targetSetter make things done, so continue to next field
   503  	}
   504  
   505  	if err != ErrShouldFallback { //nolint:errorlint //want it exactly
   506  		return // has error, break the whole copier loop
   507  	}
   508  	err = nil // fallback
   509  	return
   510  }
   511  
   512  func forEachSourceFieldCheckMergeMode(params *Params, srcval *reflect.Value,
   513  	ec errors.Error, padding string) (goon bool) {
   514  	if params.inMergeMode() {
   515  		var err error
   516  		c := params.controller
   517  
   518  		typ := params.accessor.FieldType()
   519  		dbglog.Log("    new object for %v", tool.Typfmt(*typ))
   520  
   521  		// create new object and pointer
   522  		toobjcopyptrv := reflect.New(*typ).Elem()
   523  		dbglog.Log("    toobjcopyptrv: %v", tool.Typfmtv(&toobjcopyptrv))
   524  
   525  		//nolint:gocritic // no need to switch to 'switch' clause
   526  		if err = invokeStructFieldTransformer(c, params, srcval, &toobjcopyptrv, typ, padding); err != nil {
   527  			ec.Attach(err)
   528  			dbglog.Err("error: %v", err)
   529  		} else if toobjcopyptrv.Kind() == reflect.Slice {
   530  			params.accessor.Set(toobjcopyptrv)
   531  		} else if toobjcopyptrv.Kind() == reflect.Ptr {
   532  			params.accessor.Set(toobjcopyptrv.Elem())
   533  		} else {
   534  			params.accessor.Set(toobjcopyptrv)
   535  		}
   536  		goon = true
   537  	}
   538  	return
   539  }
   540  
   541  func dbgFrontOfStruct(params *Params, padding string, logger func(msg string, args ...interface{})) {
   542  	if log.VerboseEnabled {
   543  		if params == nil {
   544  			return
   545  		}
   546  		if logger == nil {
   547  			logger = dbglog.Log
   548  		}
   549  		d := params.depth()
   550  		if d > 1 {
   551  			d -= 2
   552  		}
   553  		padding1 := strings.Repeat("  ", d*2) //nolint:gomnd //no need
   554  		// fromT, toT := params.srcDecoded.Type(), params.dstDecoded.Type()
   555  		// Log(" %s  %d, %d, %d", padding, params.index, params.srcOffset, params.dstOffset)
   556  		// fq := dbgMakeInfoString(fromT, params.owner, true, logger)
   557  		// dq := dbgMakeInfoString(toT, params.owner, false, logger)
   558  		logger(" %s- src (%v) -> dst (%v)", padding1, tool.Typfmtv(params.srcDecoded), tool.Typfmtv(params.dstDecoded))
   559  		// logger(" %s  %s -> %s", padding, fq, dq)
   560  	}
   561  }
   562  
   563  func invokeStructFieldTransformer(
   564  	c *cpController, params *Params, ff, df *reflect.Value,
   565  	dftyp *reflect.Type, //nolint:gocritic // ptrToRefParam: consider 'dftyp' to be of non-pointer type
   566  	padding string,
   567  ) (err error) {
   568  	fv, dv := ff != nil && ff.IsValid(), df != nil && df.IsValid()
   569  	fft, dft := dtypzz(ff, dftyp), dtypzz(df, dftyp)
   570  	fftk, dftk := fft.Kind(), dft.Kind()
   571  
   572  	var processed bool
   573  	if processed = checkClearIfEqualOpt(params, ff, df, dft); processed {
   574  		return
   575  	}
   576  	if processed = checkOmitEmptyOpt(params, ff, df, dft); processed {
   577  		return
   578  	}
   579  	if processed, err = tryConverters(c, params, ff, df, dftyp, false); processed {
   580  		return
   581  	}
   582  
   583  	if fftk == reflect.Struct && ff.NumField() == 0 {
   584  		// never get into here because tableRecordsT.getAllFields skip empty struct
   585  		log.Warnf("should never get into here, might be algor wrong ?")
   586  	}
   587  	if dftk == reflect.Struct && df.NumField() == 0 {
   588  		// structIterable.Next() might return an empty struct accessor
   589  		// rather than field.
   590  		dbglog.Err("shouldn't get into here because we have a failover branch at the callee")
   591  	}
   592  
   593  	if fv && dv {
   594  		dbglog.Log(`      c.copyTo: ff -> df`)
   595  		err = c.copyTo(params, *ff, *df) // or, use internal standard implementation version
   596  		dbglog.Log(`      c.copyTo.end: ff -> df. err = %v, df = %v`, err, tool.Valfmt(df))
   597  		if log.VerboseEnabled {
   598  			if df.CanInterface() {
   599  				switch k := df.Kind(); k {
   600  				case reflect.Map, reflect.Slice:
   601  					var v typ.Any = df.Interface()
   602  					dbglog.Log(`      c.copyTo.end: df = %v`, v)
   603  				}
   604  			}
   605  		}
   606  		return
   607  	}
   608  
   609  	return forInvalidValues(c, params, ff, fft, dft, fftk, dftk, fv)
   610  }
   611  
   612  //nolint:lll //keep it
   613  func forInvalidValues(c *cpController, params *Params, ff *reflect.Value, fft, dft reflect.Type, fftk, dftk reflect.Kind, fv bool) (err error) {
   614  	if !fv {
   615  		dbglog.Log("   ff is invalid: %v", tool.Typfmtv(ff))
   616  		nv := reflect.New(fft).Elem()
   617  		ff = &nv
   618  	}
   619  	if dftk == reflect.Interface {
   620  		dft, dftk = fft, fftk
   621  	}
   622  	dbglog.Log("     dft: %v", tool.Typfmt(dft))
   623  	if dftk == reflect.Ptr {
   624  		nv := reflect.New(dft.Elem())
   625  		tt := nv.Elem()
   626  		dbglog.Log("   nv.tt: %v", tool.Typfmtv(&tt))
   627  		ff1 := tool.Rindirect(*ff)
   628  		err = c.copyTo(params, ff1, tt) // use user-defined copy-n-merger to merge or copy source to destination
   629  		if err == nil && !params.accessor.IsStruct() {
   630  			params.accessor.Set(tt)
   631  		}
   632  	} else {
   633  		nv := reflect.New(dft)
   634  		ff1 := tool.Rindirect(*ff)
   635  		err = c.copyTo(params, ff1, nv.Elem()) // use user-defined copy-n-merger to merge or copy source to destination
   636  		if err == nil && !params.accessor.IsStruct() {
   637  			params.accessor.Set(nv.Elem())
   638  		}
   639  	}
   640  	return
   641  }
   642  
   643  //nolint:lll //keep it
   644  func dtypzz(df *reflect.Value, deftyp *reflect.Type) reflect.Type { //nolint:gocritic // ptrToRefParam: consider 'dftyp' to be of non-pointer type
   645  	if df != nil && df.IsValid() {
   646  		return df.Type()
   647  	}
   648  	return *deftyp
   649  }
   650  
   651  func checkOmitEmptyOpt(params *Params, ff, df *reflect.Value, dft reflect.Type) (processed bool) {
   652  	if tool.IsNilv(ff) && params.isGroupedFlagOKDeeply(cms.OmitIfNil, cms.OmitIfEmpty) {
   653  		processed = true
   654  	}
   655  	if tool.IsZerov(ff) && params.isGroupedFlagOKDeeply(cms.OmitIfZero, cms.OmitIfEmpty) {
   656  		processed = true
   657  	}
   658  	return
   659  }
   660  
   661  func checkClearIfEqualOpt(params *Params, ff, df *reflect.Value, dft reflect.Type) (processed bool) {
   662  	if params.isFlagExists(cms.ClearIfEq) {
   663  		if tool.EqualClassical(*ff, *df) {
   664  			df.Set(reflect.Zero(dft))
   665  		} else if params.isFlagExists(cms.ClearIfInvalid) && !df.IsValid() {
   666  			df.Set(reflect.Zero(dft))
   667  		}
   668  		processed = true
   669  		if params.isFlagExists(cms.KeepIfNotEq) {
   670  			return
   671  		}
   672  	}
   673  	return
   674  }
   675  
   676  func tryConverters(c *cpController, params *Params,
   677  	ff, df *reflect.Value,
   678  	dftyp *reflect.Type, //nolint:gocritic // ptrToRefParam: consider 'dftyp' to be of non-pointer type
   679  	userDefinedOnly bool,
   680  ) (processed bool, err error) {
   681  	fft, dft := dtypzz(ff, dftyp), dtypzz(df, dftyp)
   682  	if c.tryApplyConverterAtFirst {
   683  		if processed, err = findAndApplyConverters(c, params, ff, df, fft, dft, userDefinedOnly); processed {
   684  			return
   685  		}
   686  		processed, err = findAndApplyCopiers(c, params, ff, df, fft, dft, userDefinedOnly)
   687  	} else {
   688  		if processed, err = findAndApplyCopiers(c, params, ff, df, fft, dft, userDefinedOnly); processed {
   689  			return
   690  		}
   691  		processed, err = findAndApplyConverters(c, params, ff, df, fft, dft, userDefinedOnly)
   692  	}
   693  	return
   694  }
   695  
   696  //nolint:lll //keep it
   697  func findAndApplyCopiers(c *cpController, params *Params, ff, df *reflect.Value, fft, dft reflect.Type, userDefinedOnly bool) (processed bool, err error) {
   698  	if cvt, ctx := c.valueCopiers.findCopiers(params, fft, dft, userDefinedOnly); ctx != nil { //nolint:nestif //keep it
   699  		dbglog.Colored(color.DarkColor, "-> using Copier %v", reflect.ValueOf(cvt).Type())
   700  
   701  		if df.IsValid() {
   702  			if err = cvt.CopyTo(ctx, *safeFF(ff, fft), *df); err == nil { // use user-defined copy-n-merger to merge or copy source to destination
   703  				processed = true
   704  			}
   705  			return
   706  		}
   707  
   708  		if dft.Kind() == reflect.Interface {
   709  			dft = fft
   710  		}
   711  		dbglog.Log("  dft: %v", tool.Typfmt(dft))
   712  		nv := reflect.New(dft)
   713  		err = cvt.CopyTo(ctx, *safeFF(ff, fft), nv) // use user-defined copy-n-merger to merge or copy source to destination
   714  		if err == nil && !params.accessor.IsStruct() {
   715  			params.accessor.Set(nv.Elem())
   716  			processed = true
   717  		}
   718  	}
   719  	return
   720  }
   721  
   722  //nolint:lll //keep it
   723  func findAndApplyConverters(c *cpController, params *Params, ff, df *reflect.Value, fft, dft reflect.Type, userDefinedOnly bool) (processed bool, err error) {
   724  	if cvt, ctx := c.valueConverters.findConverters(params, fft, dft, userDefinedOnly); ctx != nil {
   725  		dbglog.Colored(color.DarkColor, "-> using Converter %v", reflect.ValueOf(cvt).Type())
   726  
   727  		var result reflect.Value
   728  		result, err = cvt.Transform(ctx, *safeFF(ff, fft), dft) // use user-defined value converter to transform from source to destination
   729  		if err == nil && !df.IsValid() && !params.accessor.IsStruct() {
   730  			params.accessor.Set(result)
   731  			processed = true
   732  			return
   733  		}
   734  		df.Set(result)
   735  		processed = true
   736  	}
   737  	return
   738  }
   739  
   740  func safeFF(ff *reflect.Value, fft reflect.Type) *reflect.Value {
   741  	if ff == nil {
   742  		tmpsrc := reflect.New(fft).Elem()
   743  		ff = &tmpsrc
   744  	}
   745  	return ff
   746  }
   747  
   748  // copySlice transforms from slice to target with slice or other types.
   749  func copySlice(c *cpController, params *Params, from, to reflect.Value) (err error) {
   750  	if from.IsNil() && params.isGroupedFlagOKDeeply(cms.OmitIfNil, cms.OmitIfEmpty) { // an empty slice found
   751  		return
   752  	}
   753  
   754  	var tgt, tgtptr reflect.Value
   755  	tgt, tgtptr = tool.Rdecode(to)
   756  	if to != tgtptr { //nolint:govet //how should i do //TODO needs checked-review
   757  		err = c.copyTo(params, from, tgtptr) // unwrap the pointer
   758  		return
   759  	}
   760  
   761  	if !tool.KindIs(tgt.Kind(), reflect.Map, reflect.Slice, reflect.Chan) && !tgt.CanSet() {
   762  		log.Panicf("[copySlice] tgtptr cannot be set")
   763  	}
   764  	if params.controller != c {
   765  		log.Panicf("[copySlice] c *cpController != params.controller, what's up??")
   766  	}
   767  
   768  	tk, typ := tgt.Kind(), tgt.Type()
   769  	if tk != reflect.Slice {
   770  		dbglog.Log("[copySlice] from slice -> %v", tool.Typfmt(typ))
   771  		var processed bool
   772  		if processed, err = tryConverters(c, params, &from, &tgt, &typ, false); !processed {
   773  			// log.Panicf("[copySlice] unsupported transforming: from slice -> %v,", typfmtv(&tgt))
   774  			//nolint:lll //keep it
   775  			err = ErrCannotCopy.WithErrors(err).FormatWith(tool.Valfmt(&from), tool.Typfmtv(&from), tool.Valfmt(&tgt), tool.Typfmtv(&tgt))
   776  		}
   777  		return
   778  	}
   779  
   780  	if tool.IsNil(tgt) && params.isGroupedFlagOKDeeply(cms.OmitIfTargetZero, cms.OmitIfTargetEmpty) {
   781  		return
   782  	}
   783  
   784  	params.resultForNewSlice, err = copySliceInternal(c, params, from, to, tgt, tgtptr)
   785  	return
   786  }
   787  
   788  //nolint:lll,gocognit //keep it
   789  func copySliceInternal(c *cpController, params *Params, from, to, tgt, tgtptr reflect.Value) (result *reflect.Value, err error) {
   790  	if from.Len() == 0 {
   791  		dbglog.Log("  slice copy ignored because src slice is empty.")
   792  		return
   793  	}
   794  
   795  	ec := errors.New("slice copy/merge errors")
   796  	defer ec.Defer(&err)
   797  
   798  	for _, flag := range []cms.CopyMergeStrategy{cms.SliceMerge, cms.SliceCopyAppend, cms.SliceCopy} {
   799  		if params.isGroupedFlagOKDeeply(flag) { //nolint:nestif,gocritic // nestingReduce: invert if cond, replace body with `continue`, move old body after the statement
   800  			dbglog.Log("Using slice merge mode: %v", flag)
   801  			dbglog.Log("  from.type: %v, value: %v", tool.Typfmtv(&from), tool.Valfmt(&from))
   802  			dbglog.Log("    to.type: %v, value: %v | canAddr: %v, canSet: %v", tool.Typfmtv(&to), tool.Valfmt(&to), to.CanAddr(), to.CanSet())
   803  			// Log(" src.type: %v, len: %v, cap: %v, srcptr.canAddr: %v", src.Type().Kind(), src.Len(), src.Cap(), srcptr.CanAddr())
   804  			dbglog.Log("   tgt.type: %v, tgtptr: %v .canAddr: %v", tool.Typfmtv(&tgt), tool.Typfmtv(&tgtptr), tgtptr.CanAddr())
   805  
   806  			if fn, ok := getSliceOperations()[flag]; ok {
   807  				if result, err = fn(c, params, from, tgt); err == nil {
   808  					dbglog.Log("     result: got %v (%v)", tool.Valfmt(result), tool.Typfmtv(result))
   809  					dbglog.Log("        tgt: contains %v (%v) | tgtptr: %v, .canset: %v", tool.Valfmt(&tgt), tool.Typfmtv(&tgt), tool.Typfmtv(&tgtptr), tgtptr.CanSet())
   810  
   811  					if tk := tgtptr.Kind(); tk == reflect.Ptr { //nolint:gocritic //keep it
   812  						tgtptr.Elem().Set(*result)
   813  					} else if tk == reflect.Slice || tk == reflect.Interface {
   814  						// dbglog.Log("        TGT: %v", tool.Valfmt(&tgt))
   815  						if tgtptr.CanSet() {
   816  							tgtptr.Set(*result)
   817  						}
   818  					} else {
   819  						dbglog.Log("      error: cannot make copy for a slice, the target ptr is cannot be set: tgtptr.typ = %v", tool.Typfmtv(&tgtptr))
   820  						ec.Attach(errors.New("cannot make copy for a slice, the target ptr is cannot be set: tgtptr.typ = %v", tool.Typfmtv(&tgtptr)))
   821  					}
   822  				} else {
   823  					dbglog.Log("      error: ec.Attach(e), e: %v", err)
   824  					ec.Attach(err)
   825  				}
   826  			} else {
   827  				dbglog.Log("      error: cannot make copy for a slice, unknown copy-merge-strategy %v", flag)
   828  				ec.Attach(errors.New("cannot make copy for a slice, unknown copy-merge-strategy %v", flag))
   829  			}
   830  
   831  			break
   832  		}
   833  	}
   834  
   835  	return
   836  }
   837  
   838  // transferSlice never used
   839  //
   840  //nolint:unused //future
   841  func transferSlice(src, tgt reflect.Value) reflect.Value {
   842  	i, sl, tl := 0, src.Len(), tgt.Len()
   843  	for ; i < sl && i < tl; i++ {
   844  		if i < tl {
   845  			if i >= sl {
   846  				tgt.SetLen(i)
   847  				break
   848  			}
   849  			tgt.Index(i).Set(src.Index(i))
   850  		}
   851  	}
   852  	if i < sl && i >= tl {
   853  		for ; i < sl; i++ {
   854  			tgt = reflect.Append(tgt, src.Index(i))
   855  		}
   856  	}
   857  	return tgt
   858  }
   859  
   860  type fnSliceOperator func(c *cpController, params *Params, src, tgt reflect.Value) (result *reflect.Value, err error)
   861  type mSliceOperations map[cms.CopyMergeStrategy]fnSliceOperator
   862  
   863  func getSliceOperations() (mapOfSliceOperations mSliceOperations) {
   864  	mapOfSliceOperations = mSliceOperations{ //nolint:exhaustive //i have right
   865  		cms.SliceCopy:       _sliceCopyOperation,
   866  		cms.SliceCopyAppend: _sliceCopyAppendOperation,
   867  		cms.SliceMerge:      _sliceMergeOperation,
   868  	}
   869  	return
   870  }
   871  
   872  // _sliceCopyOperation: for SliceCopy, target elements will be given up, and source copied to.
   873  func _sliceCopyOperation(c *cpController, params *Params, src, tgt reflect.Value) (result *reflect.Value, err error) {
   874  	slice := reflect.MakeSlice(tgt.Type(), 0, src.Len())
   875  	dbglog.Log("tgt slice: %v, el: %v", tgt.Type(), tgt.Type().Elem())
   876  
   877  	ecTotal := errors.New("slice merge errors (%v -> %v)", src.Type(), tgt.Type())
   878  	defer ecTotal.Defer(&err)
   879  
   880  	// if c.wipeSlice1st {
   881  	// 	// TODO c.wipeSlice1st
   882  	// }
   883  
   884  	for _, ss := range []struct {
   885  		length int
   886  		source reflect.Value
   887  	}{
   888  		// {tl, tgt},
   889  		{src.Len(), src},
   890  	} {
   891  		var one *reflect.Value
   892  		one, err = _sliceCopyOne(c, params, ecTotal, slice, ss.length, ss.source, tgt)
   893  		if one != nil && err == nil {
   894  			slice = *one
   895  		}
   896  	}
   897  	result = &slice
   898  	return
   899  }
   900  
   901  // _sliceCopyAppendOperation: for SliceCopyAppend, target and source elements will be copied to new target.
   902  // The duplicated elements were kept.
   903  //
   904  //nolint:lll //keep it
   905  func _sliceCopyAppendOperation(c *cpController, params *Params, src, tgt reflect.Value) (result *reflect.Value, err error) {
   906  	sl, tl := src.Len(), tgt.Len()
   907  	ns := reflect.MakeSlice(tgt.Type(), 0, 0)
   908  	dbglog.Log("tgt slice: %v, el: %v", tgt.Type(), tgt.Type().Elem())
   909  
   910  	ecTotal := errors.New("slice merge errors (%v -> %v)", src.Type(), tgt.Type())
   911  	defer ecTotal.Defer(&err)
   912  
   913  	for _, ss := range []struct {
   914  		length int
   915  		source reflect.Value
   916  	}{
   917  		{tl, tgt},
   918  		{sl, src},
   919  	} {
   920  		var one *reflect.Value
   921  		one, err = _sliceCopyOne(c, params, ecTotal, ns, ss.length, ss.source, tgt)
   922  		if one != nil && err == nil {
   923  			ns = *one
   924  		}
   925  	}
   926  	result = &ns
   927  	return
   928  }
   929  
   930  //nolint:lll //keep it
   931  func _sliceCopyOne(c *cpController, params *Params, ecTotal errors.Error, slice reflect.Value, sslength int, sssource, tgt reflect.Value) (result *reflect.Value, err error) {
   932  	tgtelemtype := tgt.Type().Elem()
   933  	for i := 0; i < sslength; i++ {
   934  		var (
   935  			el   = sssource.Index(i)
   936  			enew = el
   937  		)
   938  		// elv := el.Interface()
   939  		if el.Type() != tgtelemtype {
   940  			if cc, ctx := c.valueConverters.findConverters(params, el.Type(), tgtelemtype, false); cc != nil {
   941  				if enew, err = cc.Transform(ctx, el, tgtelemtype); err != nil {
   942  					ec := errors.New("cannot convert %v to %v", el.Type(), tgtelemtype)
   943  					ec.Attach(err)
   944  					ecTotal.Attach(ec)
   945  					continue // ignore invalid element
   946  				}
   947  			} else if tool.CanConvert(&el, tgtelemtype) {
   948  				enew = el.Convert(tgtelemtype)
   949  				// elv = enew.Interface()
   950  			}
   951  		}
   952  
   953  		if el.Type() == tgtelemtype { //nolint:nestif //keep it
   954  			slice = reflect.Append(slice, el)
   955  		} else {
   956  			if tool.CanConvert(&el, tgtelemtype) {
   957  				slice = reflect.Append(slice, enew)
   958  			} else {
   959  				enew = reflect.New(tgtelemtype)
   960  				e := c.copyTo(params, el, enew)
   961  				if e != nil {
   962  					ec := errors.New("cannot convert %v to %v", el.Type(), tgtelemtype)
   963  					ec.Attach(e)
   964  					ecTotal.Attach(ec)
   965  				} else {
   966  					slice = reflect.Append(slice, enew.Elem())
   967  				}
   968  			}
   969  		}
   970  		// ecTotal.Attach(ec)
   971  	}
   972  	result = &slice
   973  	return
   974  }
   975  
   976  // _sliceMergeOperation: for SliceMerge. target and source elements will be
   977  // copied to new target with uniqueness.
   978  //
   979  //nolint:gocognit //unify scene
   980  func _sliceMergeOperation(c *cpController, params *Params, src, tgt reflect.Value) (result *reflect.Value, err error) {
   981  	sl, tl := src.Len(), tgt.Len()
   982  	ns := reflect.MakeSlice(tgt.Type(), 0, 0)
   983  	tgtelemtype := tgt.Type().Elem()
   984  	dbglog.Log("tgt slice: %v, el: %v", tgt.Type(), tgtelemtype)
   985  
   986  	ecTotal := errors.New("slice merge errors (%v -> %v)", src.Type(), tgt.Type())
   987  	defer ecTotal.Defer(&err)
   988  
   989  	for _, ss := range []struct {
   990  		length int
   991  		source reflect.Value
   992  	}{
   993  		{tl, tgt},
   994  		{sl, src},
   995  	} {
   996  		for i := 0; i < ss.length; i++ {
   997  			// to.Set(reflect.Append(to, src.Index(i)))
   998  			var (
   999  				found bool
  1000  				cvtok bool
  1001  				el    = ss.source.Index(i)
  1002  				elt   = el.Type()
  1003  				elv   = el.Interface()
  1004  				enew  = el
  1005  				ec    = errors.New("cannot convert %v to %v", el.Type(), tgtelemtype)
  1006  			)
  1007  			if elt != tgtelemtype { //nolint:nestif //keep it
  1008  				if cc, ctx := c.valueConverters.findConverters(params, elt, tgtelemtype, false); cc != nil {
  1009  					if enew, err = cc.Transform(ctx, el, tgtelemtype); err != nil {
  1010  						var ve *strconv.NumError
  1011  						if !errors.As(err, &ve) {
  1012  							ec.Attach(err)
  1013  							ecTotal.Attach(ec)
  1014  						}
  1015  						continue // ignore invalid element
  1016  					} else {
  1017  						cvtok, elv = true, enew.Interface()
  1018  					}
  1019  				} else if tool.CanConvert(&el, tgtelemtype) {
  1020  					enew = el.Convert(tgtelemtype)
  1021  					cvtok, elv = true, enew.Interface()
  1022  				}
  1023  			}
  1024  
  1025  			if found = tool.FindInSlice(ns, elv, i); !found { //nolint:nestif //keep it
  1026  				if cvtok || elt == tgtelemtype {
  1027  					ns = reflect.Append(ns, enew)
  1028  				} else {
  1029  					enew = reflect.New(tgtelemtype)
  1030  					e := c.copyTo(params, el, enew)
  1031  					if e != nil {
  1032  						ec.Attach(e)
  1033  						err = ec
  1034  					} else {
  1035  						ns = reflect.Append(ns, enew.Elem())
  1036  					}
  1037  				}
  1038  			}
  1039  			if !ec.IsEmpty() {
  1040  				ecTotal.Attach(ec)
  1041  			}
  1042  		}
  1043  	}
  1044  	result = &ns
  1045  	return
  1046  }
  1047  
  1048  func copyArray(c *cpController, params *Params, from, to reflect.Value) (err error) {
  1049  	if tool.IsZero(from) && params.isGroupedFlagOKDeeply(cms.OmitIfZero, cms.OmitIfEmpty) {
  1050  		return
  1051  	}
  1052  
  1053  	src := tool.Rindirect(from)
  1054  	tgt, tgtptr := tool.Rdecode(to)
  1055  
  1056  	// if !to.CanAddr() && params != nil {
  1057  	//	if !params.isStruct() {
  1058  	//		//to = *params.dstOwner
  1059  	//		Log("    !! use dstOwner to get a ptr to array, new to.type: %v,
  1060  	// canAddr: %v, canSet: %v", to.Type().Kind(), to.CanAddr(), to.CanSet())
  1061  	//	}
  1062  	// }
  1063  
  1064  	// if tgt.CanAddr() == false && tgtptr.CanAddr() {
  1065  	//	tgt = tgtptr
  1066  	// }
  1067  
  1068  	// Log("    tgt.%v: %v", params.dstOwner.Type().Field(params.index).Name, params.dstOwner.Type().Field(params.index))
  1069  	dbglog.Log("    from.type: %v, len: %v, cap: %v", src.Type().Kind(), src.Len(), src.Cap())
  1070  	dbglog.Log("      to.type: %v, len: %v, cap: %v, tgtptr.canSet: %v, tgtptr.canaddr: %v", tgt.Type().Kind(), tgt.Len(), tgt.Cap(), tgtptr.CanSet(), tgtptr.CanAddr()) //nolint:lll //keep it
  1071  
  1072  	tk, tgttyp := tgt.Kind(), tgt.Type()
  1073  	if tk != reflect.Array {
  1074  		var processed bool
  1075  		if processed, err = tryConverters(c, params, &from, &tgt, &tgttyp, false); processed {
  1076  			return
  1077  		}
  1078  		// log.Panicf("[copySlice] unsupported transforming: from slice -> %v,", typfmtv(&tgt))
  1079  		err = ErrCannotCopy.FormatWith(tool.Valfmt(&src), tool.Typfmtv(&src), tool.Valfmt(&tgt), tool.Typfmtv(&tgt))
  1080  		return
  1081  	}
  1082  
  1083  	if tool.IsZero(tgt) && params.isGroupedFlagOKDeeply(cms.OmitIfTargetZero, cms.OmitIfTargetEmpty) {
  1084  		return
  1085  	}
  1086  
  1087  	sl, tl := src.Len(), tgt.Len()
  1088  	eltyp := tgt.Type().Elem()
  1089  	// set := src.Index(0).Type()
  1090  	// if set != tgt.Index(0).Type() {
  1091  	//	return errors.New("cannot copy %v to %v", from.Interface(), to.Interface())
  1092  	// }
  1093  
  1094  	cnt := tool.MinInt(sl, tl)
  1095  	for i := 0; i < cnt; i++ {
  1096  		se := src.Index(i)
  1097  		setyp := se.Type()
  1098  		dbglog.Log("src.el.typ: %v, tgt.el.typ: %v", tool.Typfmt(setyp), eltyp)
  1099  		if se.IsValid() {
  1100  			if setyp.AssignableTo(eltyp) {
  1101  				tgt.Index(i).Set(se)
  1102  			} else if setyp.ConvertibleTo(eltyp) {
  1103  				tgt.Index(i).Set(src.Convert(eltyp))
  1104  			}
  1105  		}
  1106  		// tgt.Index(i).Set(src.Index(i))
  1107  	}
  1108  
  1109  	for i := cnt; i < tl; i++ {
  1110  		v := tgt.Index(i)
  1111  		if !v.IsValid() {
  1112  			tgt.Index(i).Set(reflect.Zero(eltyp))
  1113  			dbglog.Log("set [%v] to zero value", i)
  1114  		}
  1115  	}
  1116  
  1117  	// to.Set(pt.Elem())
  1118  
  1119  	dbglog.Log("    from: %v, to: %v", src.Interface(), tgt.Interface()) // pt.Interface())
  1120  
  1121  	return
  1122  }
  1123  
  1124  func copyMap(c *cpController, params *Params, from, to reflect.Value) (err error) {
  1125  	if from.IsNil() && params.isGroupedFlagOKDeeply(cms.OmitIfNil, cms.OmitIfEmpty) { // an empty slice found
  1126  		return
  1127  	}
  1128  
  1129  	var tgt, tgtptr reflect.Value
  1130  	tgt, tgtptr = tool.Rdecode(to)
  1131  	if to != tgtptr { //nolint:govet //how should i do //TODO needs checked-review
  1132  		err = c.copyTo(params, from, tgtptr) // unwrap the pointer
  1133  		return
  1134  	}
  1135  
  1136  	tk, typ := tgt.Kind(), tgt.Type()
  1137  	if tk != reflect.Map {
  1138  		dbglog.Log("from map -> %v", tool.Typfmt(typ))
  1139  		// copy map to String, Slice, Struct
  1140  		var processed bool
  1141  		if processed, err = tryConverters(c, params, &from, &tgt, &typ, false); !processed {
  1142  			err = ErrCannotCopy.WithErrors(err).
  1143  				FormatWith(tool.Valfmt(&from), tool.Typfmtv(&from), tool.Valfmt(&tgt), tool.Typfmtv(&tgt))
  1144  		}
  1145  		return
  1146  	}
  1147  
  1148  	tgtNil := tool.IsNil(tgt)
  1149  	if tgtNil && params.isGroupedFlagOKDeeply(cms.OmitIfTargetZero, cms.OmitIfTargetEmpty) {
  1150  		return
  1151  	}
  1152  
  1153  	ec := errors.New("map copy/merge errors")
  1154  	defer dbglog.DeferVisit(ec, &err)
  1155  
  1156  	// By default, the nested copyTo() cannot print log msg via dbglog.Log
  1157  	// so we get clearer logging lines for debugging.
  1158  	// To enabled them, use build tags 'moremaplog'.
  1159  	defer dbglog.DisableLog()()
  1160  
  1161  	for _, flag := range []cms.CopyMergeStrategy{cms.MapMerge, cms.MapCopy} {
  1162  		if params.isGroupedFlagOKDeeply(flag) {
  1163  			if fn, ok := getMapOperations()[flag]; ok {
  1164  				ec.Attach(fn(c, params, from, tgt, tgtptr))
  1165  			} else {
  1166  				ec.Attach(errors.New("unknown strategy for map: %v", flag))
  1167  			}
  1168  			break // once any of copy-merge strategy matched, stop iterating now
  1169  		}
  1170  	}
  1171  	return
  1172  }
  1173  
  1174  type fnMapOperation func(c *cpController, params *Params, src, tgt, tgtptr reflect.Value) (err error)
  1175  type mapMapOperations map[cms.CopyMergeStrategy]fnMapOperation
  1176  
  1177  func getMapOperations() (mMapOperations mapMapOperations) {
  1178  	mMapOperations = mapMapOperations{ //nolint:exhaustive //i have right
  1179  		cms.MapCopy: func(c *cpController, params *Params, src, tgt, tgtptr reflect.Value) (err error) {
  1180  			tgt.Set(reflect.MakeMap(src.Type()))
  1181  
  1182  			ec := errors.New("map copy errors")
  1183  			defer ec.Defer(&err)
  1184  
  1185  			for _, key := range src.MapKeys() {
  1186  				originalValue := src.MapIndex(key)
  1187  				_, copyValueElem := newFromType(tgt.Type().Elem())
  1188  				ec.Attach(c.copyTo(params, originalValue, copyValueElem))
  1189  
  1190  				copyKey := reflect.New(tgt.Type().Key())
  1191  				ec.Attach(c.copyTo(params, key, copyKey.Elem()))
  1192  
  1193  				if c.targetSetter != nil && copyKey.Elem().Kind() == reflect.String {
  1194  					srcval := copyValueElem
  1195  					err = c.targetSetter(&srcval, copyKey.Elem().String())
  1196  					if err != nil {
  1197  						if err != ErrShouldFallback { //nolint:errorlint //want it exactly
  1198  							return
  1199  						}
  1200  						err = nil
  1201  					} else {
  1202  						return
  1203  					}
  1204  				}
  1205  				trySetMapIndex(c, params, tgt, copyKey.Elem(), copyValueElem)
  1206  			}
  1207  			return
  1208  		},
  1209  		cms.MapMerge: func(c *cpController, params *Params, src, tgt, tgtptr reflect.Value) (err error) {
  1210  			ec := errors.New("map merge errors")
  1211  			defer ec.Defer(&err)
  1212  
  1213  			for _, key := range src.MapKeys() {
  1214  				// dbglog.Log("------------ [MapMerge] mergeOneKeyInMap: key = %q (%v) ------------------",
  1215  				// 	tool.Valfmt(&key), tool.Typfmtv(&key))
  1216  				ec.Attach(mergeOneKeyInMap(c, params, src, tgt, tgtptr, key))
  1217  			}
  1218  			return
  1219  		},
  1220  	}
  1221  	return
  1222  }
  1223  
  1224  func mapMergePreSetter(c *cpController, ck, cv reflect.Value) (processed bool, err error) {
  1225  	if c.targetSetter != nil && ck.Kind() == reflect.String {
  1226  		err = c.targetSetter(&cv, ck.String())
  1227  		if err != nil {
  1228  			if err == ErrShouldFallback { //nolint:errorlint //want it exactly
  1229  				processed, err = true, nil
  1230  			}
  1231  		} else {
  1232  			processed = true
  1233  		}
  1234  	}
  1235  	return
  1236  }
  1237  
  1238  // mergeOneKeyInMap copy one (key, value) pair in src map to tgt map.
  1239  func mergeOneKeyInMap(c *cpController, params *Params, src, tgt, tgtptr, key reflect.Value) (err error) {
  1240  	var processed bool
  1241  
  1242  	dbglog.Colored(color.LightMagenta, "      <MAP> copying key '%v': (%v) -> (?)", tool.Valfmt(&key), tool.Valfmtv(src.MapIndex(key)))
  1243  
  1244  	var ck reflect.Value
  1245  	if ck, err = cloneMapKey(c, params, tgt, key); err != nil {
  1246  		return
  1247  	}
  1248  
  1249  	originalValue := src.MapIndex(key)
  1250  
  1251  	tgtval, newelemcreated, err2 := ensureMapPtrValue(c, params, tgt, ck, originalValue)
  1252  	if err = err2; err2 != nil {
  1253  		return
  1254  	}
  1255  	if newelemcreated {
  1256  		cv := tool.Rindirect(tgtval)
  1257  		if processed, err = mapMergePreSetter(c, ck, cv); processed {
  1258  			return
  1259  		}
  1260  		defer matchTypeAndSetMapIndex(c, params, tgt, ck, tgtval)
  1261  		if err = c.copyTo(params, originalValue, tgtval); err != nil {
  1262  			return
  1263  		}
  1264  		dbglog.Log("      <MAP> original item value: m[%v] => %v", tool.Valfmtptr(&ck), tool.Valfmt(&cv))
  1265  		return
  1266  	}
  1267  	dbglog.Log("      <VAL> duplicated/gotten: %v", tool.Valfmtptr(&tgtval))
  1268  
  1269  	eltyp := tgt.Type().Elem() // get map value type
  1270  	eltypind, _ := tool.Rskiptype(eltyp, reflect.Ptr)
  1271  
  1272  	var ptrToCopyValue, cv reflect.Value
  1273  	if eltypind.Kind() == reflect.Interface { //nolint:nestif //keep it
  1274  		var tt reflect.Type
  1275  		tgtvalind, _ := tool.Rdecode(tgtval)
  1276  		if !tgtval.IsValid() || tool.IsZero(tgtval) {
  1277  			srcval := src.MapIndex(ck)
  1278  			if !srcval.IsValid() || tool.IsZero(srcval) {
  1279  				tgtvalind = srcval
  1280  				tt = tgtvalind.Type()
  1281  			} else {
  1282  				tt = srcval.Type()
  1283  			}
  1284  		} else {
  1285  			tt = tgtvalind.Type()
  1286  		}
  1287  		dbglog.Log("  tgtval: [%v] %v, ind: %v | tt: %v", tool.Typfmtv(&tgtval), tool.Valfmt(&tgtval), tool.Typfmtv(&tgtvalind), tool.Typfmt(tt))
  1288  		ptrToCopyValue, cv = newFromType(tt)
  1289  		if processed, err = mapMergePreSetter(c, ck, cv); processed {
  1290  			return
  1291  		}
  1292  		defer trySetMapIndex(c, params, tgt, ck, cv)
  1293  		// defer func() {
  1294  		// 	trySetMapIndex(c, params, tgt, ck, cv)
  1295  		// 	dbglog.Log("  SetMapIndex: %v -> [%v] %v", ck.Interface(), cv.Type(), cv.Interface())
  1296  		// }()
  1297  	} else {
  1298  		ptrToCopyValue, cv = newFromType(eltypind)
  1299  		if processed, err = mapMergePreSetter(c, ck, cv); processed {
  1300  			return
  1301  		}
  1302  		defer matchTypeAndSetMapIndex(c, params, tgt, ck, ptrToCopyValue)
  1303  		// defer func() {
  1304  		// 	if cv.Type() == eltyp {
  1305  		// 		tgt.SetMapIndex(ck, cv)
  1306  		// 		dbglog.Log("  SetMapIndex: %v -> [%v] %v", ck.Interface(), cv.Type(), cv.Interface())
  1307  		// 	} else {
  1308  		// 		dbglog.Log("  SetMapIndex: %v -> [%v] %v", ck.Interface(), ptrToCopyValue.Type(), ptrToCopyValue.Interface())
  1309  		// 		tgt.SetMapIndex(ck, ptrToCopyValue)
  1310  		// 	}
  1311  		// }()
  1312  	}
  1313  
  1314  	dbglog.Log("  ptrToCopyValue.type: %v, eltypind: %v", tool.Typfmtv(&ptrToCopyValue), tool.Typfmt(eltypind))
  1315  	if err = c.copyTo(params, tgtval, ptrToCopyValue); err != nil {
  1316  		return
  1317  	}
  1318  	if err = c.copyTo(params, originalValue, ptrToCopyValue); err != nil {
  1319  		return
  1320  	}
  1321  
  1322  	return
  1323  }
  1324  
  1325  func matchTypeAndSetMapIndex(c *cpController, params *Params, m, key, val reflect.Value) {
  1326  	ve := m.Type().Elem()
  1327  	cv := tool.Rindirect(val)
  1328  	if cv.Type() == ve {
  1329  		trySetMapIndex(c, params, m, key, cv)
  1330  		dbglog.Log("      <MAP> map.item set to val.ind: %v -> %v", tool.Valfmt(&key), tool.Valfmt(&cv))
  1331  	} else if val.Type() == ve {
  1332  		trySetMapIndex(c, params, m, key, val)
  1333  		dbglog.Log("      <MAP> map.item set to val: %v -> %v", tool.Valfmt(&key), tool.Valfmt(&val))
  1334  	} else if val.Kind() == reflect.Ptr && val.Type().Elem() == ve { // tgtval is ptr to elem? such as tgtval got *bool, and the map[ck] => bool
  1335  		trySetMapIndex(c, params, m, key, val.Elem())
  1336  		dbglog.Log("      <MAP> map.item set to val.elem: %v -> %v", tool.Valfmt(&key), tool.Valfmtv(val.Elem()))
  1337  		dbglog.Log("      <MAP> map: %v", tool.Valfmt(&m))
  1338  	} else if ve.Kind() == reflect.Interface { // the map is map[key]interface{} ?, so the val can be anything.
  1339  		if val.Kind() == reflect.Ptr {
  1340  			trySetMapIndex(c, params, m, key, val.Elem())
  1341  		} else {
  1342  			trySetMapIndex(c, params, m, key, val)
  1343  		}
  1344  	} else {
  1345  		log.Warnf("cannot setMapIndex for key '%v' since val type mismatched: desired elem typ = %v, real tgt val.typ = %v.", tool.Valfmt(&key), tool.Typfmt(ve), tool.Typfmtv(&val))
  1346  	}
  1347  }
  1348  
  1349  func trySetMapIndex(c *cpController, params *Params, m, key, val reflect.Value) {
  1350  	// dbglog.Colored(color.LightMagenta, "    setting map index: %v -> %v", tool.Valfmt(&key), tool.Valfmt(&val))
  1351  	if params != nil && params.controller != nil && params.accessor != nil && params.controller.copyUnexportedFields {
  1352  		if fld := params.accessor.StructField(); fld != nil {
  1353  			// in a struct
  1354  			if !tool.IsExported(fld) {
  1355  				dbglog.Log("    unexported field %q (typ: %v): key '%v' => val '%v'",
  1356  					fld.Name, tool.Typfmt(fld.Type), tool.Valfmt(&key), tool.Valfmt(&val))
  1357  				cl.SetUnexportedFieldIfMap(m, key, val)
  1358  				return
  1359  			}
  1360  		}
  1361  	}
  1362  
  1363  	if params != nil && params.resultForNewSlice != nil { // specially for value is a slice
  1364  		m.SetMapIndex(key, *params.resultForNewSlice)
  1365  		params.resultForNewSlice = nil
  1366  		return
  1367  	}
  1368  
  1369  	m.SetMapIndex(key, val)
  1370  }
  1371  
  1372  func newFromType(typ reflect.Type) (valptr, val reflect.Value) {
  1373  	if k := typ.Kind(); k == reflect.Ptr {
  1374  		vp := reflect.New(typ)
  1375  		v := vp.Elem()
  1376  		ptr, _ := newFromType(typ.Elem())
  1377  		v.Set(ptr)
  1378  		valptr, val = vp, v // .Elem()
  1379  		dbglog.Log("creating new object for type %v: %+v", tool.Typfmt(typ), tool.Valfmt(&valptr))
  1380  	} else if k == reflect.Slice {
  1381  		valptr = reflect.MakeSlice(typ, 0, 0)
  1382  		val = valptr
  1383  	} else if k == reflect.Map { //nolint:gocritic //keep it
  1384  		valptr = reflect.MakeMap(typ)
  1385  		val = valptr
  1386  	} else if k == reflect.Chan {
  1387  		valptr = reflect.MakeChan(typ, 0)
  1388  		val = valptr
  1389  	} else if k == reflect.Func {
  1390  		valptr = reflect.MakeFunc(typ, func(args []reflect.Value) []reflect.Value { return args })
  1391  		val = valptr
  1392  	} else {
  1393  		valptr = reflect.New(typ)
  1394  		val = valptr.Elem()
  1395  	}
  1396  	return
  1397  }
  1398  
  1399  // newFromTypeEspSlice makes new instance for a given type.
  1400  // especially for a slice, newFromTypeEspSlice will make a pointer
  1401  // to a new slice, so that we can set the whole slice via this
  1402  // pointer later.
  1403  func newFromTypeEspSlice(typ reflect.Type) (val, valelem reflect.Value) {
  1404  	if k := typ.Kind(); k == reflect.Ptr {
  1405  		valelem, _ = newFromTypeEspSlice(typ.Elem())
  1406  		val = valelem.Addr()
  1407  	} else if k == reflect.Slice {
  1408  		var tp = tool.PointerTo(typ)
  1409  		val = reflect.New(tp).Elem()
  1410  		// valval := reflect.MakeSlice(typ, 0, 0)
  1411  		// val.Set(valval.Addr())
  1412  		val.Set(reflect.New(typ))
  1413  		valelem = val
  1414  	} else {
  1415  		val, valelem = newFromType(typ)
  1416  	}
  1417  	return
  1418  }
  1419  
  1420  //nolint:lll //keep it
  1421  func ensureMapPtrValue(c *cpController, params *Params, m, key, originalValue reflect.Value) (val reflect.Value, ptr bool, err error) {
  1422  	val = m.MapIndex(key)
  1423  	vk := val.Kind()
  1424  	if vk == reflect.Ptr { //nolint:nestif //keep it
  1425  		if tool.IsNil(val) {
  1426  			typOfValueOfMap := m.Type().Elem()     // make new instance of type pointed by pointer
  1427  			val, _ = newFromType(typOfValueOfMap)  //
  1428  			trySetMapIndex(c, params, m, key, val) // and set the new pointer into map
  1429  			ptr = true                             //
  1430  			dbglog.Log("    ensureMapPtrValue:val.typ: %v, key.typ: %v | '%v' -> %v", tool.Typfmt(typOfValueOfMap), tool.Typfmtv(&key), tool.Valfmt(&key), tool.Valfmtptr(&val))
  1431  		} else {
  1432  			// dbglog.Log("    ensureMapPtrValue: do nothing because val's is not nil")
  1433  		}
  1434  	} else if !val.IsValid() {
  1435  		typOfValueOfMap := m.Type().Elem()
  1436  		if typOfValueOfMap.Kind() != reflect.Interface {
  1437  			var valelem reflect.Value
  1438  			val, valelem = newFromType(typOfValueOfMap)
  1439  			dbglog.Log("    ensureMapPtrValue:val.typ: %v, key.typ: %v | '%v' -> %v", tool.Typfmt(typOfValueOfMap), tool.Typfmtv(&key), tool.Valfmt(&key), tool.Valfmtptr(&valelem))
  1440  			trySetMapIndex(c, params, m, key, valelem)
  1441  			ptr = true // val = vind
  1442  		} else if originalValue.IsValid() && !tool.IsZero(originalValue) { // if original value is zero, no copying needed.
  1443  			typ := tool.Rdecodesimple(originalValue).Type()
  1444  			val, _ = newFromTypeEspSlice(typ)
  1445  			ptr = true
  1446  			dbglog.Log("    ensureMapPtrValue:val.typ: %v, key.typ: %v | '%v' -> %v", tool.Typfmt(typ), tool.Typfmtv(&key), tool.Valfmt(&key), tool.Valfmtptr(&val))
  1447  			if err = c.copyTo(params, originalValue, val); err != nil {
  1448  				return
  1449  			}
  1450  			var processed bool
  1451  			if processed, err = mapMergePreSetter(c, key, val); processed {
  1452  				return
  1453  			}
  1454  			trySetMapIndex(c, params, m, key, val)
  1455  			dbglog.Log("    ensureMapPtrValue:val.typ: %v, key.typ: %v | '%v' -> %v | DONE", tool.Typfmt(typ), tool.Typfmtv(&key), tool.Valfmt(&key), tool.Valfmtptr(&val))
  1456  		} else {
  1457  			// dbglog.Log("    ensureMapPtrValue: do nothing because val and src-val are both invalid, so needn't copy.")
  1458  		}
  1459  	}
  1460  	return
  1461  }
  1462  
  1463  func cloneMapKey(c *cpController, params *Params, tgt, key reflect.Value) (ck reflect.Value, err error) {
  1464  	keyType := tgt.Type().Key()
  1465  	ptrToCopyKey := reflect.New(keyType)
  1466  	dbglog.Log("     cloneMapKey(%v): tgt(map).type: %v, tgt.key.type: %v, ptrToCopyKey.type: %v", tool.Valfmt(&key), tool.Typfmtv(&tgt), tool.Typfmt(keyType), tool.Typfmtv(&ptrToCopyKey))
  1467  	ck = ptrToCopyKey.Elem()
  1468  
  1469  	emptyParams := newParams() // use an empty params for just copying map key so the current processing struct fields won't be cared in this special child copier
  1470  	if err = c.copyTo(emptyParams, key, ck); err != nil {
  1471  		dbglog.Err("     cloneMapKey(%v) error on copyTo: %+v", tool.Valfmt(&key), err) // early break-point here
  1472  		return
  1473  	}
  1474  
  1475  	dbglog.Log("         <KEY> cloned: '%v'", tool.Valfmtptr(&ck))
  1476  	return
  1477  }
  1478  
  1479  //
  1480  
  1481  //
  1482  
  1483  //
  1484  
  1485  func copyUintptr(c *cpController, params *Params, from, to reflect.Value) (err error) {
  1486  	tgt := tool.Rindirect(to)
  1487  	if tgt.CanSet() {
  1488  		tgt.Set(from)
  1489  	} else {
  1490  		// to.SetPointer(from.Pointer())
  1491  		dbglog.Log("    copy uintptr not support: %v -> %v", from.Kind(), to.Kind())
  1492  		err = ErrCannotCopy.FormatWith(tool.Valfmt(&from), tool.Typfmtv(&from), tool.Valfmt(&to), tool.Typfmtv(&to))
  1493  	}
  1494  	return
  1495  }
  1496  
  1497  func copyUnsafePointer(c *cpController, params *Params, from, to reflect.Value) (err error) {
  1498  	tgt := tool.Rindirect(to)
  1499  	if tgt.CanSet() {
  1500  		tgt.Set(from)
  1501  	} else {
  1502  		dbglog.Log("    copy unsafe pointer not support: %v -> %v", from.Kind(), to.Kind())
  1503  		err = ErrCannotCopy.FormatWith(tool.Valfmt(&from), tool.Typfmtv(&from), tool.Valfmt(&to), tool.Typfmtv(&to))
  1504  	}
  1505  	return
  1506  }
  1507  
  1508  // copyFunc never used.
  1509  // Deprecated always.
  1510  func copyFunc(c *cpController, params *Params, from, to reflect.Value) (err error) { //nolint:unused,deadcode //reserved
  1511  	tgt := tool.Rindirect(to)
  1512  	if tgt.CanSet() {
  1513  		tgt.Set(from)
  1514  		return
  1515  	}
  1516  
  1517  	k := tgt.Kind()
  1518  	if k != reflect.Func && c.copyFunctionResultToTarget {
  1519  		// from.
  1520  		return
  1521  	}
  1522  
  1523  	if k == reflect.Func {
  1524  		if !params.processUnexportedField(to, from) {
  1525  			ptr := from.Pointer()
  1526  			//goland:noinspection GoVetUnsafePointer
  1527  			to.SetPointer(unsafe.Pointer(ptr))
  1528  		}
  1529  		dbglog.Log("    function pointer copied: %v (%v) -> %v", from.Kind(), from.Interface(), to.Kind())
  1530  	} else {
  1531  		err = ErrCannotCopy.FormatWith(tool.Valfmt(&from), tool.Typfmtv(&from), tool.Valfmt(&to), tool.Typfmtv(&to))
  1532  	}
  1533  
  1534  	return
  1535  }
  1536  
  1537  func copyChan(c *cpController, params *Params, from, to reflect.Value) (err error) {
  1538  	tgt := tool.Rindirect(to)
  1539  	if tgt.CanSet() {
  1540  		dbglog.Log("    copy chan: %v (%v) -> %v (%v)", from.Kind(), from.Type(), tgt.Kind(), tgt.Type())
  1541  		tgt.Set(from)
  1542  		// Log("        after: %v -> %v", from.Interface(), tgt.Interface())
  1543  	} else {
  1544  		v := reflect.MakeChan(from.Type(), from.Cap())
  1545  		to.Set(v)
  1546  		// // to.SetPointer(from.Pointer())
  1547  		// dbglog.Log("    copy chan not support: %v (%v) -> %v (%v)", from.Kind(), from.Type(), to.Kind(), to.Type())
  1548  		// err = ErrCannotCopy.FormatWith(tool.Valfmt(&from), tool.Typfmtv(&from), tool.Valfmt(&to), tool.Typfmtv(&to))
  1549  	}
  1550  	return
  1551  }
  1552  
  1553  //
  1554  
  1555  func copyDefaultHandler(c *cpController, params *Params, from, to reflect.Value) (err error) {
  1556  	sourceType, targetType := from.Type(), to.Type()
  1557  
  1558  	if c != nil {
  1559  		if cvt, ctx := c.valueCopiers.findCopiers(params, sourceType, targetType, false); cvt != nil {
  1560  			err = cvt.CopyTo(ctx, from, to)
  1561  			return
  1562  		}
  1563  	}
  1564  
  1565  	fromind, toind := tool.Rdecodesimple(from), tool.Rdecodesimple(to)
  1566  	dbglog.Log("  copyDefaultHandler: %v -> %v | %v", tool.Typfmtv(&fromind), tool.Typfmtv(&toind), tool.Typfmtv(&to))
  1567  
  1568  	// //////////////// source is primitive types but target isn't its
  1569  	var processed bool
  1570  	var toIndType = targetType
  1571  	if toind.IsValid() {
  1572  		toIndType = toind.Type()
  1573  	}
  1574  	processed, err = copyPrimitiveToComposite(c, params, from, to, toIndType)
  1575  	if processed || err != nil {
  1576  		return
  1577  	}
  1578  
  1579  	// create new
  1580  	if !toind.IsValid() && to.Kind() == reflect.Ptr {
  1581  		tgt := reflect.New(targetType.Elem())
  1582  		toind = tgt.Elem()
  1583  		defer func() {
  1584  			if err == nil {
  1585  				to.Set(tgt)
  1586  			}
  1587  		}()
  1588  	}
  1589  
  1590  	// try primitive -> primitive at first
  1591  	if processed, err = tryCopyPrimitiveToPrimitive(params, from, fromind, to, toind, sourceType, targetType, toIndType); processed { //nolint:lll //keep it
  1592  		return
  1593  	}
  1594  
  1595  	err = ErrCannotConvertTo.FormatWith(fromind.Interface(), fromind.Kind(), toind.Interface(), toind.Kind())
  1596  	dbglog.Err("    Error: %v", err)
  1597  	return
  1598  }
  1599  
  1600  //nolint:lll //keep it
  1601  func tryCopyPrimitiveToPrimitive(params *Params, from, fromind, to, toind reflect.Value, sourceType, targetType, toIndType reflect.Type) (stop bool, err error) {
  1602  	stop = true
  1603  	if tool.CanConvert(&fromind, toIndType) {
  1604  		var val = fromind.Convert(toIndType)
  1605  		err = setTargetValue1(params, to, toind, val)
  1606  		return
  1607  	}
  1608  	if tool.CanConvert(&from, to.Type()) && to.CanSet() {
  1609  		var val = from.Convert(to.Type())
  1610  		err = setTargetValue1(params, to, toind, val)
  1611  		return
  1612  	}
  1613  	if sourceType.AssignableTo(targetType) {
  1614  		if toind.CanSet() { //nolint:gocritic // no need to switch to 'switch' clause
  1615  			toind.Set(fromind)
  1616  		} else if to.CanSet() {
  1617  			to.Set(fromind)
  1618  		} else {
  1619  			err = ErrCannotSet.FormatWith(fromind, tool.Typfmtv(&fromind), toind, tool.Typfmtv(&toind))
  1620  		}
  1621  		return
  1622  	}
  1623  	stop = false
  1624  	return
  1625  }
  1626  
  1627  //nolint:lll //keep it
  1628  func copyPrimitiveToComposite(c *cpController, params *Params, from, to reflect.Value, desiredType reflect.Type) (processed bool, err error) {
  1629  	switch tk := desiredType.Kind(); tk { //nolint:exhaustive //no need
  1630  	case reflect.Slice:
  1631  		dbglog.Log("  copyPrimitiveToComposite: %v -> %v | %v", tool.Typfmtv(&from), tool.Typfmt(desiredType), tool.Typfmtv(&to))
  1632  
  1633  		eltyp := desiredType.Elem()
  1634  		elnew := reflect.New(eltyp)
  1635  		if err = copyDefaultHandler(c, params, from, elnew); err != nil {
  1636  			return
  1637  		}
  1638  
  1639  		elnewelem := elnew.Elem()
  1640  		dbglog.Log("    source converted: %v (%v)", tool.Valfmt(&elnewelem), tool.Typfmtv(&elnewelem))
  1641  
  1642  		slice := reflect.MakeSlice(reflect.SliceOf(eltyp), 1, 1)
  1643  		slice.Index(0).Set(elnewelem)
  1644  		dbglog.Log("    source converted: %v (%v)", tool.Valfmt(&slice), tool.Typfmtv(&slice))
  1645  
  1646  		err = copySlice(c, params, slice, to)
  1647  		processed = true
  1648  
  1649  	case reflect.Map:
  1650  		// not support
  1651  
  1652  	case reflect.Struct:
  1653  		// not support
  1654  
  1655  	case reflect.Func:
  1656  		tgt := tool.Rdecodesimple(to)
  1657  		processed, err = true, copyToFuncImpl(c, from, tgt, tgt.Type())
  1658  	}
  1659  
  1660  	return
  1661  }
  1662  
  1663  func setTargetValue1(params *Params, to, toind, newval reflect.Value) (err error) {
  1664  	if err = setTargetValue2(params, toind, newval); err == nil {
  1665  		return //nolint:nilerr //i do
  1666  	}
  1667  	if to != toind { //nolint:govet //how should i do //TODO needs checked-review
  1668  		if err = setTargetValue2(params, to, newval); err == nil {
  1669  			return //nolint:nilerr //i do
  1670  		}
  1671  	}
  1672  	if err == nil {
  1673  		err = ErrUnknownState.WithTaggedData(errors.TaggedData{ // record the sites
  1674  			"source": tool.Valfmt(&toind),
  1675  			"target": tool.Valfmt(&newval),
  1676  		})
  1677  	}
  1678  	return
  1679  }
  1680  
  1681  func setTargetValue2(params *Params, to, newval reflect.Value) (err error) {
  1682  	if copyUnexportedFields, isExported := params.dstFieldIsExportedR(); !isExported {
  1683  		if copyUnexportedFields {
  1684  			cl.SetUnexportedField(to, newval)
  1685  		} // else do nothing
  1686  		return
  1687  	}
  1688  	
  1689  	// const unexportedR = true
  1690  	// if unexportedR {
  1691  	// 	if copyUnexportedFields, isExported := params.dstFieldIsExportedR(); !isExported {
  1692  	// 		if copyUnexportedFields {
  1693  	// 			cl.SetUnexportedField(to, newval)
  1694  	// 		} // else do nothing
  1695  	// 		return
  1696  	// 	}
  1697  	// } else {
  1698  	// 	k := reflect.Invalid
  1699  	// 	if params != nil && params.dstDecoded != nil {
  1700  	// 		k = params.dstDecoded.Kind()
  1701  	// 	}
  1702  	// 
  1703  	// 	if k == reflect.Struct && params.accessor != nil && !tool.IsExported(params.accessor.StructField()) {
  1704  	// 		if params.controller.copyUnexportedFields {
  1705  	// 			cl.SetUnexportedField(to, newval)
  1706  	// 		} // else ignore the unexported field
  1707  	// 		return
  1708  	// 	}
  1709  	// }
  1710  
  1711  	if to.CanSet() {
  1712  		to.Set(newval)
  1713  		return
  1714  		// } else if newval.IsValid() {
  1715  		//	to.Set(newval)
  1716  		//	return
  1717  	}
  1718  
  1719  	err = ErrUnknownState.WithTaggedData(errors.TaggedData{ // record the sites
  1720  		"source": tool.Valfmt(&to),
  1721  		"target": tool.Valfmt(&newval),
  1722  	})
  1723  	return
  1724  }