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 = ¶msChild.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, ¶msChild.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 }