github.com/hedzr/evendeep@v0.4.8/cvts.go (about) 1 package evendeep 2 3 import ( 4 "bytes" 5 "encoding" 6 "encoding/json" 7 "fmt" 8 "math" 9 "reflect" 10 "strconv" 11 "strings" 12 "time" 13 14 "github.com/hedzr/log" 15 16 "github.com/hedzr/evendeep/dbglog" 17 "github.com/hedzr/evendeep/flags" 18 "github.com/hedzr/evendeep/flags/cms" 19 "github.com/hedzr/evendeep/internal/syscalls" 20 "github.com/hedzr/evendeep/internal/tool" 21 "github.com/hedzr/evendeep/typ" 22 23 "gopkg.in/hedzr/errors.v3" 24 ) 25 26 const timeConstString = "time" 27 28 // RegisterDefaultConverters registers the ValueConverter list into 29 // default converters registry. 30 // 31 // It takes effects on DefaultCopyController, MakeClone, DeepCopy, 32 // and New, .... 33 func RegisterDefaultConverters(ss ...ValueConverter) { 34 defValueConverters = append(defValueConverters, ss...) 35 initGlobalOperators() 36 } 37 38 // RegisterDefaultCopiers registers the ValueCopier list into 39 // default copiers registry. 40 // 41 // It takes effects on DefaultCopyController, MakeClone, DeepCopy, 42 // and New, .... 43 func RegisterDefaultCopiers(ss ...ValueCopier) { 44 defValueCopiers = append(defValueCopiers, ss...) 45 initGlobalOperators() 46 } 47 48 func initConverters() { 49 dbglog.Log("initializing default converters and copiers ...") 50 defValueConverters = ValueConverters{ // Transform() 51 &fromStringConverter{}, // the final choice here 52 &toStringConverter{}, 53 54 // &toFuncConverter{}, 55 &fromFuncConverter{}, 56 57 &toDurationConverter{}, 58 &fromDurationConverter{}, 59 &toTimeConverter{}, 60 &fromTimeConverter{}, 61 62 &fromBytesBufferConverter{}, 63 &fromSyncPkgConverter{}, 64 &fromMapConverter{}, 65 } 66 defValueCopiers = ValueCopiers{ // CopyTo() 67 &fromStringConverter{}, // the final choice here 68 &toStringConverter{}, 69 70 &toFuncConverter{}, 71 &fromFuncConverter{}, 72 73 &toDurationConverter{}, 74 &fromDurationConverter{}, 75 &toTimeConverter{}, 76 &fromTimeConverter{}, 77 78 &fromBytesBufferConverter{}, 79 &fromSyncPkgConverter{}, 80 &fromMapConverter{}, 81 } 82 83 lenValueConverters = len(defValueConverters) 84 lenValueCopiers = len(defValueCopiers) 85 } 86 87 var defValueConverters ValueConverters //nolint:gochecknoglobals //i know that 88 var defValueCopiers ValueCopiers //nolint:gochecknoglobals //i know that 89 var lenValueConverters, lenValueCopiers int //nolint:gochecknoglobals //i know that 90 91 func defaultValueConverters() ValueConverters { return defValueConverters } 92 func defaultValueCopiers() ValueCopiers { return defValueCopiers } 93 94 // ValueConverter for internal used. 95 type ValueConverter interface { 96 Transform(ctx *ValueConverterContext, source reflect.Value, targetType reflect.Type) (target reflect.Value, err error) 97 Match(params *Params, source, target reflect.Type) (ctx *ValueConverterContext, yes bool) 98 } 99 100 // ValueCopier for internal used. 101 type ValueCopier interface { 102 CopyTo(ctx *ValueConverterContext, source, target reflect.Value) (err error) 103 Match(params *Params, source, target reflect.Type) (ctx *ValueConverterContext, yes bool) 104 } 105 106 // NameConverter for internal used. 107 type NameConverter interface { 108 ToGoName(ctx *NameConverterContext, fieldName string) (goName string) 109 ToFieldName(ctx *NameConverterContext, goName string) (fieldName string) 110 } 111 112 // ValueConverters for internal used. 113 type ValueConverters []ValueConverter 114 115 // ValueCopiers for internal used. 116 type ValueCopiers []ValueCopier 117 118 // NameConverters for internal used. 119 type NameConverters []NameConverter 120 121 // NameConverterContext for internal used. 122 type NameConverterContext struct { 123 *Params 124 } 125 126 // ValueConverterContext for internal used. 127 type ValueConverterContext struct { 128 *Params 129 } 130 131 // 132 133 //nolint:lll //no why 134 func (valueConverters ValueConverters) findConverters(params *Params, from, to reflect.Type, userDefinedOnly bool) (converter ValueConverter, ctx *ValueConverterContext) { 135 var yes bool 136 var min int 137 if userDefinedOnly { 138 min = lenValueConverters 139 } 140 for i := len(valueConverters) - 1; i >= min; i-- { 141 // FILO: the last added converter has the first priority 142 cvt := valueConverters[i] 143 if cvt != nil { 144 if ctx, yes = cvt.Match(params, from, to); yes { 145 converter = cvt 146 break 147 } 148 } 149 } 150 return 151 } 152 153 //nolint:lll //no why 154 func (valueCopiers ValueCopiers) findCopiers(params *Params, from, to reflect.Type, userDefinedOnly bool) (copier ValueCopier, ctx *ValueConverterContext) { 155 var yes bool 156 var min int 157 if userDefinedOnly { 158 min = lenValueCopiers 159 } 160 for i := len(valueCopiers) - 1; i >= min; i-- { 161 // FILO: the last added converter has the first priority 162 cpr := valueCopiers[i] 163 if cpr != nil { 164 if ctx, yes = cpr.Match(params, from, to); yes { 165 copier = cpr 166 break 167 } 168 } 169 } 170 return 171 } 172 173 // 174 175 // IsCopyFunctionResultToTarget does SAFELY test if copyFunctionResultToTarget is true or not. 176 func (ctx *ValueConverterContext) IsCopyFunctionResultToTarget() bool { 177 if ctx == nil || ctx.Params == nil || ctx.controller == nil { 178 return false 179 } 180 return ctx.controller.copyFunctionResultToTarget 181 } 182 183 // IsPassSourceToTargetFunction does SAFELY test if passSourceAsFunctionInArgs is true or not. 184 func (ctx *ValueConverterContext) IsPassSourceToTargetFunction() bool { 185 if ctx == nil || ctx.Params == nil || ctx.controller == nil { 186 return false 187 } 188 return ctx.controller.passSourceAsFunctionInArgs 189 } 190 191 // Preprocess find out a converter to transform source to target. 192 // If no comfortable converter found, the return processed is false. 193 // 194 //nolint:lll //no why 195 func (ctx *ValueConverterContext) Preprocess(source reflect.Value, targetType reflect.Type, cvtOuter ValueConverter) (processed bool, target reflect.Value, err error) { 196 if ctx != nil && ctx.Params != nil && ctx.Params.controller != nil { 197 sourceType := source.Type() 198 if cvt, ctxCvt := ctx.controller.valueConverters.findConverters(ctx.Params, sourceType, targetType, false); cvt != nil && cvt != cvtOuter { 199 target, err = cvt.Transform(ctxCvt, source, targetType) 200 processed = true 201 return 202 } 203 } 204 return 205 } 206 207 //nolint:unused //future 208 func (ctx *ValueConverterContext) isStruct() bool { 209 if ctx == nil { 210 return false 211 } 212 return ctx.Params.isStruct() 213 } 214 215 //nolint:unused //future 216 func (ctx *ValueConverterContext) isFlagExists(ftf cms.CopyMergeStrategy) (ret bool) { 217 if ctx == nil { 218 return 219 } 220 return ctx.Params.isFlagExists(ftf) 221 } 222 223 // isGroupedFlagOK tests if the given flag is exists or valid. 224 // 225 // Different with isGroupedFlagOKDeeply is, isGroupedFlagOK will return 226 // false simply while Params.fieldTags is empty or unset. 227 // 228 // When Params.fieldTags is valid, the actual testing will be forwarded 229 // to Params.fieldTags.flags.isGroupedFlagOK(). 230 func (ctx *ValueConverterContext) isGroupedFlagOK(ftf ...cms.CopyMergeStrategy) (ret bool) { //nolint:unused //future 231 if ctx == nil { 232 return flags.New().IsGroupedFlagOK(ftf...) 233 } 234 return ctx.Params.isGroupedFlagOK(ftf...) 235 } 236 237 // isGroupedFlagOKDeeply tests if the given flag is exists or valid. 238 // 239 // Different with isGroupedFlagOK is, isGroupedFlagOKDeeply will check 240 // whether the given flag is a leader (i.e. default choice) in a group 241 // or not, even if Params.fieldTags is empty or unset. 242 // 243 // When Params.fieldTags is valid, the actual testing will be forwarded 244 // to Params.fieldTags.flags.isGroupedFlagOK(). 245 func (ctx *ValueConverterContext) isGroupedFlagOKDeeply(ftf ...cms.CopyMergeStrategy) (ret bool) { 246 if ctx == nil { 247 return flags.New().IsGroupedFlagOK(ftf...) 248 } 249 return ctx.Params.isGroupedFlagOKDeeply(ftf...) 250 } 251 252 //nolint:unused //future 253 func (ctx *ValueConverterContext) isAnyFlagsOK(ftf ...cms.CopyMergeStrategy) (ret bool) { 254 if ctx == nil { 255 return flags.New().IsAnyFlagsOK(ftf...) 256 } 257 return ctx.Params.isAnyFlagsOK(ftf...) 258 } 259 260 //nolint:unused //future 261 func (ctx *ValueConverterContext) isAllFlagsOK(ftf ...cms.CopyMergeStrategy) (ret bool) { 262 if ctx == nil { 263 return flags.New().IsAllFlagsOK(ftf...) 264 } 265 return ctx.Params.isAllFlagsOK(ftf...) 266 } 267 268 // 269 270 // 271 272 // 273 274 type cvtbase struct{} 275 276 func (c *cvtbase) safeType(tgt, tgtptr reflect.Value) reflect.Type { 277 if tgt.IsValid() { 278 return tgt.Type() 279 } 280 if tgtptr.IsValid() { 281 if tgtptr.Kind() == reflect.Interface { 282 return tgtptr.Type() 283 } 284 return tgtptr.Type().Elem() 285 } 286 log.Panicf("niltyp !! CANNOT fetch type: tgt = %v, tgtptr = %v", tool.Typfmtv(&tgt), tool.Typfmtv(&tgtptr)) 287 return tool.Niltyp 288 } 289 290 // processUnexportedField try to set newval into target if it's an unexported field. 291 func (c *cvtbase) processUnexportedField(ctx *ValueConverterContext, target, newval reflect.Value) (processed bool) { 292 if ctx == nil || ctx.Params == nil { 293 return 294 } 295 processed = ctx.Params.processUnexportedField(target, newval) 296 return 297 } 298 299 //nolint:lll //no why 300 func (c *cvtbase) checkSource(ctx *ValueConverterContext, source reflect.Value, targetType reflect.Type) (target reflect.Value, processed bool) { 301 if ctx == nil { 302 return 303 } 304 305 if processed = ctx.isGroupedFlagOKDeeply(cms.Ignore); processed { 306 return 307 } 308 if processed = tool.IsNil(source) && ctx.isGroupedFlagOKDeeply(cms.OmitIfNil, cms.OmitIfEmpty); processed { 309 target = reflect.Zero(targetType) 310 return 311 } 312 if processed = tool.IsZero(source) && ctx.isGroupedFlagOKDeeply(cms.OmitIfZero, cms.OmitIfEmpty); processed { 313 target = reflect.Zero(targetType) 314 } 315 return 316 } 317 318 //nolint:lll //no why 319 func (c *cvtbase) checkTarget(ctx *ValueConverterContext, target reflect.Value, targetType reflect.Type) (processed bool) { 320 if processed = !target.IsValid(); processed { 321 return 322 } 323 if processed = tool.IsNil(target) && ctx.isGroupedFlagOKDeeply(cms.OmitIfTargetNil); processed { 324 return 325 } 326 processed = tool.IsZero(target) && ctx.isGroupedFlagOKDeeply(cms.OmitIfTargetZero) 327 return 328 } 329 330 // 331 332 type toConverterBase struct{ cvtbase } 333 334 func (c *toConverterBase) fallback(target reflect.Value) (err error) { 335 tgtType := reflect.TypeOf((*time.Duration)(nil)).Elem() 336 tool.Rindirect(target).Set(reflect.Zero(tgtType)) 337 return 338 } 339 340 // 341 342 type fromConverterBase struct{ cvtbase } 343 344 func (c *fromConverterBase) CopyTo(ctx *ValueConverterContext, source, target reflect.Value) (err error) { 345 panic("not impl") 346 } 347 348 func (c *fromConverterBase) Transform(ctx *ValueConverterContext, 349 source reflect.Value, targetType reflect.Type) (target reflect.Value, err error) { 350 panic("not impl") 351 } 352 353 func (c *fromConverterBase) Match(params *Params, source, target reflect.Type) (ctx *ValueConverterContext, yes bool) { 354 panic("not impl") 355 } 356 357 //nolint:unused,lll //future 358 func (c *fromConverterBase) preprocess(ctx *ValueConverterContext, source reflect.Value, targetType reflect.Type) (processed bool, target reflect.Value, err error) { 359 if !(ctx != nil && ctx.Params != nil && ctx.Params.controller != nil) { 360 return 361 } 362 363 sourceType := source.Type() 364 if cvt, ctxCvt := ctx.controller.valueConverters.findConverters(ctx.Params, sourceType, targetType, false); cvt != nil { 365 if cvt == c { 366 return 367 } 368 if cc, ok := cvt.(*fromConverterBase); ok && cc == c { 369 return 370 } 371 372 target, err = cvt.Transform(ctxCvt, source, targetType) 373 processed = true 374 return 375 } 376 return 377 } 378 379 func (c *fromConverterBase) postCopyTo(ctx *ValueConverterContext, source, target reflect.Value) (err error) { 380 // if source.IsValid() { 381 // if canConvert(&source, target.Type()) { 382 // nv := source.Convert(target.Type()) 383 // target.Set(nv) 384 // return 385 // //} else { 386 // // nv := fmt.Sprintf("%v", source.Interface()) 387 // // target.Set(reflect.ValueOf(nv)) 388 // } 389 // } 390 // 391 // target = reflect.Zero(target.Type()) 392 // return 393 var nv reflect.Value 394 nv, err = c.convertToOrZeroTarget(ctx, source, target.Type()) 395 if err == nil { 396 if target.CanSet() { 397 dbglog.Log(" postCopyTo: set nv(%v) into target (%v)", tool.Valfmt(&nv), tool.Valfmt(&target)) 398 target.Set(nv) 399 } else { 400 err = ErrCannotSet.FormatWith(tool.Valfmt(&target), tool.Typfmtv(&target), tool.Valfmt(&nv), tool.Typfmtv(&nv)) 401 } 402 } 403 return 404 } 405 406 func (c *fromConverterBase) convertToOrZeroTarget(ctx *ValueConverterContext, 407 source reflect.Value, targetType reflect.Type) (target reflect.Value, err error) { 408 if tool.CanConvert(&source, targetType) { 409 nv := source.Convert(targetType) 410 target = nv 411 } else if ctx.isGroupedFlagOKDeeply(cms.ClearIfInvalid) { 412 target = reflect.Zero(targetType) 413 } 414 return 415 } 416 417 // 418 419 // 420 421 // 422 423 type toStringConverter struct{ toConverterBase } 424 425 func (c *toStringConverter) postCopyTo(ctx *ValueConverterContext, source, target reflect.Value) (err error) { 426 if source.IsValid() { 427 if tool.CanConvert(&source, target.Type()) { 428 nv := source.Convert(target.Type()) 429 if c.processUnexportedField(ctx, target, nv) { 430 return 431 } 432 target.Set(nv) 433 return 434 } 435 436 newVal := fmt.Sprintf("%v", source.Interface()) 437 nv := reflect.ValueOf(newVal) 438 if c.processUnexportedField(ctx, target, nv) { 439 return 440 } 441 target.Set(nv) 442 return 443 } 444 445 // target = reflect.Zero(target.Type()) 446 return //nolint:nakedret //i do 447 } 448 449 func (c *toStringConverter) CopyTo(ctx *ValueConverterContext, source, target reflect.Value) (err error) { 450 tgt, tgtptr := tool.Rdecode(target) 451 tgtType := c.safeType(tgt, tgtptr) // because tgt might be invalid, so we fetch tgt type via its pointer 452 dbglog.Log(" target: %v (%v), tgtptr: %v, tgt: %v, tgttyp: %v", 453 tool.Typfmtv(&target), tool.Typfmt(target.Type()), tool.Typfmtv(&tgtptr), 454 tool.Typfmtv(&tgt), tool.Typfmt(tgtType)) 455 456 if processed := c.checkTarget(ctx, tgt, tgtType); processed { 457 return 458 } 459 460 if ret, e := c.Transform(ctx, source, tgtType); e == nil { 461 if c.processUnexportedField(ctx, target, ret) { 462 return 463 } 464 dbglog.Log(" set: %v (%v) <- %v", tool.Valfmt(&target), tool.Typfmtv(&target), tool.Valfmt(&ret)) 465 tgtptr.Set(ret) 466 } else { 467 err = c.postCopyTo(ctx, source, target) 468 } 469 return 470 } 471 472 // Transform will transform source type (bool, int, ...) to target string. 473 func (c *toStringConverter) Transform(ctx *ValueConverterContext, source reflect.Value, 474 targetType reflect.Type) (target reflect.Value, err error) { 475 if source.IsValid() { 476 // var processed bool 477 // if processed, target, err = ctx.Preprocess(source, targetType, c); processed { 478 // return 479 // } 480 481 var processed bool 482 if target, processed = c.checkSource(ctx, source, targetType); processed { 483 return 484 } 485 486 var str string 487 if str, processed, err = tryMarshalling(source); processed { 488 if err == nil { 489 target = reflect.ValueOf(str) 490 } 491 return 492 } 493 494 target, err = rToString(source, targetType) 495 return 496 } 497 498 if ctx == nil || ctx.isGroupedFlagOKDeeply(cms.ClearIfInvalid) { 499 target = reflect.Zero(reflect.TypeOf((*string)(nil)).Elem()) 500 } 501 return 502 } 503 504 func (c *toStringConverter) Match(params *Params, source, target reflect.Type) (ctx *ValueConverterContext, yes bool) { 505 if yes = target.Kind() == reflect.String; yes { 506 ctx = &ValueConverterContext{params} 507 } 508 return 509 } 510 511 // 512 513 var marshallableTypes = map[string]reflect.Type{ //nolint:gochecknoglobals //no 514 // "MarshalBinary": reflect.TypeOf((*encoding.BinaryMarshaler)(nil)).Elem(), 515 "MarshalText": reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem(), 516 "MarshalJSON": reflect.TypeOf((*json.Marshaler)(nil)).Elem(), 517 } 518 519 var textMarshaller = TextMarshaller(func(v interface{}) ([]byte, error) { //nolint:gochecknoglobals //no 520 return json.MarshalIndent(v, "", " ") 521 }) 522 523 func canMarshalling(source reflect.Value) (mtd reflect.Value, yes bool) { 524 st := source.Type() 525 for fnn, t := range marshallableTypes { 526 if st.Implements(t) { 527 yes, mtd = true, source.MethodByName(fnn) 528 break 529 } 530 } 531 return 532 } 533 534 // FallbackToBuiltinStringMarshalling exposes the builtin string 535 // marshalling mechanism for your customized ValueConverter or 536 // ValueCopier. 537 func FallbackToBuiltinStringMarshalling(source reflect.Value) (str string, err error) { 538 return doMarshalling(source) 539 } 540 541 func doMarshalling(source reflect.Value) (str string, err error) { 542 var data []byte 543 if mtd, yes := canMarshalling(source); yes { 544 ret := mtd.Call(nil) 545 if err, yes = (ret[1].Interface()).(error); err == nil && yes { 546 data = ret[0].Interface().([]byte) //nolint:errcheck //no need 547 } 548 } else { 549 data, err = textMarshaller(source.Interface()) 550 } 551 if err == nil { 552 str = string(data) 553 } 554 return 555 } 556 557 func tryMarshalling(source reflect.Value) (str string, processed bool, err error) { 558 var data []byte 559 var mtd reflect.Value 560 if mtd, processed = canMarshalling(source); processed { 561 ret := mtd.Call(nil) 562 if err, _ = (ret[1].Interface()).(error); err == nil { 563 data = ret[0].Interface().([]byte) //nolint:errcheck //no need 564 } 565 } 566 if err == nil { 567 str = string(data) 568 } 569 return 570 } 571 572 // 573 574 type fromStringConverter struct{ fromConverterBase } 575 576 func (c *fromStringConverter) CopyTo(ctx *ValueConverterContext, source, target reflect.Value) (err error) { 577 tgt, tgtptr := tool.Rdecode(target) 578 tgttyp := c.safeType(tgt, tgtptr) // because tgt might be invalid, so we fetch tgt type via its pointer 579 dbglog.Log(" target: %v (%v), tgtptr: %v, tgt: %v, tgttyp: %v", 580 tool.Typfmtv(&target), tool.Typfmt(target.Type()), tool.Typfmtv(&tgtptr), 581 tool.Typfmtv(&tgt), tool.Typfmt(tgttyp)) 582 583 if processed := c.checkTarget(ctx, tgt, tgttyp); processed { 584 // target.Set(ret) 585 return 586 } 587 588 var ret reflect.Value 589 var e error 590 if ret, e = c.Transform(ctx, source, tgttyp); e == nil { 591 if tgtptr.Kind() == reflect.Interface { //nolint:gocritic // no need to switch to 'switch' clause 592 tgtptr.Set(ret) 593 } else if tgtptr.Kind() == reflect.Ptr { 594 tgtptr.Elem().Set(ret) 595 } else if tgt.CanSet() { 596 tgt.Set(ret) 597 } else { 598 err = ErrCannotSet.FormatWith(tool.Valfmt(&tgt), tool.Typfmtv(&tgt), tool.Valfmt(&ret), tool.Typfmtv(&ret)) 599 } 600 dbglog.Log(" tgt / ret transformed: %v / %v", tool.Valfmt(&tgt), tool.Valfmt(&ret)) 601 return 602 } 603 604 if !errors.IsAnyOf(e, strconv.ErrSyntax, strconv.ErrRange) { 605 dbglog.Log(" Transform() failed: %v", e) 606 dbglog.Log(" try running postCopyTo()") 607 err = c.postCopyTo(ctx, source, target) 608 } 609 return 610 } 611 612 // Transform will transform source string to target type (bool, int, ...) 613 func (c *fromStringConverter) Transform(ctx *ValueConverterContext, source reflect.Value, targetType reflect.Type) (target reflect.Value, err error) { 614 if !source.IsValid() { 615 target, err = c.convertToOrZeroTarget(ctx, source, targetType) 616 return 617 } 618 619 // var processed bool 620 // if processed, target, err = c.preprocess(ctx, source, targetType); processed { 621 // return 622 // } 623 624 var processed bool 625 if target, processed = c.checkSource(ctx, source, targetType); processed { 626 return 627 } 628 629 switch k := targetType.Kind(); k { //nolint:exhaustive //no need 630 case reflect.Bool: 631 target = rToBool(source) 632 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 633 target, err = rToInteger(source, targetType) 634 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 635 target, err = rToUInteger(source, targetType) 636 637 case reflect.Uintptr: 638 target = rToUIntegerHex(source, targetType) 639 // case reflect.UnsafePointer: 640 // // target = rToUIntegerHex(source, targetType) 641 // err = errors.InvalidArgument 642 // case reflect.Ptr: 643 // //target = rToUIntegerHex(source, targetType) 644 // err = errors.InvalidArgument 645 646 case reflect.Float32, reflect.Float64: 647 target, err = rToFloat(source, targetType) 648 case reflect.Complex64, reflect.Complex128: 649 target, err = rToComplex(source, targetType) 650 651 case reflect.String: 652 target = source 653 654 // reflect.Array 655 // reflect.Chan 656 // reflect.Func 657 // reflect.Interface 658 // reflect.Map 659 // reflect.Slice 660 // reflect.Struct 661 662 default: 663 target, err = c.convertToOrZeroTarget(ctx, source, targetType) 664 } 665 return 666 } 667 668 //nolint:lll //keep it 669 func (c *fromStringConverter) Match(params *Params, source, target reflect.Type) (ctx *ValueConverterContext, yes bool) { 670 if yes = source.Kind() == reflect.String; yes { 671 ctx = &ValueConverterContext{params} 672 } 673 return 674 } 675 676 // 677 678 // 679 680 // 681 682 // fromMapConverter transforms a map to other types (esp string, slice, struct). 683 type fromMapConverter struct{ fromConverterBase } 684 685 func (c *fromMapConverter) CopyTo(ctx *ValueConverterContext, source, target reflect.Value) (err error) { 686 tgt, tgtptr := tool.Rdecode(target) 687 tgttyp := c.safeType(tgt, tgtptr) // because tgt might be invalid, so we fetch tgt type via its pointer 688 dbglog.Log(" target: %v (%v), tgtptr: %v, tgt: %v, tgttyp: %v", 689 tool.Typfmtv(&target), tool.Typfmt(target.Type()), tool.Typfmtv(&tgtptr), 690 tool.Typfmtv(&tgt), tool.Typfmt(tgttyp)) 691 692 if processed := c.checkTarget(ctx, tgt, tgttyp); processed { 693 // target.Set(ret) 694 return 695 } 696 697 if ctx.controller.targetSetter != nil { 698 if tgttyp.Kind() == reflect.Struct { 699 // DON'T get into c.Transform(), because Transform will modify 700 // a temporary new instance and return it to caller, and 701 // the new instance will be set to 'target'. 702 // When target setter is valid, we assume the setter will 703 // modify the real target directly rather than on a temporary 704 // object. 705 err = c.toStructDirectly(ctx, source, target, tgttyp) 706 return 707 } 708 } 709 710 if ret, e := c.Transform(ctx, source, tgttyp); e == nil { //nolint:nestif //keep it 711 if k := tgtptr.Kind(); k == reflect.Interface { //nolint:gocritic // no need to switch to 'switch' clause 712 tgtptr.Set(ret) 713 } else if k == reflect.Ptr { 714 tgtptr.Elem().Set(ret) 715 // } else if tool.IsZero(tgt) { 716 } else if tgt.CanSet() { 717 tgt.Set(ret) 718 } else { 719 err = ErrCannotSet.FormatWith(tool.Valfmt(&tgt), tool.Typfmtv(&tgt), tool.Valfmt(&ret), tool.Typfmtv(&ret)) 720 } 721 dbglog.Log(" tgt: %v (ret = %v)", tool.Valfmt(&tgt), tool.Valfmt(&ret)) 722 } else if !errors.Is(e, strconv.ErrSyntax) && !errors.Is(e, strconv.ErrRange) { 723 dbglog.Log(" Transform() failed: %v", e) 724 dbglog.Log(" try running postCopyTo()") 725 err = c.postCopyTo(ctx, source, target) 726 } 727 return 728 } 729 730 // Transform will transform source string to target type (bool, int, ...) 731 // 732 //nolint:lll //keep it 733 func (c *fromMapConverter) Transform(ctx *ValueConverterContext, source reflect.Value, targetType reflect.Type) (target reflect.Value, err error) { 734 if source.IsValid() { 735 var processed bool 736 if target, processed = c.checkSource(ctx, source, targetType); processed { 737 return 738 } 739 740 switch k := targetType.Kind(); k { //nolint:exhaustive //no need 741 case reflect.String: 742 var str string 743 if str, err = doMarshalling(source); err == nil { 744 target = reflect.ValueOf(str) 745 } 746 747 case reflect.Struct: 748 target, err = c.toStruct(ctx, source, targetType) 749 750 // case reflect.Slice: 751 // case reflect.Array: 752 753 default: 754 target, err = c.convertToOrZeroTarget(ctx, source, targetType) 755 } 756 } else { 757 target, err = c.convertToOrZeroTarget(ctx, source, targetType) 758 } 759 return 760 } 761 762 //nolint:lll,gocognit //keep it 763 func (c *fromMapConverter) toStructDirectly(ctx *ValueConverterContext, source, target reflect.Value, targetType reflect.Type) (err error) { 764 cc := ctx.controller 765 766 preSetter := func(value reflect.Value, names ...string) (processed bool, err error) { 767 if cc.targetSetter != nil { 768 if err = cc.targetSetter(&value, names...); err == nil { 769 processed = true 770 } else { 771 if err != ErrShouldFallback { //nolint:errorlint //want it exactly 772 return // has error 773 } 774 err, processed = nil, false 775 } 776 } 777 return 778 } 779 780 var ec = errors.New("map -> struct errors") 781 defer ec.Defer(&err) 782 783 keys := source.MapKeys() 784 for _, key := range keys { 785 src := source.MapIndex(key) 786 st := src.Kind() 787 if st == reflect.Interface { 788 src = src.Elem() 789 } 790 791 // convert map key to string type 792 key, err = rToString(key, tool.StringType) 793 if err != nil { 794 continue // ignore non-string key 795 } 796 ks := key.String() 797 dbglog.Log(" key %q, src: %v (%v)", ks, tool.Valfmt(&src), tool.Typfmtv(&src)) 798 799 if cc.targetSetter != nil { 800 newtyp := src.Type() 801 val := reflect.New(newtyp).Elem() 802 err = ctx.controller.copyTo(ctx.Params, src, val) 803 dbglog.Log(" nv.%q: %v (%v) ", ks, tool.Valfmt(&val), tool.Typfmtv(&val)) 804 var processed bool 805 if processed, err = preSetter(val, ks); err != nil || processed { 806 ec.Attach(err) 807 continue 808 } 809 } 810 } 811 return 812 } 813 814 //nolint:lll,gocognit //keep it 815 func (c *fromMapConverter) toStruct(ctx *ValueConverterContext, source reflect.Value, targetType reflect.Type) (target reflect.Value, err error) { 816 cc := ctx.controller 817 818 preSetter := func(value reflect.Value, names ...string) (processed bool, err error) { 819 if cc.targetSetter != nil { 820 if err = cc.targetSetter(&value, names...); err == nil { 821 processed = true 822 } else { 823 if err != ErrShouldFallback { //nolint:errorlint //want it exactly 824 return // has error 825 } 826 err, processed = nil, false 827 } 828 } 829 return 830 } 831 832 var ec = errors.New("map -> struct errors") 833 defer ec.Defer(&err) 834 835 target = reflect.New(targetType).Elem() 836 keys := source.MapKeys() 837 for _, key := range keys { 838 src := source.MapIndex(key) 839 st := src.Kind() 840 if st == reflect.Interface { 841 src = src.Elem() 842 } 843 844 // convert map key to string type 845 key, err = rToString(key, tool.StringType) 846 if err != nil { 847 continue // ignore non-string key 848 } 849 ks := key.String() 850 dbglog.Log(" key %q, src: %v (%v)", ks, tool.Valfmt(&src), tool.Typfmtv(&src)) 851 852 if cc.targetSetter != nil { 853 newtyp := src.Type() 854 val := reflect.New(newtyp).Elem() 855 err = ctx.controller.copyTo(ctx.Params, src, val) 856 dbglog.Log(" nv.%q: %v (%v) ", ks, tool.Valfmt(&val), tool.Typfmtv(&val)) 857 var processed bool 858 if processed, err = preSetter(val, ks); err != nil || processed { 859 ec.Attach(err) 860 continue 861 } 862 } 863 864 // use the key.(string) as the target struct field name 865 tsf, ok := targetType.FieldByName(ks) 866 if !ok { 867 continue 868 } 869 870 fld := target.FieldByName(ks) 871 // dbglog.Log(" fld %q: ", ks) 872 tsft := tsf.Type 873 tsfk := tsft.Kind() 874 if tsfk == reflect.Interface { 875 // tsft = tsft.Elem() 876 fld = fld.Elem() 877 } else if tsfk == reflect.Ptr { 878 dbglog.Log(" fld.%q: %v (%v)", ks, tool.Valfmt(&fld), tool.Typfmtv(&fld)) 879 if fld.IsNil() { 880 n := reflect.New(fld.Type().Elem()) 881 target.FieldByName(ks).Set(n) 882 fld = target.FieldByName(ks) 883 } 884 // tsft = tsft.Elem() 885 fld = fld.Elem() 886 dbglog.Log(" fld.%q: %v (%v)", ks, tool.Valfmt(&fld), tool.Typfmtv(&fld)) 887 } 888 889 err = ctx.controller.copyTo(ctx.Params, src, fld) 890 dbglog.Log(" nv.%q: %v (%v) ", ks, tool.Valfmt(&fld), tool.Typfmtv(&fld)) 891 ec.Attach(err) 892 893 // var nv reflect.Value 894 // nv, err = c.fromConverterBase.convertToOrZeroTarget(ctx, src, tsft) 895 // dbglog.Log(" nv.%q: %v (%v) ", ks, valfmt(&nv), typfmtv(&nv)) 896 // if err == nil { 897 // if fld.CanSet() { 898 // if tsfk == reflect.Ptr { 899 // n := reflect.New(fld.Type().Elem()) 900 // n.Elem().Set(nv) 901 // nv = n 902 // } 903 // fld.Set(nv) 904 // } else { 905 // err = ErrCannotSet.FormatWith(valfmt(&fld), typfmtv(&fld), valfmt(&nv), typfmtv(&nv)) 906 // } 907 // } 908 } 909 dbglog.Log(" target: %v (%v) ", tool.Valfmt(&target), tool.Typfmtv(&target)) 910 return 911 } 912 913 func (c *fromMapConverter) Match(params *Params, source, target reflect.Type) (ctx *ValueConverterContext, yes bool) { 914 if yes = source.Kind() == reflect.Map && target.Kind() != reflect.Map; yes { 915 ctx = &ValueConverterContext{params} 916 } 917 return 918 } 919 920 // 921 922 // 923 924 // 925 926 // fromSyncPkgConverter provides default actions for all entities 927 // in sync package, such as sync.Pool, sync.RWMutex, and so on. 928 // 929 // By default, these entities should NOT be copied from one to another 930 // one. So our default actions are empty. 931 type fromSyncPkgConverter struct{ fromConverterBase } 932 933 //nolint:lll //keep it 934 func (c *fromSyncPkgConverter) Match(params *Params, source, target reflect.Type) (ctx *ValueConverterContext, yes bool) { 935 // st.PkgPath() . st.Name() 936 if yes = source.Kind() == reflect.Struct && strings.HasPrefix(source.String(), "sync."); yes { 937 ctx = &ValueConverterContext{params} 938 dbglog.Log(" src: %v, tgt: %v | Matched", source, target) 939 } else { 940 // dbglog.Log(" src: %v, tgt: %v", source, target) 941 } 942 return 943 } 944 func (c *fromSyncPkgConverter) CopyTo(ctx *ValueConverterContext, source, target reflect.Value) (err error) { 945 return 946 } 947 948 func (c *fromSyncPkgConverter) Transform(ctx *ValueConverterContext, source reflect.Value, targetType reflect.Type) (target reflect.Value, err error) { 949 return 950 } 951 952 // 953 954 type fromBytesBufferConverter struct{ fromConverterBase } 955 956 func (c *fromBytesBufferConverter) CopyTo(ctx *ValueConverterContext, source, target reflect.Value) (err error) { 957 tgt, tgtptr := tool.Rdecode(target) 958 tgtType := c.safeType(tgt, tgtptr) // because tgt might be invalid, so we fetch tgt type via its pointer 959 // tgtType := target.Type() 960 dbglog.Log(" target: %v (%v), tgtptr: %v, tgt: %v, tgttyp: %v", 961 tool.Typfmtv(&target), tool.Typfmt(target.Type()), 962 tool.Typfmtv(&tgtptr), tool.Typfmtv(&tgt), tool.Typfmt(tgtType)) 963 964 if processed := c.checkTarget(ctx, tgt, tgtType); processed { 965 // target.Set(ret) 966 return 967 } 968 969 from := source.Interface().(bytes.Buffer) //nolint:errcheck //no need 970 tv := tgtptr.Interface() 971 switch to := tv.(type) { 972 case bytes.Buffer: 973 to.Reset() 974 to.Write(from.Bytes()) 975 // dbglog.Log(" to: %v", to.String()) 976 case *bytes.Buffer: 977 to.Reset() 978 to.Write(from.Bytes()) 979 // dbglog.Log(" *to: %v", to.String()) 980 case *[]byte: 981 tgtptr.Elem().Set(reflect.ValueOf(from.Bytes())) 982 case []byte: 983 tgtptr.Elem().Set(reflect.ValueOf(from.Bytes())) 984 } 985 return 986 } 987 988 //nolint:lll //keep it 989 func (c *fromBytesBufferConverter) Transform(ctx *ValueConverterContext, source reflect.Value, targetType reflect.Type) (target reflect.Value, err error) { 990 var processed bool 991 if target, processed = c.checkSource(ctx, source, targetType); processed { 992 return 993 } 994 995 // TO/DO implement me 996 // panic("implement me") 997 from := source.Interface().(bytes.Buffer) //nolint:errcheck //no need 998 var to bytes.Buffer 999 _, err = to.Write(from.Bytes()) 1000 target = reflect.ValueOf(to) 1001 return 1002 } 1003 1004 //nolint:lll //keep it 1005 func (c *fromBytesBufferConverter) Match(params *Params, source, target reflect.Type) (ctx *ValueConverterContext, yes bool) { 1006 // st.PkgPath() . st.Name() 1007 if yes = source.Kind() == reflect.Struct && source.String() == "bytes.Buffer"; yes { 1008 ctx = &ValueConverterContext{params} 1009 dbglog.Log(" src: %v, tgt: %v | Matched", source, target) 1010 } else { 1011 // dbglog.Log(" src: %v, tgt: %v", source, target) 1012 } 1013 return 1014 } 1015 1016 // 1017 1018 // 1019 1020 // 1021 1022 type fromTimeConverter struct{ fromConverterBase } 1023 1024 func (c *fromTimeConverter) CopyTo(ctx *ValueConverterContext, source, target reflect.Value) (err error) { 1025 tgt, tgtptr := tool.Rdecode(target) 1026 tgtType := c.safeType(tgt, tgtptr) // because tgt might be invalid, so we fetch tgt type via its pointer 1027 dbglog.Log(" target: %v (%v), tgtptr: %v, tgt: %v, tgttyp: %v", 1028 tool.Typfmtv(&target), tool.Typfmt(target.Type()), tool.Typfmtv(&tgtptr), 1029 tool.Typfmtv(&tgt), tool.Typfmt(tgtType)) 1030 1031 if processed := c.checkTarget(ctx, tgt, tgtType); processed { 1032 // tgtptr.Set(ret) 1033 return 1034 } 1035 1036 var ret reflect.Value 1037 var e error 1038 if ret, e = c.Transform(ctx, source, tgtType); e == nil { 1039 if k := tgtptr.Kind(); k == reflect.Interface { //nolint:gocritic // no need to switch to 'switch' clause 1040 tgtptr.Set(ret) 1041 } else if k == reflect.Ptr { 1042 tgtptr.Elem().Set(ret) 1043 } else if tgt.CanSet() { 1044 tgt.Set(ret) 1045 } else { 1046 err = ErrCannotSet.FormatWith(tool.Valfmt(&tgt), tool.Typfmtv(&tgt), tool.Valfmt(&ret), tool.Typfmtv(&ret)) 1047 } 1048 dbglog.Log(" tgt: %v (ret = %v)", tool.Valfmt(&tgt), tool.Valfmt(&ret)) 1049 return 1050 } 1051 1052 dbglog.Log(" Transform() failed: %v", e) 1053 dbglog.Log(" trying to postCopyTo()") 1054 err = c.postCopyTo(ctx, source, target) 1055 return 1056 } 1057 1058 //nolint:lll //keep it 1059 func (c *fromTimeConverter) Transform(ctx *ValueConverterContext, source reflect.Value, targetType reflect.Type) (target reflect.Value, err error) { 1060 if source.IsValid() { 1061 var processed bool 1062 if target, processed = c.checkSource(ctx, source, targetType); processed { 1063 return 1064 } 1065 1066 switch k := targetType.Kind(); k { //nolint:exhaustive //no need 1067 case reflect.Bool: 1068 b := tool.IsNil(source) || tool.IsZero(source) 1069 target = reflect.ValueOf(b) 1070 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 1071 tm := source.Interface().(time.Time) //nolint:errcheck //no need 1072 t := reflect.ValueOf(tm.Unix()) 1073 target, err = rToInteger(t, targetType) 1074 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 1075 tm := source.Interface().(time.Time) //nolint:errcheck //no need 1076 t := reflect.ValueOf(tm.Unix()) 1077 target, err = rToUInteger(t, targetType) 1078 1079 case reflect.Float32, reflect.Float64: 1080 tm := source.Interface().(time.Time) //nolint:errcheck //no need 1081 f := float64(tm.UnixNano()) / 1e9 //nolint:gomnd //simple case 1082 t := reflect.ValueOf(f) 1083 target, err = rToFloat(t, targetType) 1084 case reflect.Complex64, reflect.Complex128: 1085 tm := source.Interface().(time.Time) //nolint:errcheck //no need 1086 f := float64(tm.UnixNano()) / 1e9 //nolint:gomnd //simple case 1087 t := reflect.ValueOf(f) 1088 target, err = rToComplex(t, targetType) 1089 1090 case reflect.String: 1091 tm := source.Interface().(time.Time) //nolint:errcheck //no need 1092 str := tm.Format(time.RFC3339) 1093 t := reflect.ValueOf(str) 1094 target, err = rToString(t, targetType) 1095 1096 default: 1097 target, err = c.convertToOrZeroTarget(ctx, source, targetType) 1098 } 1099 } else { 1100 target, err = c.convertToOrZeroTarget(ctx, source, targetType) 1101 } 1102 return 1103 } 1104 1105 func (c *fromTimeConverter) Match(params *Params, source, target reflect.Type) (ctx *ValueConverterContext, yes bool) { 1106 if sk := source.Kind(); sk == reflect.Struct { 1107 if yes = source.Name() == "Time" && source.PkgPath() == timeConstString; yes { 1108 ctx = &ValueConverterContext{params} 1109 } 1110 } 1111 return 1112 } 1113 1114 // 1115 1116 //nolint:gochecknoglobals //i know that 1117 var knownTimeLayouts = []string{ 1118 "2006-01-02 15:04:05.000000000", 1119 "2006-01-02 15:04:05.000000", 1120 "2006-01-02 15:04:05.000", 1121 "2006-01-02 15:04:05", 1122 "2006-01-02 15:04", 1123 "2006-01-02", 1124 1125 "2006-01-02 15:04:05.999999999Z07:00", 1126 "2006-01-02 15:04:05.999999999", 1127 "2006-01-02 15:04:05Z07:00", 1128 "2006-01-02 15:04:05", 1129 1130 time.RFC3339, 1131 1132 time.ANSIC, 1133 time.UnixDate, 1134 time.RubyDate, 1135 time.RFC822, 1136 time.RFC822Z, 1137 time.RFC850, 1138 time.RFC1123, 1139 time.RFC1123Z, 1140 time.RFC3339Nano, 1141 time.Kitchen, 1142 time.Stamp, 1143 time.StampMilli, 1144 time.StampMicro, 1145 time.StampNano, 1146 1147 "01/02/2006 15:04:05.000000000", 1148 "01/02/2006 15:04:05.000000", 1149 "01/02/2006 15:04:05.000", 1150 "01/02/2006 15:04:05", 1151 "01/02/2006 15:04", 1152 "01/02/2006", 1153 } 1154 1155 type toTimeConverter struct{ toConverterBase } 1156 1157 // func (c *toTimeConverter) fallback(target reflect.Value) (err error) { 1158 // var timeTimeTyp = reflect.TypeOf((*time.Time)(nil)).Elem() 1159 // rindirect(target).Set(reflect.Zero(timeTimeTyp)) 1160 // return 1161 // } 1162 1163 func (c *toTimeConverter) CopyTo(ctx *ValueConverterContext, source, target reflect.Value) (err error) { 1164 // tgtType := target.Type() 1165 tgt, tgtptr := tool.Rdecode(target) 1166 tgtType := c.safeType(tgt, tgtptr) // because tgt might be invalid, so we fetch tgt type via its pointer 1167 dbglog.Log(" target: %v (%v), tgtptr: %v, tgt: %v, tgttyp: %v", 1168 tool.Typfmtv(&target), tool.Typfmt(target.Type()), tool.Typfmtv(&tgtptr), 1169 tool.Typfmtv(&tgt), tool.Typfmt(tgtType)) 1170 1171 if processed := c.checkTarget(ctx, tgt, tgtType); processed { 1172 // target.Set(ret) 1173 return 1174 } 1175 1176 if ret, e := c.Transform(ctx, source, tgtType); e == nil { 1177 target.Set(ret) 1178 } else if ctx.isGroupedFlagOKDeeply(cms.ClearIfInvalid) { 1179 err = c.fallback(target) 1180 } 1181 return 1182 } 1183 1184 func tryParseTime(s string) (tm time.Time) { 1185 var err error 1186 for _, layout := range knownTimeLayouts { 1187 tm, err = time.Parse(layout, s) 1188 if err == nil { 1189 return 1190 } 1191 } 1192 return 1193 } 1194 1195 //nolint:lll //keep it 1196 func (c *toTimeConverter) Transform(ctx *ValueConverterContext, source reflect.Value, targetType reflect.Type) (target reflect.Value, err error) { 1197 if source.IsValid() { //nolint:gocritic // no need to switch to 'switch' clause 1198 var processed bool 1199 if target, processed = c.checkSource(ctx, source, targetType); processed { 1200 return 1201 } 1202 1203 switch k := source.Kind(); k { //nolint:exhaustive //no need 1204 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 1205 tm := time.Unix(source.Int(), 0) 1206 target = reflect.ValueOf(tm) 1207 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 1208 tm := time.Unix(int64(source.Uint()), 0) 1209 target = reflect.ValueOf(tm) 1210 1211 case reflect.Float32, reflect.Float64: 1212 sec, dec := math.Modf(source.Float()) 1213 tm := time.Unix(int64(sec), int64(dec*(1e9))) 1214 target = reflect.ValueOf(tm) 1215 case reflect.Complex64, reflect.Complex128: 1216 sec, dec := math.Modf(real(source.Complex())) 1217 tm := time.Unix(int64(sec), int64(dec*(1e9))) 1218 target = reflect.ValueOf(tm) 1219 1220 case reflect.String: 1221 tm := tryParseTime(source.String()) 1222 target = reflect.ValueOf(tm) 1223 1224 default: 1225 err = ErrCannotConvertTo.FormatWith(source, tool.Typfmtv(&source), targetType, targetType.Kind()) 1226 } 1227 } else if ctx.isGroupedFlagOKDeeply(cms.ClearIfInvalid) { 1228 target = reflect.Zero(targetType) 1229 } else { 1230 err = errors.New("source (%v) is invalid", tool.Valfmt(&source)) 1231 } 1232 return 1233 } 1234 1235 func (c *toTimeConverter) Match(params *Params, source, target reflect.Type) (ctx *ValueConverterContext, yes bool) { 1236 if tk := target.Kind(); tk == reflect.Struct { 1237 if yes = target.Name() == "Time" && target.PkgPath() == timeConstString; yes { 1238 ctx = &ValueConverterContext{params} 1239 } 1240 } 1241 return 1242 } 1243 1244 // 1245 1246 // 1247 1248 // 1249 1250 type fromDurationConverter struct{ fromConverterBase } 1251 1252 func (c *fromDurationConverter) CopyTo(ctx *ValueConverterContext, source, target reflect.Value) (err error) { 1253 tgt, tgtptr := tool.Rdecode(target) 1254 tgttyp := c.safeType(tgt, tgtptr) // because tgt might be invalid, so we fetch tgt type via its pointer 1255 dbglog.Log(" target: %v (%v), tgtptr: %v, tgt: %v, tgttyp: %v", 1256 tool.Typfmtv(&target), tool.Typfmt(target.Type()), tool.Typfmtv(&tgtptr), 1257 tool.Typfmtv(&tgt), tool.Typfmt(tgttyp)) 1258 1259 var processed bool 1260 if target, processed = c.checkSource(ctx, source, tgttyp); processed { 1261 return 1262 } 1263 1264 var ret reflect.Value 1265 var e error 1266 if ret, e = c.Transform(ctx, source, tgttyp); e == nil { 1267 if tgtptr.Kind() == reflect.Interface { //nolint:gocritic // no need to switch to 'switch' clause 1268 tgtptr.Set(ret) 1269 } else if tgtptr.Kind() == reflect.Ptr { 1270 tgtptr.Elem().Set(ret) 1271 } else if tgt.CanSet() { 1272 tgt.Set(ret) 1273 } else { 1274 err = ErrCannotSet.FormatWith(tool.Valfmt(&tgt), tool.Typfmtv(&tgt), tool.Valfmt(&ret), tool.Typfmtv(&ret)) 1275 } 1276 dbglog.Log(" tgt: %v (ret = %v)", tool.Valfmt(&tgt), tool.Valfmt(&ret)) 1277 return 1278 } 1279 1280 dbglog.Log(" Transform() failed: %v", e) 1281 dbglog.Log(" trying to postCopyTo()") 1282 err = c.postCopyTo(ctx, source, target) 1283 return 1284 } 1285 1286 //nolint:lll //keep it 1287 func (c *fromDurationConverter) Transform(ctx *ValueConverterContext, source reflect.Value, targetType reflect.Type) (target reflect.Value, err error) { 1288 if source.IsValid() { 1289 // var processed bool 1290 // if processed, target, err = c.preprocess(ctx, source, targetType); processed { 1291 // return 1292 // } 1293 1294 var processed bool 1295 if target, processed = c.checkSource(ctx, source, targetType); processed { 1296 return 1297 } 1298 1299 switch k := targetType.Kind(); k { //nolint:exhaustive //no need 1300 case reflect.Bool: 1301 target = rToBool(source) 1302 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 1303 target, err = rToInteger(source, targetType) 1304 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 1305 target, err = rToUInteger(source, targetType) 1306 1307 case reflect.Uintptr: 1308 target = rToUIntegerHex(source, targetType) 1309 // case reflect.UnsafePointer: 1310 // // target = rToUIntegerHex(source, targetType) 1311 // err = errors.InvalidArgument 1312 // case reflect.Ptr: 1313 // //target = rToUIntegerHex(source, targetType) 1314 // err = errors.InvalidArgument 1315 1316 case reflect.Float32, reflect.Float64: 1317 target, err = rToFloat(source, targetType) 1318 case reflect.Complex64, reflect.Complex128: 1319 target, err = rToComplex(source, targetType) 1320 1321 case reflect.String: 1322 target, err = rToString(source, targetType) 1323 1324 // reflect.Array 1325 // reflect.Chan 1326 // reflect.Func 1327 // reflect.Interface 1328 // reflect.Map 1329 // reflect.Slice 1330 // reflect.Struct 1331 1332 default: 1333 target, err = c.convertToOrZeroTarget(ctx, source, targetType) 1334 } 1335 } else { 1336 target, err = c.convertToOrZeroTarget(ctx, source, targetType) 1337 } 1338 return 1339 } 1340 1341 //nolint:lll //keep it 1342 func (c *fromDurationConverter) Match(params *Params, source, target reflect.Type) (ctx *ValueConverterContext, yes bool) { 1343 if sk := source.Kind(); sk == reflect.Int64 { 1344 if yes = source.Name() == "Duration" && source.PkgPath() == timeConstString; yes { 1345 ctx = &ValueConverterContext{params} 1346 } 1347 } 1348 return 1349 } 1350 1351 // 1352 1353 // 1354 1355 // 1356 1357 type toDurationConverter struct{ toConverterBase } 1358 1359 func (c *toDurationConverter) CopyTo(ctx *ValueConverterContext, source, target reflect.Value) (err error) { 1360 // tgtType := target.Type() 1361 tgt, tgtptr := tool.Rdecode(target) 1362 tgtType := c.safeType(tgt, tgtptr) // because tgt might be invalid, so we fetch tgt type via its pointer 1363 dbglog.Log(" target: %v (%v), tgtptr: %v, tgt: %v, tgttyp: %v", 1364 tool.Typfmtv(&target), tool.Typfmt(target.Type()), tool.Typfmtv(&tgtptr), 1365 tool.Typfmtv(&tgt), tool.Typfmt(tgtType)) 1366 1367 if processed := c.checkTarget(ctx, tgt, tgtType); processed { 1368 // tgtptr.Set(ret) 1369 return 1370 } 1371 1372 if ret, e := c.Transform(ctx, source, tgtType); e == nil { 1373 target.Set(ret) 1374 } else if ctx.isGroupedFlagOKDeeply(cms.ClearIfInvalid) { 1375 err = c.fallback(target) 1376 } 1377 return 1378 } 1379 1380 //nolint:lll //keep it 1381 func (c *toDurationConverter) Transform(ctx *ValueConverterContext, source reflect.Value, targetType reflect.Type) (target reflect.Value, err error) { 1382 if source.IsValid() { //nolint:nestif,gocritic // no need to switch to 'switch' clause 1383 var processed bool 1384 if target, processed = c.checkSource(ctx, source, targetType); processed { 1385 return 1386 } 1387 1388 switch k := source.Kind(); k { //nolint:exhaustive //no need 1389 case reflect.Bool: 1390 if source.Bool() { 1391 target = reflect.ValueOf(1 * time.Nanosecond) 1392 } else { 1393 target = reflect.ValueOf(0 * time.Second) 1394 } 1395 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 1396 target = reflect.ValueOf(time.Duration(source.Int())) 1397 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 1398 target = reflect.ValueOf(time.Duration(int64(source.Uint()))) 1399 1400 case reflect.Uintptr: 1401 target = reflect.ValueOf(time.Duration(int64(syscalls.UintptrToUint(source.Pointer())))) 1402 // case reflect.UnsafePointer: 1403 // // target = rToUIntegerHex(source, targetType) 1404 // err = errors.InvalidArgument 1405 // case reflect.Ptr: 1406 // //target = rToUIntegerHex(source, targetType) 1407 // err = errors.InvalidArgument 1408 1409 case reflect.Float32, reflect.Float64: 1410 target = reflect.ValueOf(time.Duration(int64(source.Float()))) 1411 case reflect.Complex64, reflect.Complex128: 1412 target = reflect.ValueOf(time.Duration(int64(real(source.Complex())))) 1413 1414 case reflect.String: 1415 var dur time.Duration 1416 dur, err = time.ParseDuration(source.String()) 1417 if err == nil { 1418 target = reflect.ValueOf(dur) 1419 } 1420 1421 // reflect.Array 1422 // reflect.Chan 1423 // reflect.Func 1424 // reflect.Interface 1425 // reflect.Map 1426 // reflect.Slice 1427 // reflect.Struct 1428 1429 default: 1430 err = ErrCannotConvertTo.FormatWith(source, tool.Typfmtv(&source), targetType, targetType.Kind()) 1431 } 1432 } else if ctx.isGroupedFlagOKDeeply(cms.ClearIfInvalid) { 1433 target = reflect.Zero(targetType) 1434 } else { 1435 err = errors.New("source (%v) is invalid", tool.Valfmt(&source)) 1436 } 1437 return 1438 } 1439 1440 //nolint:lll //keep it 1441 func (c *toDurationConverter) Match(params *Params, source, target reflect.Type) (ctx *ValueConverterContext, yes bool) { 1442 if tk := target.Kind(); tk == reflect.Int64 { 1443 if yes = target.Name() == "Duration" && target.PkgPath() == timeConstString; yes { 1444 ctx = &ValueConverterContext{params} 1445 } 1446 } 1447 return 1448 } 1449 1450 // 1451 1452 // 1453 1454 type toFuncConverter struct{ fromConverterBase } 1455 1456 func copyToFuncImpl(controller *cpController, source, target reflect.Value, targetType reflect.Type) (err error) { 1457 var presets []typ.Any 1458 if controller != nil { 1459 presets = controller.funcInputs 1460 } 1461 if targetType.NumIn() == len(presets)+1 { 1462 var args []reflect.Value 1463 for _, in := range presets { 1464 args = append(args, reflect.ValueOf(in)) 1465 } 1466 args = append(args, source) 1467 1468 res := target.Call(args) 1469 if len(res) > 0 { 1470 last := res[len(res)-1] 1471 if tool.Iserrortype(targetType.Out(len(res)-1)) && !tool.IsNil(last) { 1472 err = last.Interface().(error) //nolint:errcheck //no need 1473 } 1474 } 1475 } 1476 return 1477 } 1478 1479 // processUnexportedField try to set newval into target if it's an unexported field. 1480 // 1481 //nolint:lll //keep it 1482 func (c *toFuncConverter) processUnexportedField(ctx *ValueConverterContext, target, newval reflect.Value) (processed bool) { 1483 if ctx == nil || ctx.Params == nil { 1484 return 1485 } 1486 processed = ctx.Params.processUnexportedField(target, newval) 1487 return 1488 } 1489 1490 func (c *toFuncConverter) copyTo(ctx *ValueConverterContext, source, src, tgt, tsetter reflect.Value) (err error) { 1491 if ctx.isGroupedFlagOKDeeply(cms.Ignore) { 1492 return 1493 } 1494 1495 tgttyp := tgt.Type() 1496 dbglog.Log(" copyTo: src: %v, tgt: %v,", tool.Typfmtv(&src), tool.Typfmt(tgttyp)) 1497 1498 if k := src.Kind(); k != reflect.Func && ctx.IsPassSourceToTargetFunction() { 1499 var controller *cpController 1500 if ctx.Params != nil && ctx.controller != nil { 1501 controller = ctx.controller 1502 } 1503 err = copyToFuncImpl(controller, source, tgt, tgttyp) 1504 } else if k == reflect.Func { 1505 if !c.processUnexportedField(ctx, tgt, src) { 1506 tsetter.Set(src) 1507 } 1508 dbglog.Log(" function pointer copied: %v (%v) -> %v", source.Kind(), source.Interface(), tgt.Kind()) 1509 } 1510 return 1511 } 1512 1513 func (c *toFuncConverter) CopyTo(ctx *ValueConverterContext, source, target reflect.Value) (err error) { 1514 src := tool.Rdecodesimple(source) 1515 tgt, tgtptr := tool.Rdecode(target) 1516 tgtType := c.safeType(tgt, tgtptr) // because tgt might be invalid, so we fetch tgt type via its pointer 1517 // Log(" CopyTo: src: %v, tgt: %v,", typfmtv(&src), typfmt(tgtType)) 1518 dbglog.Log(" target: %v (%v), tgtptr: %v, tgt: %v, tgttyp: %v", 1519 tool.Typfmtv(&target), tool.Typfmt(target.Type()), tool.Typfmtv(&tgtptr), 1520 tool.Typfmtv(&tgt), tool.Typfmt(tgtType)) 1521 1522 if processed := c.checkTarget(ctx, tgt, tgtType); processed { 1523 // tgtptr.Set(ret) 1524 return 1525 } 1526 1527 err = c.copyTo(ctx, source, src, tgt, tgtptr) 1528 return 1529 } 1530 1531 // func (c *toFuncConverter) Transform(ctx *ValueConverterContext, source reflect.Value, 1532 // targetType reflect.Type) (target reflect.Value, err error) { 1533 // 1534 // target = reflect.New(targetType).Elem() 1535 // 1536 // src := rdecodesimple(source) 1537 // tgt, tgtptr := rdecode(target) 1538 // 1539 // var processed bool 1540 // if target, processed = c.checkSource(ctx, source, targetType); processed { 1541 // return 1542 // } 1543 // 1544 // err = c.copyTo(ctx, source, src, tgt, tgtptr) 1545 // return 1546 // } 1547 1548 func (c *toFuncConverter) Match(params *Params, source, target reflect.Type) (ctx *ValueConverterContext, yes bool) { 1549 if tk := target.Kind(); tk == reflect.Func { 1550 yes, ctx = true, &ValueConverterContext{params} 1551 } 1552 return 1553 } 1554 1555 // 1556 1557 type fromFuncConverter struct{ fromConverterBase } 1558 1559 func (c *fromFuncConverter) CopyTo(ctx *ValueConverterContext, source, target reflect.Value) (err error) { 1560 // tsetter might not be equal to tgt when: 1561 // target represents -> (ptr - interface{} - bool) 1562 // such as: 1563 // var a interface{} = true 1564 // var target = reflect.ValueOf(&a) 1565 // tgt, tsetter := rdecodesimple(target), rindirect(target) 1566 // assertNotEqual(tgt, tsetter) 1567 // // in this case, tsetter represents 'a' and tgt represents 1568 // // 'decoded bool(a)'. 1569 // 1570 src := tool.Rdecodesimple(source) 1571 tgt, tgtptr := tool.Rdecode(target) 1572 tgtType := c.safeType(tgt, tgtptr) 1573 // dbglog.Log(" CopyTo: src: %v, tgt: %v, tsetter: %v", typfmtv(&src), typfmt(tgttyp), typfmtv(&tsetter)) 1574 dbglog.Log(" target: %v (%v), tgtptr: %v, tgt: %v, tgttyp: %v", 1575 tool.Typfmtv(&target), tool.Typfmt(target.Type()), tool.Typfmtv(&tgtptr), 1576 tool.Typfmtv(&tgt), tool.Typfmt(tgtType)) 1577 1578 if processed := c.checkTarget(ctx, tgt, tgtType); processed { 1579 // target.Set(ret) 1580 return 1581 } 1582 1583 if k := tgtType.Kind(); k != reflect.Func && ctx.IsCopyFunctionResultToTarget() { 1584 err = c.funcResultToTarget(ctx, src, target) 1585 return 1586 } else if k == reflect.Func { 1587 if !c.processUnexportedField(ctx, tgt, src) { 1588 tgtptr.Set(src) 1589 } 1590 dbglog.Log(" function pointer copied: %v (%v) -> %v", source.Kind(), source.Interface(), target.Kind()) 1591 } 1592 1593 // if ret, e := c.Transform(ctx, src, tgttyp); e == nil { 1594 // if !target.IsValid() || isZero(target) { 1595 // return errors.New("cannot set to zero or invalid target") 1596 // } 1597 // if canConvert(&ret, tgttyp) { 1598 // nv := ret.Convert(tgttyp) 1599 // if c.processUnexportedField(ctx, tgt, nv) { 1600 // return 1601 // } 1602 // tsetter.Set(nv) 1603 // } 1604 // } 1605 return 1606 } 1607 1608 //nolint:lll,gocognit //keep it 1609 func (c *fromFuncConverter) funcResultToTarget(ctx *ValueConverterContext, source, target reflect.Value) (err error) { 1610 sourceType := source.Type() 1611 var presetInArgsLen int 1612 var ok bool 1613 var controllerIsValid = ctx != nil && ctx.Params != nil && ctx.Params.controller != nil 1614 if controllerIsValid { 1615 presetInArgsLen = len(ctx.controller.funcInputs) 1616 } 1617 if sourceType.NumIn() == presetInArgsLen { //nolint:nestif //keep it 1618 numOutSrc := sourceType.NumOut() 1619 if numOutSrc > 0 { 1620 srcResults := source.Call([]reflect.Value{}) 1621 1622 results := srcResults 1623 lastoutargtype := sourceType.Out(sourceType.NumOut() - 1) 1624 ok = tool.Iserrortype(lastoutargtype) 1625 if ok { 1626 v := results[len(results)-1].Interface() 1627 err, _ = v.(error) 1628 if err != nil { 1629 return 1630 } 1631 results = results[:len(results)-1] 1632 } 1633 1634 if len(results) > 0 { 1635 if controllerIsValid { 1636 // if tk := target.Kind(); tk == reflect.Ptr && isNil(target) {} 1637 err = ctx.controller.copyTo(ctx.Params, results[0], target) 1638 return 1639 } 1640 1641 // target, err = c.expandResults(ctx, sourceType, targetType, results) 1642 err = errors.New("expecting ctx.Params.controller is valid object ptr") 1643 return 1644 } 1645 } 1646 } 1647 //nolint:lll //keep it 1648 err = errors.New("unmatched number of function return and preset input args: function needs %v params but preset %v input args", sourceType.NumIn(), presetInArgsLen) 1649 return 1650 } 1651 1652 // // processUnexportedField try to set newval into target if it's an unexported field 1653 // func (c *fromFuncConverter) processUnexportedField(ctx *ValueConverterContext, target, 1654 // newval reflect.Value) (processed bool) { 1655 // if ctx == nil || ctx.Params == nil { 1656 // return 1657 // } 1658 // processed = ctx.Params.processUnexportedField(target, newval) 1659 // return 1660 // } 1661 1662 //nolint:lll //keep it 1663 func (c *fromFuncConverter) Transform(ctx *ValueConverterContext, source reflect.Value, targetType reflect.Type) (target reflect.Value, err error) { 1664 var processed bool 1665 if target, processed = c.checkSource(ctx, source, targetType); processed { 1666 return 1667 } 1668 1669 target = reflect.New(targetType).Elem() 1670 err = c.CopyTo(ctx, source, target) 1671 1672 // src, tgt, tgttyp := rdecodesimple(source), rdecodesimple(target), rdecodetypesimple(targetType) 1673 // Log(" Transform: src: %v, tgt: %v", typfmtv(&src), typfmt(tgttyp)) 1674 // if k := tgttyp.Kind(); k != reflect.Func && ctx.IsCopyFunctionResultToTarget() { 1675 // target, err = c.funcResultToField(ctx, src, tgttyp) 1676 // return 1677 // 1678 // } else if k == reflect.Func { 1679 // 1680 // if c.processUnexportedField(ctx, tgt, src) { 1681 // ptr := source.Pointer() 1682 // target.SetPointer(unsafe.Pointer(ptr)) 1683 // } 1684 // Log(" function pointer copied: %v (%v) -> %v", source.Kind(), source.Interface(), target.Kind()) 1685 // } 1686 return 1687 } 1688 1689 // func (c *fromFuncConverter) funcResultToField(ctx *ValueConverterContext, source reflect.Value, 1690 // targetType reflect.Type) (target reflect.Value, err error) { 1691 // sourceType := source.Type() 1692 // var presetInArgsLen int 1693 // var ok bool 1694 // var controllerIsValid = ctx != nil && ctx.Params != nil && ctx.Params.controller != nil 1695 // if controllerIsValid { 1696 // presetInArgsLen = len(ctx.controller.funcInputs) 1697 // } 1698 // if sourceType.NumIn() == presetInArgsLen { 1699 // numOutSrc := sourceType.NumOut() 1700 // if numOutSrc > 0 { 1701 // srcResults := source.Call([]reflect.Value{}) 1702 // 1703 // results := srcResults 1704 // lastoutargtype := sourceType.Out(sourceType.NumOut() - 1) 1705 // ok = iserrortype(lastoutargtype) 1706 // if ok { 1707 // err, ok = results[len(results)-1].Interface().(error) 1708 // if err != nil { 1709 // return 1710 // } 1711 // results = results[:len(results)-1] 1712 // } 1713 // 1714 // if len(results) > 0 { 1715 // // slice,map,struct 1716 // // scalar 1717 // 1718 // target, err = c.expandResults(ctx, sourceType, targetType, results) 1719 // } 1720 // } 1721 // } else { 1722 // err = errors.New("unmatched number of function return and preset input args: function needs 1723 // %v params but preset %v input args", sourceType.NumIn(), presetInArgsLen) 1724 // } 1725 // return 1726 // } 1727 // 1728 // func (c *fromFuncConverter) expandResults(ctx *ValueConverterContext, sourceType, targetType 1729 // reflect.Type, results []reflect.Value) (target reflect.Value, err error) { 1730 // //srclen := len(results) 1731 // switch kind := targetType.Kind(); kind { 1732 // case reflect.Bool: 1733 // target = rToBool(results[0]) 1734 // case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 1735 // target, err = rToInteger(results[0], targetType) 1736 // case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 1737 // target, err = rToUInteger(results[0], targetType) 1738 // case reflect.Float32, reflect.Float64: 1739 // target, err = rToFloat(results[0], targetType) 1740 // case reflect.Complex64, reflect.Complex128: 1741 // target, err = rToComplex(results[0], targetType) 1742 // case reflect.String: 1743 // { 1744 // var processed bool 1745 // if processed, target, err = ctx.Preprocess(results[0], targetType, c); processed { 1746 // return 1747 // } 1748 // } 1749 // target, err = rToString(results[0], targetType) 1750 // 1751 // case reflect.Array: 1752 // target, err = rToArray(ctx, results[0], targetType, -1) 1753 // case reflect.Slice: 1754 // target, err = rToSlice(ctx, results[0], targetType, -1) 1755 // case reflect.Map: 1756 // target, err = rToMap(ctx, results[0], sourceType, targetType) 1757 // case reflect.Struct: 1758 // target, err = rToStruct(ctx, results[0], sourceType, targetType) 1759 // case reflect.Func: 1760 // target, err = rToFunc(ctx, results[0], sourceType, targetType) 1761 // 1762 // case reflect.Interface, reflect.Ptr, reflect.Chan: 1763 // if results[0].Type().ConvertibleTo(targetType) { 1764 // target = results[0].Convert(targetType) 1765 // } else { 1766 // err = errCannotConvertTo.FormatWith(typfmt(results[0].Type()), typfmt(targetType)) 1767 // } 1768 // 1769 // case reflect.UnsafePointer: 1770 // err = errCannotConvertTo.FormatWith(typfmt(results[0].Type()), typfmt(targetType)) 1771 // } 1772 // return 1773 // } 1774 1775 func (c *fromFuncConverter) Match(params *Params, source, target reflect.Type) (ctx *ValueConverterContext, yes bool) { 1776 if sk := source.Kind(); sk == reflect.Func { 1777 yes, ctx = true, &ValueConverterContext{params} 1778 } 1779 return 1780 }