goki.dev/laser@v0.1.34/basic.go (about) 1 // Copyright (c) 2023, The Goki Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package laser 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "reflect" 11 "strconv" 12 13 "goki.dev/enums" 14 "goki.dev/glop/bools" 15 ) 16 17 // Has convenience functions for converting any (e.g. properties) to given 18 // types uses the "ok" bool mechanism to report failure -- are as robust and 19 // general as possible. 20 // 21 // WARNING: these violate many of the type-safety features of Go but OTOH give 22 // maximum robustness, appropriate for the world of end-user settable 23 // properties, and deal with most common-sense cases, e.g., string <-> number, 24 // etc. nil values return !ok 25 26 // AnyIsNil checks if an interface value is nil -- the interface itself could be 27 // nil, or the value pointed to by the interface could be nil -- this checks 28 // both, safely 29 // gopy:interface=handle 30 func AnyIsNil(it any) bool { 31 if it == nil { 32 return true 33 } 34 v := reflect.ValueOf(it) 35 vk := v.Kind() 36 if vk == reflect.Ptr || vk == reflect.Interface || vk == reflect.Map || vk == reflect.Slice || vk == reflect.Func || vk == reflect.Chan { 37 return v.IsNil() 38 } 39 return false 40 } 41 42 // KindIsBasic returns true if the reflect.Kind is a basic, elemental 43 // type such as Int, Float, etc 44 func KindIsBasic(vk reflect.Kind) bool { 45 if vk >= reflect.Bool && vk <= reflect.Complex128 { 46 return true 47 } 48 return false 49 } 50 51 // ValueIsZero returns true if the reflect.Value is Zero or nil or invalid or 52 // otherwise doesn't have a useful value -- from 53 // https://github.com/golang/go/issues/7501 54 func ValueIsZero(v reflect.Value) bool { 55 if !v.IsValid() { 56 return true 57 } 58 switch v.Kind() { 59 case reflect.Array, reflect.String: 60 return v.Len() == 0 61 case reflect.Bool: 62 return !v.Bool() 63 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 64 return v.Int() == 0 65 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 66 return v.Uint() == 0 67 case reflect.Float32, reflect.Float64: 68 return v.Float() == 0 69 case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: 70 return v.IsNil() 71 case reflect.Func: 72 return v == reflect.Zero(v.Type()) 73 } 74 return false 75 } 76 77 // ToBool robustly converts to a bool any basic elemental type 78 // (including pointers to such) using a big type switch organized 79 // for greatest efficiency. It tries the [goki.dev/glop/bools.Booler] 80 // interface if not a bool type. It falls back on reflection when all 81 // else fails. 82 // 83 //gopy:interface=handle 84 func ToBool(v any) (bool, error) { 85 switch vt := v.(type) { 86 case bool: 87 return vt, nil 88 case *bool: 89 if vt == nil { 90 return false, fmt.Errorf("got nil *bool") 91 } 92 return *vt, nil 93 } 94 95 if br, ok := v.(bools.Booler); ok { 96 return br.Bool(), nil 97 } 98 99 switch vt := v.(type) { 100 case int: 101 return vt != 0, nil 102 case *int: 103 if vt == nil { 104 return false, fmt.Errorf("got nil *int") 105 } 106 return *vt != 0, nil 107 case int32: 108 return vt != 0, nil 109 case *int32: 110 if vt == nil { 111 return false, fmt.Errorf("got nil *int32") 112 } 113 return *vt != 0, nil 114 case int64: 115 return vt != 0, nil 116 case *int64: 117 if vt == nil { 118 return false, fmt.Errorf("got nil *int64") 119 } 120 return *vt != 0, nil 121 case uint8: 122 return vt != 0, nil 123 case *uint8: 124 if vt == nil { 125 return false, fmt.Errorf("got nil *uint8") 126 } 127 return *vt != 0, nil 128 case float64: 129 return vt != 0, nil 130 case *float64: 131 if vt == nil { 132 return false, fmt.Errorf("got nil *float64") 133 } 134 return *vt != 0, nil 135 case float32: 136 return vt != 0, nil 137 case *float32: 138 if vt == nil { 139 return false, fmt.Errorf("got nil *float32") 140 } 141 return *vt != 0, nil 142 case string: 143 r, err := strconv.ParseBool(vt) 144 if err != nil { 145 return false, err 146 } 147 return r, nil 148 case *string: 149 if vt == nil { 150 return false, fmt.Errorf("got nil *string") 151 } 152 r, err := strconv.ParseBool(*vt) 153 if err != nil { 154 return false, err 155 } 156 return r, nil 157 case int8: 158 return vt != 0, nil 159 case *int8: 160 if vt == nil { 161 return false, fmt.Errorf("got nil *int8") 162 } 163 return *vt != 0, nil 164 case int16: 165 return vt != 0, nil 166 case *int16: 167 if vt == nil { 168 return false, fmt.Errorf("got nil *int16") 169 } 170 return *vt != 0, nil 171 case uint: 172 return vt != 0, nil 173 case *uint: 174 if vt == nil { 175 return false, fmt.Errorf("got nil *uint") 176 } 177 return *vt != 0, nil 178 case uint16: 179 return vt != 0, nil 180 case *uint16: 181 if vt == nil { 182 return false, fmt.Errorf("got nil *uint16") 183 } 184 return *vt != 0, nil 185 case uint32: 186 return vt != 0, nil 187 case *uint32: 188 if vt == nil { 189 return false, fmt.Errorf("got nil *uint32") 190 } 191 return *vt != 0, nil 192 case uint64: 193 return vt != 0, nil 194 case *uint64: 195 if vt == nil { 196 return false, fmt.Errorf("got nil *uint64") 197 } 198 return *vt != 0, nil 199 case uintptr: 200 return vt != 0, nil 201 case *uintptr: 202 if vt == nil { 203 return false, fmt.Errorf("got nil *uintptr") 204 } 205 return *vt != 0, nil 206 } 207 208 // then fall back on reflection 209 if AnyIsNil(v) { 210 return false, fmt.Errorf("got nil value of type %T", v) 211 } 212 npv := NonPtrValue(reflect.ValueOf(v)) 213 vk := npv.Kind() 214 switch { 215 case vk >= reflect.Int && vk <= reflect.Int64: 216 return (npv.Int() != 0), nil 217 case vk >= reflect.Uint && vk <= reflect.Uint64: 218 return (npv.Uint() != 0), nil 219 case vk == reflect.Bool: 220 return npv.Bool(), nil 221 case vk >= reflect.Float32 && vk <= reflect.Float64: 222 return (npv.Float() != 0.0), nil 223 case vk >= reflect.Complex64 && vk <= reflect.Complex128: 224 return (real(npv.Complex()) != 0.0), nil 225 case vk == reflect.String: 226 r, err := strconv.ParseBool(npv.String()) 227 if err != nil { 228 return false, err 229 } 230 return r, nil 231 default: 232 return false, fmt.Errorf("got value %v of unsupported type %T", v, v) 233 } 234 } 235 236 // ToInt robustly converts to an int64 any basic elemental type 237 // (including pointers to such) using a big type switch organized 238 // for greatest efficiency, only falling back on reflection when all 239 // else fails. 240 // 241 //gopy:interface=handle 242 func ToInt(v any) (int64, error) { 243 switch vt := v.(type) { 244 case int: 245 return int64(vt), nil 246 case *int: 247 if vt == nil { 248 return 0, fmt.Errorf("got nil *int") 249 } 250 return int64(*vt), nil 251 case int32: 252 return int64(vt), nil 253 case *int32: 254 if vt == nil { 255 return 0, fmt.Errorf("got nil *int32") 256 } 257 return int64(*vt), nil 258 case int64: 259 return vt, nil 260 case *int64: 261 if vt == nil { 262 return 0, fmt.Errorf("got nil *int64") 263 } 264 return *vt, nil 265 case uint8: 266 return int64(vt), nil 267 case *uint8: 268 if vt == nil { 269 return 0, fmt.Errorf("got nil *uint8") 270 } 271 return int64(*vt), nil 272 case float64: 273 return int64(vt), nil 274 case *float64: 275 if vt == nil { 276 return 0, fmt.Errorf("got nil *float64") 277 } 278 return int64(*vt), nil 279 case float32: 280 return int64(vt), nil 281 case *float32: 282 if vt == nil { 283 return 0, fmt.Errorf("got nil *float32") 284 } 285 return int64(*vt), nil 286 case bool: 287 if vt { 288 return 1, nil 289 } 290 return 0, nil 291 case *bool: 292 if vt == nil { 293 return 0, fmt.Errorf("got nil *bool") 294 } 295 if *vt { 296 return 1, nil 297 } 298 return 0, nil 299 case string: 300 r, err := strconv.ParseInt(vt, 0, 64) 301 if err != nil { 302 return 0, err 303 } 304 return r, nil 305 case *string: 306 if vt == nil { 307 return 0, fmt.Errorf("got nil *string") 308 } 309 r, err := strconv.ParseInt(*vt, 0, 64) 310 if err != nil { 311 return 0, err 312 } 313 return r, nil 314 case enums.Enum: 315 return vt.Int64(), nil 316 case int8: 317 return int64(vt), nil 318 case *int8: 319 if vt == nil { 320 return 0, fmt.Errorf("got nil *int8") 321 } 322 return int64(*vt), nil 323 case int16: 324 return int64(vt), nil 325 case *int16: 326 if vt == nil { 327 return 0, fmt.Errorf("got nil *int16") 328 } 329 return int64(*vt), nil 330 case uint: 331 return int64(vt), nil 332 case *uint: 333 if vt == nil { 334 return 0, fmt.Errorf("got nil *uint") 335 } 336 return int64(*vt), nil 337 case uint16: 338 return int64(vt), nil 339 case *uint16: 340 if vt == nil { 341 return 0, fmt.Errorf("got nil *uint16") 342 } 343 return int64(*vt), nil 344 case uint32: 345 return int64(vt), nil 346 case *uint32: 347 if vt == nil { 348 return 0, fmt.Errorf("got nil *uint32") 349 } 350 return int64(*vt), nil 351 case uint64: 352 return int64(vt), nil 353 case *uint64: 354 if vt == nil { 355 return 0, fmt.Errorf("got nil *uint64") 356 } 357 return int64(*vt), nil 358 case uintptr: 359 return int64(vt), nil 360 case *uintptr: 361 if vt == nil { 362 return 0, fmt.Errorf("got nil *uintptr") 363 } 364 return int64(*vt), nil 365 } 366 367 // then fall back on reflection 368 if AnyIsNil(v) { 369 return 0, fmt.Errorf("got nil value of type %T", v) 370 } 371 npv := NonPtrValue(reflect.ValueOf(v)) 372 vk := npv.Kind() 373 switch { 374 case vk >= reflect.Int && vk <= reflect.Int64: 375 return npv.Int(), nil 376 case vk >= reflect.Uint && vk <= reflect.Uint64: 377 return int64(npv.Uint()), nil 378 case vk == reflect.Bool: 379 if npv.Bool() { 380 return 1, nil 381 } 382 return 0, nil 383 case vk >= reflect.Float32 && vk <= reflect.Float64: 384 return int64(npv.Float()), nil 385 case vk >= reflect.Complex64 && vk <= reflect.Complex128: 386 return int64(real(npv.Complex())), nil 387 case vk == reflect.String: 388 r, err := strconv.ParseInt(npv.String(), 0, 64) 389 if err != nil { 390 return 0, err 391 } 392 return r, nil 393 default: 394 return 0, fmt.Errorf("got value %v of unsupported type %T", v, v) 395 } 396 } 397 398 // ToFloat robustly converts to a float64 any basic elemental type 399 // (including pointers to such) using a big type switch organized for 400 // greatest efficiency, only falling back on reflection when all else fails. 401 // 402 //gopy:interface=handle 403 func ToFloat(v any) (float64, error) { 404 switch vt := v.(type) { 405 case float64: 406 return vt, nil 407 case *float64: 408 if vt == nil { 409 return 0, fmt.Errorf("got nil *float64") 410 } 411 return *vt, nil 412 case float32: 413 return float64(vt), nil 414 case *float32: 415 if vt == nil { 416 return 0, fmt.Errorf("got nil *float32") 417 } 418 return float64(*vt), nil 419 case int: 420 return float64(vt), nil 421 case *int: 422 if vt == nil { 423 return 0, fmt.Errorf("got nil *int") 424 } 425 return float64(*vt), nil 426 case int32: 427 return float64(vt), nil 428 case *int32: 429 if vt == nil { 430 return 0, fmt.Errorf("got nil *int32") 431 } 432 return float64(*vt), nil 433 case int64: 434 return float64(vt), nil 435 case *int64: 436 if vt == nil { 437 return 0, fmt.Errorf("got nil *int64") 438 } 439 return float64(*vt), nil 440 case uint8: 441 return float64(vt), nil 442 case *uint8: 443 if vt == nil { 444 return 0, fmt.Errorf("got nil *uint8") 445 } 446 return float64(*vt), nil 447 case bool: 448 if vt { 449 return 1, nil 450 } 451 return 0, nil 452 case *bool: 453 if vt == nil { 454 return 0, fmt.Errorf("got nil *bool") 455 } 456 if *vt { 457 return 1, nil 458 } 459 return 0, nil 460 case string: 461 r, err := strconv.ParseFloat(vt, 64) 462 if err != nil { 463 return 0.0, err 464 } 465 return r, nil 466 case *string: 467 if vt == nil { 468 return 0, fmt.Errorf("got nil *string") 469 } 470 r, err := strconv.ParseFloat(*vt, 64) 471 if err != nil { 472 return 0.0, err 473 } 474 return r, nil 475 case int8: 476 return float64(vt), nil 477 case *int8: 478 if vt == nil { 479 return 0, fmt.Errorf("got nil *int8") 480 } 481 return float64(*vt), nil 482 case int16: 483 return float64(vt), nil 484 case *int16: 485 if vt == nil { 486 return 0, fmt.Errorf("got nil *int16") 487 } 488 return float64(*vt), nil 489 case uint: 490 return float64(vt), nil 491 case *uint: 492 if vt == nil { 493 return 0, fmt.Errorf("got nil *uint") 494 } 495 return float64(*vt), nil 496 case uint16: 497 return float64(vt), nil 498 case *uint16: 499 if vt == nil { 500 return 0, fmt.Errorf("got nil *uint16") 501 } 502 return float64(*vt), nil 503 case uint32: 504 return float64(vt), nil 505 case *uint32: 506 if vt == nil { 507 return 0, fmt.Errorf("got nil *uint32") 508 } 509 return float64(*vt), nil 510 case uint64: 511 return float64(vt), nil 512 case *uint64: 513 if vt == nil { 514 return 0, fmt.Errorf("got nil *uint64") 515 } 516 return float64(*vt), nil 517 case uintptr: 518 return float64(vt), nil 519 case *uintptr: 520 if vt == nil { 521 return 0, fmt.Errorf("got nil *uintptr") 522 } 523 return float64(*vt), nil 524 } 525 526 // then fall back on reflection 527 if AnyIsNil(v) { 528 return 0, fmt.Errorf("got nil value of type %T", v) 529 } 530 npv := NonPtrValue(reflect.ValueOf(v)) 531 vk := npv.Kind() 532 switch { 533 case vk >= reflect.Int && vk <= reflect.Int64: 534 return float64(npv.Int()), nil 535 case vk >= reflect.Uint && vk <= reflect.Uint64: 536 return float64(npv.Uint()), nil 537 case vk == reflect.Bool: 538 if npv.Bool() { 539 return 1, nil 540 } 541 return 0, nil 542 case vk >= reflect.Float32 && vk <= reflect.Float64: 543 return npv.Float(), nil 544 case vk >= reflect.Complex64 && vk <= reflect.Complex128: 545 return real(npv.Complex()), nil 546 case vk == reflect.String: 547 r, err := strconv.ParseFloat(npv.String(), 64) 548 if err != nil { 549 return 0, err 550 } 551 return r, nil 552 default: 553 return 0, fmt.Errorf("got value %v of unsupported type %T", v, v) 554 } 555 } 556 557 // ToFloat32 robustly converts to a float32 any basic elemental type 558 // (including pointers to such) using a big type switch organized for 559 // greatest efficiency, only falling back on reflection when all else fails. 560 // 561 //gopy:interface=handle 562 func ToFloat32(v any) (float32, error) { 563 switch vt := v.(type) { 564 case float32: 565 return vt, nil 566 case *float32: 567 if vt == nil { 568 return 0, fmt.Errorf("got nil *float32") 569 } 570 return *vt, nil 571 case float64: 572 return float32(vt), nil 573 case *float64: 574 if vt == nil { 575 return 0, fmt.Errorf("got nil *float64") 576 } 577 return float32(*vt), nil 578 case int: 579 return float32(vt), nil 580 case *int: 581 if vt == nil { 582 return 0, fmt.Errorf("got nil *int") 583 } 584 return float32(*vt), nil 585 case int32: 586 return float32(vt), nil 587 case *int32: 588 if vt == nil { 589 return 0, fmt.Errorf("got nil *int32") 590 } 591 return float32(*vt), nil 592 case int64: 593 return float32(vt), nil 594 case *int64: 595 if vt == nil { 596 return 0, fmt.Errorf("got nil *int64") 597 } 598 return float32(*vt), nil 599 case uint8: 600 return float32(vt), nil 601 case *uint8: 602 if vt == nil { 603 return 0, fmt.Errorf("got nil *uint8") 604 } 605 return float32(*vt), nil 606 case bool: 607 if vt { 608 return 1, nil 609 } 610 return 0, nil 611 case *bool: 612 if vt == nil { 613 return 0, fmt.Errorf("got nil *bool") 614 } 615 if *vt { 616 return 1, nil 617 } 618 return 0, nil 619 case string: 620 r, err := strconv.ParseFloat(vt, 32) 621 if err != nil { 622 return 0, err 623 } 624 return float32(r), nil 625 case *string: 626 if vt == nil { 627 return 0, fmt.Errorf("got nil *string") 628 } 629 r, err := strconv.ParseFloat(*vt, 32) 630 if err != nil { 631 return 0, err 632 } 633 return float32(r), nil 634 case int8: 635 return float32(vt), nil 636 case *int8: 637 if vt == nil { 638 return 0, fmt.Errorf("got nil *int8") 639 } 640 return float32(*vt), nil 641 case int16: 642 return float32(vt), nil 643 case *int16: 644 if vt == nil { 645 return 0, fmt.Errorf("got nil *int8") 646 } 647 return float32(*vt), nil 648 case uint: 649 return float32(vt), nil 650 case *uint: 651 if vt == nil { 652 return 0, fmt.Errorf("got nil *uint") 653 } 654 return float32(*vt), nil 655 case uint16: 656 return float32(vt), nil 657 case *uint16: 658 if vt == nil { 659 return 0, fmt.Errorf("got nil *uint16") 660 } 661 return float32(*vt), nil 662 case uint32: 663 return float32(vt), nil 664 case *uint32: 665 if vt == nil { 666 return 0, fmt.Errorf("got nil *uint32") 667 } 668 return float32(*vt), nil 669 case uint64: 670 return float32(vt), nil 671 case *uint64: 672 if vt == nil { 673 return 0, fmt.Errorf("got nil *uint64") 674 } 675 return float32(*vt), nil 676 case uintptr: 677 return float32(vt), nil 678 case *uintptr: 679 if vt == nil { 680 return 0, fmt.Errorf("got nil *uintptr") 681 } 682 return float32(*vt), nil 683 } 684 685 // then fall back on reflection 686 if AnyIsNil(v) { 687 return 0, fmt.Errorf("got nil value of type %T", v) 688 } 689 npv := NonPtrValue(reflect.ValueOf(v)) 690 vk := npv.Kind() 691 switch { 692 case vk >= reflect.Int && vk <= reflect.Int64: 693 return float32(npv.Int()), nil 694 case vk >= reflect.Uint && vk <= reflect.Uint64: 695 return float32(npv.Uint()), nil 696 case vk == reflect.Bool: 697 if npv.Bool() { 698 return 1, nil 699 } 700 return 0, nil 701 case vk >= reflect.Float32 && vk <= reflect.Float64: 702 return float32(npv.Float()), nil 703 case vk >= reflect.Complex64 && vk <= reflect.Complex128: 704 return float32(real(npv.Complex())), nil 705 case vk == reflect.String: 706 r, err := strconv.ParseFloat(npv.String(), 32) 707 if err != nil { 708 return 0, err 709 } 710 return float32(r), nil 711 default: 712 return 0, fmt.Errorf("got value %v of unsupported type %T", v, v) 713 } 714 } 715 716 // ToString robustly converts anything to a String 717 // using a big type switch organized for greatest efficiency. 718 // First checks for string or []byte and returns that immediately, 719 // then checks for the Stringer interface as the preferred conversion 720 // (e.g., for enums), and then falls back on strconv calls for numeric types. 721 // If everything else fails, it uses Sprintf("%v") which always works, 722 // so there is no need for an error return value. 723 // - returns "nil" for any nil pointers 724 // - byte is converted as string(byte) not the decimal representation 725 // 726 //gopy:interface=handle 727 func ToString(v any) string { 728 nilstr := "nil" 729 switch vt := v.(type) { 730 case string: 731 return vt 732 case *string: 733 if vt == nil { 734 return nilstr 735 } 736 return *vt 737 case []byte: 738 return string(vt) 739 case *[]byte: 740 if vt == nil { 741 return nilstr 742 } 743 return string(*vt) 744 } 745 746 if stringer, ok := v.(fmt.Stringer); ok { 747 return stringer.String() 748 } 749 750 switch vt := v.(type) { 751 case bool: 752 if vt { 753 return "true" 754 } 755 return "false" 756 case *bool: 757 if vt == nil { 758 return nilstr 759 } 760 if *vt { 761 return "true" 762 } 763 return "false" 764 case int: 765 return strconv.FormatInt(int64(vt), 10) 766 case *int: 767 if vt == nil { 768 return nilstr 769 } 770 return strconv.FormatInt(int64(*vt), 10) 771 case int32: 772 return strconv.FormatInt(int64(vt), 10) 773 case *int32: 774 if vt == nil { 775 return nilstr 776 } 777 return strconv.FormatInt(int64(*vt), 10) 778 case int64: 779 return strconv.FormatInt(vt, 10) 780 case *int64: 781 if vt == nil { 782 return nilstr 783 } 784 return strconv.FormatInt(*vt, 10) 785 case uint8: // byte, converts as string char 786 return string(vt) 787 case *uint8: 788 if vt == nil { 789 return nilstr 790 } 791 return string(*vt) 792 case float64: 793 return strconv.FormatFloat(vt, 'G', -1, 64) 794 case *float64: 795 if vt == nil { 796 return nilstr 797 } 798 return strconv.FormatFloat(*vt, 'G', -1, 64) 799 case float32: 800 return strconv.FormatFloat(float64(vt), 'G', -1, 32) 801 case *float32: 802 if vt == nil { 803 return nilstr 804 } 805 return strconv.FormatFloat(float64(*vt), 'G', -1, 32) 806 case uintptr: 807 return fmt.Sprintf("%#x", uintptr(vt)) 808 case *uintptr: 809 if vt == nil { 810 return nilstr 811 } 812 return fmt.Sprintf("%#x", uintptr(*vt)) 813 814 case int8: 815 return strconv.FormatInt(int64(vt), 10) 816 case *int8: 817 if vt == nil { 818 return nilstr 819 } 820 return strconv.FormatInt(int64(*vt), 10) 821 case int16: 822 return strconv.FormatInt(int64(vt), 10) 823 case *int16: 824 if vt == nil { 825 return nilstr 826 } 827 return strconv.FormatInt(int64(*vt), 10) 828 case uint: 829 return strconv.FormatInt(int64(vt), 10) 830 case *uint: 831 if vt == nil { 832 return nilstr 833 } 834 return strconv.FormatInt(int64(*vt), 10) 835 case uint16: 836 return strconv.FormatInt(int64(vt), 10) 837 case *uint16: 838 if vt == nil { 839 return nilstr 840 } 841 return strconv.FormatInt(int64(*vt), 10) 842 case uint32: 843 return strconv.FormatInt(int64(vt), 10) 844 case *uint32: 845 if vt == nil { 846 return nilstr 847 } 848 return strconv.FormatInt(int64(*vt), 10) 849 case uint64: 850 return strconv.FormatInt(int64(vt), 10) 851 case *uint64: 852 if vt == nil { 853 return nilstr 854 } 855 return strconv.FormatInt(int64(*vt), 10) 856 case complex64: 857 return strconv.FormatFloat(float64(real(vt)), 'G', -1, 32) + "," + strconv.FormatFloat(float64(imag(vt)), 'G', -1, 32) 858 case *complex64: 859 if vt == nil { 860 return nilstr 861 } 862 return strconv.FormatFloat(float64(real(*vt)), 'G', -1, 32) + "," + strconv.FormatFloat(float64(imag(*vt)), 'G', -1, 32) 863 case complex128: 864 return strconv.FormatFloat(real(vt), 'G', -1, 64) + "," + strconv.FormatFloat(imag(vt), 'G', -1, 64) 865 case *complex128: 866 if vt == nil { 867 return nilstr 868 } 869 return strconv.FormatFloat(real(*vt), 'G', -1, 64) + "," + strconv.FormatFloat(imag(*vt), 'G', -1, 64) 870 } 871 872 // then fall back on reflection 873 if AnyIsNil(v) { 874 return nilstr 875 } 876 npv := NonPtrValue(reflect.ValueOf(v)) 877 vk := npv.Kind() 878 switch { 879 case vk >= reflect.Int && vk <= reflect.Int64: 880 return strconv.FormatInt(npv.Int(), 10) 881 case vk >= reflect.Uint && vk <= reflect.Uint64: 882 return strconv.FormatUint(npv.Uint(), 10) 883 case vk == reflect.Bool: 884 return strconv.FormatBool(npv.Bool()) 885 case vk >= reflect.Float32 && vk <= reflect.Float64: 886 return strconv.FormatFloat(npv.Float(), 'G', -1, 64) 887 case vk >= reflect.Complex64 && vk <= reflect.Complex128: 888 cv := npv.Complex() 889 rv := strconv.FormatFloat(real(cv), 'G', -1, 64) + "," + strconv.FormatFloat(imag(cv), 'G', -1, 64) 890 return rv 891 case vk == reflect.String: 892 return npv.String() 893 case vk == reflect.Slice: 894 eltyp := SliceElType(v) 895 if eltyp.Kind() == reflect.Uint8 { // []byte 896 return string(v.([]byte)) 897 } 898 fallthrough 899 default: 900 return fmt.Sprintf("%v", v) 901 } 902 } 903 904 // ToStringPrec robustly converts anything to a String using given precision 905 // for converting floating values -- using a value like 6 truncates the 906 // nuisance random imprecision of actual floating point values due to the 907 // fact that they are represented with binary bits. 908 // Otherwise is identical to ToString for any other cases. 909 // 910 //gopy:interface=handle 911 func ToStringPrec(v any, prec int) string { 912 nilstr := "nil" 913 switch vt := v.(type) { 914 case string: 915 return vt 916 case *string: 917 if vt == nil { 918 return nilstr 919 } 920 return *vt 921 case []byte: 922 return string(vt) 923 case *[]byte: 924 if vt == nil { 925 return nilstr 926 } 927 return string(*vt) 928 } 929 930 if stringer, ok := v.(fmt.Stringer); ok { 931 return stringer.String() 932 } 933 934 switch vt := v.(type) { 935 case float64: 936 return strconv.FormatFloat(vt, 'G', prec, 64) 937 case *float64: 938 if vt == nil { 939 return nilstr 940 } 941 return strconv.FormatFloat(*vt, 'G', prec, 64) 942 case float32: 943 return strconv.FormatFloat(float64(vt), 'G', prec, 32) 944 case *float32: 945 if vt == nil { 946 return nilstr 947 } 948 return strconv.FormatFloat(float64(*vt), 'G', prec, 32) 949 case complex64: 950 return strconv.FormatFloat(float64(real(vt)), 'G', prec, 32) + "," + strconv.FormatFloat(float64(imag(vt)), 'G', prec, 32) 951 case *complex64: 952 if vt == nil { 953 return nilstr 954 } 955 return strconv.FormatFloat(float64(real(*vt)), 'G', prec, 32) + "," + strconv.FormatFloat(float64(imag(*vt)), 'G', prec, 32) 956 case complex128: 957 return strconv.FormatFloat(real(vt), 'G', prec, 64) + "," + strconv.FormatFloat(imag(vt), 'G', prec, 64) 958 case *complex128: 959 if vt == nil { 960 return nilstr 961 } 962 return strconv.FormatFloat(real(*vt), 'G', prec, 64) + "," + strconv.FormatFloat(imag(*vt), 'G', prec, 64) 963 } 964 return ToString(v) 965 } 966 967 // SetRobust robustly sets the 'to' value from the 'from' value. 968 // destination must be a pointer-to. Copies slices and maps robustly, 969 // and can set a struct, slice or map from a JSON-formatted string from value. 970 // Note that a map is _not_ reset prior to setting, whereas a slice length 971 // is set to the source length and is thus equivalent to the source slice. 972 // 973 //gopy:interface=handle 974 func SetRobust(to, frm any) error { 975 if sa, ok := to.(SetAnyer); ok { 976 err := sa.SetAny(frm) 977 if err != nil { 978 return err 979 } 980 return nil 981 } 982 if ss, ok := to.(SetStringer); ok { 983 if s, ok := frm.(string); ok { 984 err := ss.SetString(s) 985 if err != nil { 986 return err 987 } 988 return nil 989 } 990 } 991 992 if AnyIsNil(to) { 993 return fmt.Errorf("got nil destination value") 994 } 995 v := reflect.ValueOf(to) 996 vnp := NonPtrValue(v) 997 if !vnp.IsValid() { 998 return fmt.Errorf("got invalid destination value %v of type %T", to, to) 999 } 1000 typ := vnp.Type() 1001 vp := OnePtrValue(vnp) 1002 vk := vnp.Kind() 1003 if !vp.Elem().CanSet() { 1004 return fmt.Errorf("destination value cannot be set; it must be a variable or field, not a const or tmp or other value that cannot be set (value: %v of type %T)", vp, vp) 1005 } 1006 1007 if es, ok := to.(enums.EnumSetter); ok { 1008 if en, ok := frm.(enums.Enum); ok { 1009 es.SetInt64(en.Int64()) 1010 return nil 1011 } 1012 if str, ok := frm.(string); ok { 1013 return es.SetString(str) 1014 } 1015 fm, err := ToInt(frm) 1016 if err != nil { 1017 return err 1018 } 1019 es.SetInt64(fm) 1020 return nil 1021 } 1022 1023 if bv, ok := to.(bools.BoolSetter); ok { 1024 fb, err := ToBool(frm) 1025 if err != nil { 1026 return err 1027 } 1028 bv.SetBool(fb) 1029 return nil 1030 } 1031 1032 switch { 1033 case vk >= reflect.Int && vk <= reflect.Int64: 1034 fm, err := ToInt(frm) 1035 if err != nil { 1036 return err 1037 } 1038 vp.Elem().Set(reflect.ValueOf(fm).Convert(typ)) 1039 return nil 1040 case vk >= reflect.Uint && vk <= reflect.Uint64: 1041 fm, err := ToInt(frm) 1042 if err != nil { 1043 return err 1044 } 1045 vp.Elem().Set(reflect.ValueOf(fm).Convert(typ)) 1046 return nil 1047 case vk == reflect.Bool: 1048 fm, err := ToBool(frm) 1049 if err != nil { 1050 return err 1051 } 1052 vp.Elem().Set(reflect.ValueOf(fm).Convert(typ)) 1053 return nil 1054 case vk >= reflect.Float32 && vk <= reflect.Float64: 1055 fm, err := ToFloat(frm) 1056 if err != nil { 1057 return err 1058 } 1059 vp.Elem().Set(reflect.ValueOf(fm).Convert(typ)) 1060 return nil 1061 case vk >= reflect.Complex64 && vk <= reflect.Complex128: 1062 // cv := v.Complex() 1063 // rv := strconv.FormatFloat(real(cv), 'G', -1, 64) + "," + strconv.FormatFloat(imag(cv), 'G', -1, 64) 1064 // return rv, nil 1065 case vk == reflect.String: 1066 fm := ToString(frm) 1067 vp.Elem().Set(reflect.ValueOf(fm).Convert(typ)) 1068 return nil 1069 case vk == reflect.Struct: 1070 if NonPtrType(reflect.TypeOf(frm)).Kind() == reflect.String { 1071 err := json.Unmarshal([]byte(ToString(frm)), to) // todo: this is not working -- see what marshal says, etc 1072 if err != nil { 1073 marsh, _ := json.Marshal(to) 1074 return fmt.Errorf("error setting struct from string: %w (example format for string: %s)", err, string(marsh)) 1075 } 1076 return nil 1077 } 1078 case vk == reflect.Slice: 1079 if NonPtrType(reflect.TypeOf(frm)).Kind() == reflect.String { 1080 err := json.Unmarshal([]byte(ToString(frm)), to) 1081 if err != nil { 1082 marsh, _ := json.Marshal(to) 1083 return fmt.Errorf("error setting slice from string: %w (example format for string: %s)", err, string(marsh)) 1084 } 1085 return nil 1086 } 1087 return CopySliceRobust(to, frm) 1088 case vk == reflect.Map: 1089 if NonPtrType(reflect.TypeOf(frm)).Kind() == reflect.String { 1090 err := json.Unmarshal([]byte(ToString(frm)), to) 1091 if err != nil { 1092 marsh, _ := json.Marshal(to) 1093 return fmt.Errorf("error setting map from string: %w (example format for string: %s)", err, string(marsh)) 1094 } 1095 return nil 1096 } 1097 return CopyMapRobust(to, frm) 1098 } 1099 1100 fv := NonPtrValue(reflect.ValueOf(frm)) 1101 // Just set it if possible to assign 1102 if fv.Type().AssignableTo(typ) { 1103 vp.Elem().Set(fv) 1104 return nil 1105 } 1106 return fmt.Errorf("unable to set value %v of type %T from value %v of type %T (not a supported type pair and direct assigning is not possible)", to, to, frm, frm) 1107 }