github.com/goki/ki@v1.1.11/kit/convert.go (about) 1 // Copyright (c) 2018, 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 kit 6 7 import ( 8 "fmt" 9 "log" 10 "math" 11 "reflect" 12 "strconv" 13 "unicode" 14 15 "github.com/goki/ki/floats" 16 "github.com/goki/ki/ints" 17 ) 18 19 // Sel implements the "mute" function from here 20 // http://blog.vladimirvivien.com/2014/03/hacking-go-filter-values-from-multi.html 21 // provides a way to select a particular return value in a single expression, 22 // without having a separate assignment in between -- I just call it "Sel" as 23 // I'm unlikely to remember how to type a mu 24 func Sel(a ...interface{}) []interface{} { 25 return a 26 } 27 28 // IfaceIsNil checks if an interface value is nil -- the interface itself could be 29 // nil, or the value pointed to by the interface could be nil -- this checks 30 // both, safely 31 // gopy:interface=handle 32 func IfaceIsNil(it interface{}) bool { 33 if it == nil { 34 return true 35 } 36 v := reflect.ValueOf(it) 37 vk := v.Kind() 38 if vk == reflect.Ptr || vk == reflect.Interface || vk == reflect.Map || vk == reflect.Slice || vk == reflect.Func || vk == reflect.Chan { 39 return v.IsNil() 40 } 41 return false 42 } 43 44 // KindIsBasic returns true if the reflect.Kind is a basic type such as Int, Float, etc 45 func KindIsBasic(vk reflect.Kind) bool { 46 if vk >= reflect.Bool && vk <= reflect.Complex128 { 47 return true 48 } 49 return false 50 } 51 52 // ValueIsZero returns true if the reflect.Value is Zero or nil or invalid or 53 // otherwise doesn't have a useful value -- from 54 // https://github.com/golang/go/issues/7501 55 func ValueIsZero(v reflect.Value) bool { 56 if !v.IsValid() { 57 return true 58 } 59 switch v.Kind() { 60 case reflect.Array, reflect.String: 61 return v.Len() == 0 62 case reflect.Bool: 63 return !v.Bool() 64 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 65 return v.Int() == 0 66 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 67 return v.Uint() == 0 68 case reflect.Float32, reflect.Float64: 69 return v.Float() == 0 70 case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: 71 return v.IsNil() 72 case reflect.Func: 73 return v == reflect.Zero(v.Type()) 74 } 75 return false 76 } 77 78 // Convenience functions for converting interface{} (e.g. properties) to given 79 // types uses the "ok" bool mechanism to report failure -- are as robust and 80 // general as possible. 81 // 82 // WARNING: these violate many of the type-safety features of Go but OTOH give 83 // maximum robustness, appropriate for the world of end-user settable 84 // properties, and deal with most common-sense cases, e.g., string <-> number, 85 // etc. nil values return !ok 86 87 // ToBool robustly converts anything to a bool 88 // gopy:interface=handle 89 func ToBool(it interface{}) (bool, bool) { 90 // first check for most likely cases for greatest efficiency 91 switch bt := it.(type) { 92 case bool: 93 return bt, true 94 case *bool: 95 return *bt, true 96 case int: 97 return bt != 0, true 98 case *int: 99 return *bt != 0, true 100 case int32: 101 return bt != 0, true 102 case int64: 103 return bt != 0, true 104 case byte: 105 return bt != 0, true 106 case float64: 107 return bt != 0, true 108 case *float64: 109 return *bt != 0, true 110 case float32: 111 return bt != 0, true 112 case *float32: 113 return *bt != 0, true 114 case string: 115 r, err := strconv.ParseBool(bt) 116 if err != nil { 117 return false, false 118 } 119 return r, true 120 case *string: 121 r, err := strconv.ParseBool(*bt) 122 if err != nil { 123 return false, false 124 } 125 return r, true 126 } 127 128 // then fall back on reflection 129 if IfaceIsNil(it) { 130 return false, false 131 } 132 v := NonPtrValue(reflect.ValueOf(it)) 133 vk := v.Kind() 134 switch { 135 case vk >= reflect.Int && vk <= reflect.Int64: 136 return (v.Int() != 0), true 137 case vk >= reflect.Uint && vk <= reflect.Uint64: 138 return (v.Uint() != 0), true 139 case vk == reflect.Bool: 140 return v.Bool(), true 141 case vk >= reflect.Float32 && vk <= reflect.Float64: 142 return (v.Float() != 0.0), true 143 case vk >= reflect.Complex64 && vk <= reflect.Complex128: 144 return (real(v.Complex()) != 0.0), true 145 case vk == reflect.String: 146 r, err := strconv.ParseBool(v.String()) 147 if err != nil { 148 return false, false 149 } 150 return r, true 151 default: 152 return false, false 153 } 154 } 155 156 // ToInt robustly converts anything to an int64 -- uses the ints.Inter ToInt 157 // interface first if available 158 // gopy:interface=handle 159 func ToInt(it interface{}) (int64, bool) { 160 // first check for most likely cases for greatest efficiency 161 switch it := it.(type) { 162 case bool: 163 if it { 164 return 1, true 165 } 166 return 0, true 167 case *bool: 168 if *it { 169 return 1, true 170 } 171 return 0, true 172 case int: 173 return int64(it), true 174 case *int: 175 return int64(*it), true 176 case int32: 177 return int64(it), true 178 case *int32: 179 return int64(*it), true 180 case int64: 181 return it, true 182 case *int64: 183 return *it, true 184 case byte: 185 return int64(it), true 186 case *byte: 187 return int64(*it), true 188 case float64: 189 return int64(it), true 190 case *float64: 191 return int64(*it), true 192 case float32: 193 return int64(it), true 194 case *float32: 195 return int64(*it), true 196 case string: 197 r, err := strconv.ParseInt(it, 0, 64) 198 if err != nil { 199 return 0, false 200 } 201 return r, true 202 case *string: 203 r, err := strconv.ParseInt(*it, 0, 64) 204 if err != nil { 205 return 0, false 206 } 207 return r, true 208 } 209 210 // then fall back on reflection 211 if IfaceIsNil(it) { 212 return 0, false 213 } 214 if inter, ok := it.(ints.Inter); ok { 215 return inter.Int(), true 216 } 217 v := NonPtrValue(reflect.ValueOf(it)) 218 vk := v.Kind() 219 switch { 220 case vk >= reflect.Int && vk <= reflect.Int64: 221 return v.Int(), true 222 case vk >= reflect.Uint && vk <= reflect.Uint64: 223 return int64(v.Uint()), true 224 case vk == reflect.Bool: 225 if v.Bool() { 226 return 1, true 227 } 228 return 0, true 229 case vk >= reflect.Float32 && vk <= reflect.Float64: 230 return int64(v.Float()), true 231 case vk >= reflect.Complex64 && vk <= reflect.Complex128: 232 return int64(real(v.Complex())), true 233 case vk == reflect.String: 234 r, err := strconv.ParseInt(v.String(), 0, 64) 235 if err != nil { 236 return 0, false 237 } 238 return r, true 239 default: 240 return 0, false 241 } 242 } 243 244 // ToFloat robustly converts anything to a Float64 -- uses the floats.Floater Float() 245 // interface first if available 246 // gopy:interface=handle 247 func ToFloat(it interface{}) (float64, bool) { 248 // first check for most likely cases for greatest efficiency 249 switch it := it.(type) { 250 case bool: 251 if it { 252 return 1, true 253 } 254 return 0, true 255 case *bool: 256 if *it { 257 return 1, true 258 } 259 return 0, true 260 case int: 261 return float64(it), true 262 case *int: 263 return float64(*it), true 264 case int32: 265 return float64(it), true 266 case *int32: 267 return float64(*it), true 268 case int64: 269 return float64(it), true 270 case *int64: 271 return float64(*it), true 272 case byte: 273 return float64(it), true 274 case *byte: 275 return float64(*it), true 276 case float64: 277 return it, true 278 case *float64: 279 return *it, true 280 case float32: 281 return float64(it), true 282 case *float32: 283 return float64(*it), true 284 case string: 285 r, err := strconv.ParseFloat(it, 64) 286 if err != nil { 287 return 0.0, false 288 } 289 return r, true 290 case *string: 291 r, err := strconv.ParseFloat(*it, 64) 292 if err != nil { 293 return 0.0, false 294 } 295 return r, true 296 } 297 298 if floater, ok := it.(floats.Floater); ok { 299 return floater.Float(), true 300 } 301 // then fall back on reflection 302 if IfaceIsNil(it) { 303 return 0.0, false 304 } 305 v := NonPtrValue(reflect.ValueOf(it)) 306 vk := v.Kind() 307 switch { 308 case vk >= reflect.Int && vk <= reflect.Int64: 309 return float64(v.Int()), true 310 case vk >= reflect.Uint && vk <= reflect.Uint64: 311 return float64(v.Uint()), true 312 case vk == reflect.Bool: 313 if v.Bool() { 314 return 1.0, true 315 } 316 return 0.0, true 317 case vk >= reflect.Float32 && vk <= reflect.Float64: 318 return v.Float(), true 319 case vk >= reflect.Complex64 && vk <= reflect.Complex128: 320 return real(v.Complex()), true 321 case vk == reflect.String: 322 r, err := strconv.ParseFloat(v.String(), 64) 323 if err != nil { 324 return 0.0, false 325 } 326 return r, true 327 default: 328 return 0.0, false 329 } 330 } 331 332 // ToFloat32 robustly converts anything to a Float32 -- uses the floats.Floater Float() 333 // interface first if available 334 // gopy:interface=handle 335 func ToFloat32(it interface{}) (float32, bool) { 336 // first check for most likely cases for greatest efficiency 337 switch it := it.(type) { 338 case bool: 339 if it { 340 return 1, true 341 } 342 return 0, true 343 case *bool: 344 if *it { 345 return 1, true 346 } 347 return 0, true 348 case int: 349 return float32(it), true 350 case *int: 351 return float32(*it), true 352 case int32: 353 return float32(it), true 354 case *int32: 355 return float32(*it), true 356 case int64: 357 return float32(it), true 358 case *int64: 359 return float32(*it), true 360 case byte: 361 return float32(it), true 362 case *byte: 363 return float32(*it), true 364 case float64: 365 return float32(it), true 366 case *float64: 367 return float32(*it), true 368 case float32: 369 return it, true 370 case *float32: 371 return *it, true 372 case string: 373 r, err := strconv.ParseFloat(it, 32) 374 if err != nil { 375 return 0.0, false 376 } 377 return float32(r), true 378 case *string: 379 r, err := strconv.ParseFloat(*it, 32) 380 if err != nil { 381 return 0.0, false 382 } 383 return float32(r), true 384 } 385 386 if floater, ok := it.(floats.Floater); ok { 387 return float32(floater.Float()), true 388 } 389 // then fall back on reflection 390 if IfaceIsNil(it) { 391 return float32(0.0), false 392 } 393 v := NonPtrValue(reflect.ValueOf(it)) 394 vk := v.Kind() 395 switch { 396 case vk >= reflect.Int && vk <= reflect.Int64: 397 return float32(v.Int()), true 398 case vk >= reflect.Uint && vk <= reflect.Uint64: 399 return float32(v.Uint()), true 400 case vk == reflect.Bool: 401 if v.Bool() { 402 return 1.0, true 403 } 404 return 0.0, true 405 case vk >= reflect.Float32 && vk <= reflect.Float64: 406 return float32(v.Float()), true 407 case vk >= reflect.Complex64 && vk <= reflect.Complex128: 408 return float32(real(v.Complex())), true 409 case vk == reflect.String: 410 r, err := strconv.ParseFloat(v.String(), 32) 411 if err != nil { 412 return float32(0.0), false 413 } 414 return float32(r), true 415 default: 416 return float32(0.0), false 417 } 418 } 419 420 // ToString robustly converts anything to a String -- because Stringer is so 421 // ubiquitous, and we fall back to fmt.Sprintf(%v) in worst case, this should 422 // definitely work in all cases, so there is no bool return value 423 // gopy:interface=handle 424 func ToString(it interface{}) string { 425 // first check for most likely cases for greatest efficiency 426 switch it := it.(type) { 427 case string: 428 return it 429 case *string: 430 return *it 431 case bool: 432 if it { 433 return "true" 434 } 435 return "false" 436 case *bool: 437 if *it { 438 return "true" 439 } 440 return "false" 441 case int: 442 return strconv.FormatInt(int64(it), 10) 443 case *int: 444 return strconv.FormatInt(int64(*it), 10) 445 case int32: 446 return strconv.FormatInt(int64(it), 10) 447 case *int32: 448 return strconv.FormatInt(int64(*it), 10) 449 case int64: 450 return strconv.FormatInt(it, 10) 451 case *int64: 452 return strconv.FormatInt(*it, 10) 453 case byte: 454 return strconv.FormatInt(int64(it), 10) 455 case *byte: 456 return strconv.FormatInt(int64(*it), 10) 457 case float64: 458 return strconv.FormatFloat(it, 'G', -1, 64) 459 case *float64: 460 return strconv.FormatFloat(*it, 'G', -1, 64) 461 case float32: 462 return strconv.FormatFloat(float64(it), 'G', -1, 32) 463 case *float32: 464 return strconv.FormatFloat(float64(*it), 'G', -1, 32) 465 case uintptr: 466 return fmt.Sprintf("%#x", uintptr(it)) 467 case *uintptr: 468 return fmt.Sprintf("%#x", uintptr(*it)) 469 } 470 471 if stringer, ok := it.(fmt.Stringer); ok { 472 return stringer.String() 473 } 474 if IfaceIsNil(it) { 475 return "nil" 476 } 477 v := NonPtrValue(reflect.ValueOf(it)) 478 vk := v.Kind() 479 switch { 480 case vk >= reflect.Int && vk <= reflect.Int64: 481 return strconv.FormatInt(v.Int(), 10) 482 case vk >= reflect.Uint && vk <= reflect.Uint64: 483 return strconv.FormatUint(v.Uint(), 10) 484 case vk == reflect.Bool: 485 return strconv.FormatBool(v.Bool()) 486 case vk >= reflect.Float32 && vk <= reflect.Float64: 487 return strconv.FormatFloat(v.Float(), 'G', -1, 64) 488 case vk >= reflect.Complex64 && vk <= reflect.Complex128: 489 cv := v.Complex() 490 rv := strconv.FormatFloat(real(cv), 'G', -1, 64) + "," + strconv.FormatFloat(imag(cv), 'G', -1, 64) 491 return rv 492 case vk == reflect.String: 493 return v.String() 494 case vk == reflect.Slice: 495 eltyp := SliceElType(it) 496 if eltyp.Kind() == reflect.Uint8 { // []byte 497 return string(it.([]byte)) 498 } 499 fallthrough 500 default: 501 return fmt.Sprintf("%v", it) 502 } 503 } 504 505 // ToStringPrec robustly converts anything to a String using given precision 506 // for converting floating values -- using a value like 6 truncates the 507 // nuisance random imprecision of actual floating point values due to the 508 // fact that they are represented with binary bits. See ToString 509 // for more info. 510 // gopy:interface=handle 511 func ToStringPrec(it interface{}, prec int) string { 512 if IfaceIsNil(it) { 513 return "nil" 514 } 515 if stringer, ok := it.(fmt.Stringer); ok { 516 return stringer.String() 517 } 518 v := NonPtrValue(reflect.ValueOf(it)) 519 vk := v.Kind() 520 switch { 521 case vk >= reflect.Int && vk <= reflect.Int64: 522 return strconv.FormatInt(v.Int(), 10) 523 case vk >= reflect.Uint && vk <= reflect.Uint64: 524 return strconv.FormatUint(v.Uint(), 10) 525 case vk == reflect.Bool: 526 return strconv.FormatBool(v.Bool()) 527 case vk >= reflect.Float32 && vk <= reflect.Float64: 528 return strconv.FormatFloat(v.Float(), 'G', prec, 64) 529 case vk >= reflect.Complex64 && vk <= reflect.Complex128: 530 cv := v.Complex() 531 rv := strconv.FormatFloat(real(cv), 'G', prec, 64) + "," + strconv.FormatFloat(imag(cv), 'G', prec, 64) 532 return rv 533 case vk == reflect.String: 534 return v.String() 535 case vk == reflect.Slice: 536 eltyp := SliceElType(it) 537 if eltyp.Kind() == reflect.Uint8 { // []byte 538 return string(it.([]byte)) 539 } 540 fallthrough 541 default: 542 return fmt.Sprintf("%v", it) 543 } 544 } 545 546 // SetRobust robustly sets the to value from the from value -- to must be a 547 // pointer-to -- only for basic field values -- use copier package for more 548 // complex cases 549 // gopy:interface=handle 550 func SetRobust(to, frm interface{}) bool { 551 if IfaceIsNil(to) { 552 return false 553 } 554 v := reflect.ValueOf(to) 555 vnp := NonPtrValue(v) 556 if !vnp.IsValid() { 557 return false 558 } 559 typ := vnp.Type() 560 vp := OnePtrValue(vnp) 561 vk := vnp.Kind() 562 if !vp.Elem().CanSet() { 563 log.Printf("ki.SetRobust 'to' cannot be set -- must be a variable or field, not a const or tmp or other value that cannot be set. Value info: %v\n", vp) 564 return false 565 } 566 switch { 567 case vk >= reflect.Int && vk <= reflect.Int64: 568 fm, ok := ToInt(frm) 569 if ok { 570 vp.Elem().Set(reflect.ValueOf(fm).Convert(typ)) 571 return true 572 } 573 case vk >= reflect.Uint && vk <= reflect.Uint64: 574 fm, ok := ToInt(frm) 575 if ok { 576 vp.Elem().Set(reflect.ValueOf(fm).Convert(typ)) 577 return true 578 } 579 case vk == reflect.Bool: 580 fm, ok := ToBool(frm) 581 if ok { 582 vp.Elem().Set(reflect.ValueOf(fm).Convert(typ)) 583 return true 584 } 585 case vk >= reflect.Float32 && vk <= reflect.Float64: 586 fm, ok := ToFloat(frm) 587 if ok { 588 vp.Elem().Set(reflect.ValueOf(fm).Convert(typ)) 589 return true 590 } 591 case vk >= reflect.Complex64 && vk <= reflect.Complex128: 592 // cv := v.Complex() 593 // rv := strconv.FormatFloat(real(cv), 'G', -1, 64) + "," + strconv.FormatFloat(imag(cv), 'G', -1, 64) 594 // return rv, true 595 case vk == reflect.String: // todo: what about []byte? 596 fm := ToString(frm) 597 vp.Elem().Set(reflect.ValueOf(fm).Convert(typ)) 598 return true 599 } 600 601 fv := reflect.ValueOf(frm) 602 // Just set it if possible to assign 603 if fv.Type().AssignableTo(typ) { 604 vp.Elem().Set(fv) 605 return true 606 } 607 return false 608 } 609 610 // SetMapRobust robustly sets a map value using reflect.Value representations 611 // of the map, key, and value elements, ensuring that the proper types are 612 // used for the key and value elements using sensible conversions. 613 // map value must be a valid map value -- that is not checked. 614 func SetMapRobust(mp, ky, val reflect.Value) bool { 615 mtyp := mp.Type() 616 if mtyp.Kind() != reflect.Map { 617 log.Printf("ki.SetMapRobust: map arg is not map, is: %v\n", mtyp.String()) 618 return false 619 } 620 if !mp.CanSet() { 621 log.Printf("ki.SetMapRobust: map arg is not settable: %v\n", mtyp.String()) 622 return false 623 } 624 ktyp := mtyp.Key() 625 etyp := mtyp.Elem() 626 if etyp.Kind() == val.Kind() && ky.Kind() == ktyp.Kind() { 627 mp.SetMapIndex(ky, val) 628 return true 629 } 630 if ky.Kind() == ktyp.Kind() { 631 mp.SetMapIndex(ky, val.Convert(etyp)) 632 return true 633 } 634 if etyp.Kind() == val.Kind() { 635 mp.SetMapIndex(ky.Convert(ktyp), val) 636 return true 637 } 638 mp.SetMapIndex(ky.Convert(ktyp), val.Convert(etyp)) 639 return true 640 } 641 642 // MakeMap makes a map that is actually addressable, getting around the hidden 643 // interface{} that reflect.MakeMap makes, by calling UnhideIfaceValue (from ptrs.go) 644 func MakeMap(typ reflect.Type) reflect.Value { 645 return UnhideIfaceValue(reflect.MakeMap(typ)) 646 } 647 648 // MakeSlice makes a map that is actually addressable, getting around the hidden 649 // interface{} that reflect.MakeSlice makes, by calling UnhideIfaceValue (from ptrs.go) 650 func MakeSlice(typ reflect.Type, len, cap int) reflect.Value { 651 return UnhideIfaceValue(reflect.MakeSlice(typ, len, cap)) 652 } 653 654 // CloneToType creates a new object of given type, and uses SetRobust to copy 655 // an existing value (of perhaps another type) into it -- only expected to 656 // work for basic types 657 func CloneToType(typ reflect.Type, val interface{}) reflect.Value { 658 if NonPtrType(typ).Kind() == reflect.Map { 659 return MakeMap(typ) 660 } else if NonPtrType(typ).Kind() == reflect.Slice { 661 return MakeSlice(typ, 0, 0) 662 } 663 vn := reflect.New(typ) 664 evi := vn.Interface() 665 SetRobust(evi, val) 666 return vn 667 } 668 669 // MakeOfType creates a new object of given type with appropriate magic foo to 670 // make it usable 671 func MakeOfType(typ reflect.Type) reflect.Value { 672 if NonPtrType(typ).Kind() == reflect.Map { 673 return MakeMap(typ) 674 } else if NonPtrType(typ).Kind() == reflect.Slice { 675 return MakeSlice(typ, 0, 0) 676 } 677 vn := reflect.New(typ) 678 return vn 679 } 680 681 //////////////////////////////////////////////////////////////////////////////////////// 682 // Min / Max for other types.. 683 684 // math provides Max/Min for 64bit -- these are for specific subtypes 685 686 func Max32(a, b float32) float32 { 687 if a > b { 688 return a 689 } 690 return b 691 } 692 693 func Min32(a, b float32) float32 { 694 if a < b { 695 return a 696 } 697 return b 698 } 699 700 // minimum excluding 0 701 func MinPos(a, b float64) float64 { 702 if a > 0.0 && b > 0.0 { 703 return math.Min(a, b) 704 } else if a > 0.0 { 705 return a 706 } else if b > 0.0 { 707 return b 708 } 709 return a 710 } 711 712 // minimum excluding 0 713 func MinPos32(a, b float32) float32 { 714 if a > 0.0 && b > 0.0 { 715 return Min32(a, b) 716 } else if a > 0.0 { 717 return a 718 } else if b > 0.0 { 719 return b 720 } 721 return a 722 } 723 724 // HasUpperCase returns true if string has an upper-case letter 725 func HasUpperCase(str string) bool { 726 for _, r := range str { 727 if unicode.IsUpper(r) { 728 return true 729 } 730 } 731 return false 732 }