github.com/avicd/go-utilx@v0.1.0/refx/op.go (about) 1 package refx 2 3 import ( 4 "fmt" 5 "github.com/avicd/go-utilx/conv" 6 "github.com/avicd/go-utilx/logx" 7 "math/big" 8 "reflect" 9 ) 10 11 const ( 12 CmpNeq = -2 13 CmpLss = -1 14 CmpEq = 0 15 CmpGtr = 1 16 ) 17 18 func Zero() reflect.Value { 19 return reflect.Value{} 20 } 21 22 func ZeroOf(vl any) reflect.Value { 23 return reflect.New(TypeOf(vl)).Elem() 24 } 25 26 func ValueOf(vl any) reflect.Value { 27 switch tmp := vl.(type) { 28 case reflect.Value: 29 return tmp 30 case *reflect.Value: 31 return *tmp 32 default: 33 return reflect.ValueOf(vl) 34 } 35 } 36 37 func TypeOf(vl any) reflect.Type { 38 var value reflect.Value 39 switch tmp := vl.(type) { 40 case reflect.Type: 41 return tmp 42 case reflect.Value: 43 value = tmp 44 case *reflect.Value: 45 value = *tmp 46 } 47 if value.IsValid() { 48 return value.Type() 49 } else { 50 return reflect.TypeOf(vl) 51 } 52 } 53 54 func KindOf(vl any) reflect.Kind { 55 switch tmp := vl.(type) { 56 case reflect.Value: 57 return tmp.Kind() 58 case *reflect.Value: 59 return tmp.Kind() 60 case reflect.Type: 61 if tmp != nil { 62 return tmp.Kind() 63 } else { 64 return reflect.Invalid 65 } 66 default: 67 if tp := reflect.TypeOf(vl); tp != nil { 68 return tp.Kind() 69 } 70 } 71 return reflect.Invalid 72 } 73 74 func IndirectKind(val any) reflect.Kind { 75 if IsPointer(val) || IsInterface(val) { 76 switch tmp := val.(type) { 77 case reflect.Value: 78 return KindOf(IndirectType(tmp)) 79 case *reflect.Value: 80 return KindOf(IndirectType(*tmp)) 81 case reflect.Type: 82 return KindOf(IndirectType(tmp)) 83 default: 84 return KindOf(IndirectType(val)) 85 } 86 } 87 return KindOf(val) 88 } 89 90 func Indirect(vl any) reflect.Value { 91 buf := ValueOf(vl) 92 for buf.Kind() == reflect.Pointer || buf.Kind() == reflect.Interface { 93 buf = buf.Elem() 94 } 95 return buf 96 } 97 98 func IndirectType(vl any) reflect.Type { 99 buf := TypeOf(vl) 100 for buf != nil { 101 if buf.Kind() == reflect.Pointer { 102 buf = buf.Elem() 103 } else { 104 break 105 } 106 } 107 return buf 108 } 109 110 func NewOf(vl any) reflect.Value { 111 target := TypeOf(vl) 112 if IsInvalid(target) { 113 return Zero() 114 } 115 if target.Kind() == reflect.Pointer { 116 p := reflect.New(target) 117 p.Elem().Set(NewOf(target.Elem()).Addr()) 118 return p.Elem() 119 } else if target.Kind() == reflect.Map { 120 return reflect.MakeMap(target) 121 } else { 122 return reflect.New(target).Elem() 123 } 124 } 125 126 func AddrAbleOf(vl any) (reflect.Value, bool) { 127 buf := ValueOf(vl) 128 for (IsPointer(buf) || IsInterface(buf)) && !buf.CanAddr() { 129 buf = buf.Elem() 130 } 131 if buf.CanAddr() { 132 return buf, true 133 } 134 return reflect.Value{}, false 135 } 136 137 func Assign(dest any, vl any) bool { 138 target, ok := AddrAbleOf(dest) 139 if ok { 140 target.Set(NewOf(target)) 141 } else { 142 logx.Fatal("dest is unaddressable") 143 } 144 if IsNil(vl) { 145 return false 146 } 147 value := ValueOf(vl) 148 if IsPointer(target) { 149 if target.Type() == value.Type() { 150 target.Set(value) 151 return true 152 } else if target.Type().Elem() == value.Type() { 153 buf := NewOf(target) 154 buf.Elem().Set(value) 155 target.Set(buf) 156 return true 157 } 158 } else if IsInterface(target) { 159 if IsPointer(value) { 160 if value.CanConvert(TypeOf(target.Type())) { 161 target.Set(value) 162 return true 163 } 164 } else { 165 pointer := reflect.New(TypeOf(value)) 166 if pointer.CanConvert(target.Type()) { 167 pointer.Elem().Set(value) 168 target.Set(pointer) 169 return true 170 } 171 } 172 } 173 el := Indirect(value) 174 if target.Type() == el.Type() { 175 target.Set(el) 176 return true 177 } 178 failed := false 179 if IsNumber(target) { 180 if IsString(el) { 181 if IsGeneralInt(target) { 182 num := conv.ParseInt(el.String()) 183 if target.CanInt() { 184 target.SetInt(num) 185 } else { 186 target.SetUint(uint64(num)) 187 } 188 } else { 189 target.SetFloat(conv.ParseFloat(el.String())) 190 } 191 return true 192 } 193 194 if target.CanInt() { 195 if el.CanInt() { 196 target.SetInt(el.Int()) 197 } else if el.CanUint() { 198 target.SetInt(int64(el.Uint())) 199 } else if el.CanFloat() { 200 target.SetInt(int64(el.Float())) 201 } else { 202 failed = true 203 } 204 } else if target.CanUint() { 205 if el.CanUint() { 206 target.SetUint(el.Uint()) 207 } else if el.CanInt() { 208 target.SetUint(uint64(el.Int())) 209 } else if el.CanFloat() { 210 target.SetUint(uint64(el.Float())) 211 } else { 212 failed = true 213 } 214 } else if target.CanFloat() { 215 if el.CanFloat() { 216 target.SetFloat(el.Float()) 217 } else if el.CanInt() { 218 target.SetFloat(float64(el.Int())) 219 } else if el.CanUint() { 220 target.SetFloat(float64(el.Uint())) 221 } else { 222 failed = true 223 } 224 } 225 } else if IsString(target) { 226 if IsString(el) { 227 target.SetString(el.String()) 228 } else { 229 target.SetString(fmt.Sprintf("%v", vl)) 230 } 231 } else if IsBool(target) { 232 if IsBool(el) { 233 target.SetBool(el.Bool()) 234 } else { 235 target.SetBool(!el.IsZero()) 236 } 237 } else { 238 failed = true 239 } 240 if failed { 241 logx.Fatalf("can't assign %s to %s", TypeOf(vl), TypeOf(dest)) 242 } 243 return true 244 } 245 246 func Clone(dest any, src any) { 247 var target reflect.Value 248 if buf, ok := AddrAbleOf(dest); ok { 249 buf.Set(NewOf(buf)) 250 target = Indirect(buf) 251 } else { 252 logx.Fatal("dest is unaddressable") 253 } 254 el := Indirect(src) 255 if IsNil(el) { 256 return 257 } 258 if el.Type() != target.Type() { 259 logx.Fatalf("can't clone %s into %s", el.Type(), target.Type()) 260 } 261 if IsBasic(target) { 262 target.Set(el) 263 return 264 } 265 switch el.Kind() { 266 case reflect.Slice, reflect.Array: 267 for i := 0; i < el.Len(); i++ { 268 sf := el.Index(i) 269 if !IsBasic(sf) { 270 newVal := NewOf(el.Type().Elem()) 271 Clone(newVal.Addr(), sf) 272 sf = newVal 273 } 274 newTarget := reflect.Append(target, sf) 275 target.Set(newTarget) 276 } 277 case reflect.Struct: 278 for i := 0; i < el.Type().NumField(); i++ { 279 tf := el.Type().Field(i) 280 if !tf.IsExported() { 281 continue 282 } 283 sf := el.Field(i) 284 if !IsBasic(tf.Type) { 285 target.Field(i).Set(sf) 286 } else { 287 newVal := NewOf(tf.Type) 288 Clone(newVal.Addr(), sf) 289 sf = newVal 290 } 291 target.Field(i).Set(sf) 292 } 293 case reflect.Map: 294 for itr := el.MapRange(); itr.Next(); { 295 sf := itr.Value() 296 if IsBasic(sf) { 297 target.SetMapIndex(itr.Key(), sf) 298 } else { 299 var newVal reflect.Value 300 if IsInterface(el.Type().Elem()) { 301 newVal = NewOf(sf.Elem()) 302 } else { 303 newVal = NewOf(el.Type().Elem()) 304 } 305 Clone(newVal.Addr(), sf) 306 target.SetMapIndex(itr.Key(), newVal) 307 } 308 } 309 } 310 } 311 312 func Merge(dest any, src any) { 313 if IsNil(src) { 314 return 315 } 316 to := Indirect(dest) 317 if IsBasic(to) || IsList(to) || IsNil(to) { 318 if target, ok := AddrAbleOf(dest); ok { 319 if IsNil(target) { 320 target.Set(NewOf(target)) 321 } 322 to = Indirect(target) 323 } else { 324 logx.Fatal("dest is unaddressable") 325 } 326 } 327 from := Indirect(src) 328 329 if !IsList(to) && !IsList(from) && to.Type() != from.Type() { 330 logx.Fatalf("can't merge %s into %s", TypeOf(src), TypeOf(dest)) 331 } 332 switch to.Kind() { 333 case reflect.Slice: 334 buf := NewOf(to) 335 buf.Set(to) 336 for i := 0; i < from.Len(); i++ { 337 sf := from.Index(i) 338 buf = reflect.Append(buf, sf) 339 } 340 to.Set(buf) 341 case reflect.Array: 342 for i := 0; i < from.Len() && i < to.Len(); i++ { 343 sf := from.Index(i) 344 if IsInterface(sf) { 345 sf = sf.Elem() 346 } 347 if !sf.IsZero() { 348 to.Index(i).Set(sf) 349 } 350 } 351 case reflect.Struct: 352 for i := 0; i < from.Type().NumField(); i++ { 353 tf := from.Type().Field(i) 354 if !tf.IsExported() { 355 continue 356 } 357 left := to.Field(i) 358 right := from.Field(i) 359 if IsBasic(tf.Type) { 360 if right.IsValid() && !right.IsZero() { 361 left.Set(right) 362 } 363 } else if !right.IsZero() { 364 if IsNil(left) { 365 left.Set(NewOf(tf.Type)) 366 } 367 Merge(left.Addr(), right) 368 } 369 } 370 case reflect.Map: 371 for itr := from.MapRange(); itr.Next(); { 372 left := to.MapIndex(itr.Key()) 373 right := itr.Value() 374 if IsInterface(left) { 375 left = left.Elem() 376 } 377 if IsInterface(right) { 378 right = right.Elem() 379 } 380 if left.IsValid() { 381 if !IsBasic(left) && left.Type() == right.Type() { 382 var newVal reflect.Value 383 if IsInterface(from.Type().Elem()) { 384 newVal = NewOf(left) 385 } else { 386 newVal = NewOf(from.Type().Elem()) 387 } 388 newVal.Set(left) 389 Merge(newVal.Addr(), right) 390 to.SetMapIndex(itr.Key(), newVal) 391 } else if !right.IsZero() { 392 to.SetMapIndex(itr.Key(), right) 393 } 394 } else { 395 to.SetMapIndex(itr.Key(), right) 396 } 397 } 398 default: 399 if !from.IsZero() { 400 to.Set(from) 401 } 402 } 403 } 404 405 func FieldOf(src any, props ...any) (reflect.Value, bool) { 406 vl := ValueOf(src) 407 if IsBasic(vl) || len(props) < 1 || IsNil(vl) { 408 return Zero(), false 409 } 410 buf := vl 411 for _, key := range props { 412 el := Indirect(buf) 413 switch el.Kind() { 414 case reflect.Map: 415 index := AsOf(el.Type().Key(), key) 416 buf = el.MapIndex(index) 417 if IsInterface(buf) { 418 buf = buf.Elem() 419 } 420 case reflect.Struct: 421 name := AsString(key) 422 if sf, ok := el.Type().FieldByName(name); ok && sf.IsExported() { 423 buf = el.FieldByName(name) 424 } else { 425 return Zero(), false 426 } 427 case reflect.Slice, reflect.Array: 428 index := AsInt(key) 429 if index >= 0 && index < el.Len() { 430 buf = el.Index(index) 431 } else { 432 return Zero(), false 433 } 434 default: 435 return Zero(), false 436 } 437 if !buf.IsValid() || !buf.CanInterface() { 438 return Zero(), false 439 } 440 } 441 return buf, true 442 } 443 444 func TypeOfField(vl any, props ...any) (reflect.Type, bool) { 445 if _, ok := vl.(reflect.Type); !ok && !IsNil(vl) { 446 if sf, exist := FieldOf(vl, props...); exist { 447 return TypeOf(sf), true 448 } 449 } 450 buf := TypeOf(vl) 451 if len(props) < 1 || buf == nil { 452 return nil, false 453 } 454 for _, key := range props { 455 buf = IndirectType(buf) 456 switch buf.Kind() { 457 case reflect.Struct: 458 name := AsString(key) 459 if sf, ok := buf.FieldByName(name); ok { 460 buf = sf.Type 461 } else { 462 return nil, false 463 } 464 case reflect.Array, reflect.Slice, reflect.Map: 465 buf = buf.Elem() 466 default: 467 return nil, false 468 } 469 } 470 return buf, true 471 } 472 473 func TypeOfId(vl any, ident string) (reflect.Type, bool) { 474 props := AsList(conv.StrToArr(ident, ".")) 475 return TypeOfField(vl, props...) 476 } 477 478 func PropOf(src any, props ...any) (any, bool) { 479 vl := ValueOf(src) 480 if IsBasic(vl) || len(props) < 1 || IsNil(vl) { 481 return nil, false 482 } 483 if value, ok := FieldOf(vl, props...); ok { 484 return value.Interface(), true 485 } else { 486 return nil, false 487 } 488 } 489 490 func PropOfId(src any, ident string) (any, bool) { 491 if IsBasic(src) || IsNil(src) { 492 return nil, false 493 } 494 props := AsList(conv.StrToArr(ident, ".")) 495 if val, ok := PropOf(src, props...); ok { 496 return val, true 497 } else if IsMap(src) && len(props) > 1 { 498 return PropOf(src, ident) 499 } else { 500 return nil, false 501 } 502 } 503 504 func Set(dest any, vl any, props ...any) bool { 505 if IsBasic(dest) { 506 return Assign(dest, vl) 507 } 508 value := ValueOf(vl) 509 buf := Indirect(dest) 510 if IsNil(buf) || IsArray(dest) { 511 if target, ok := AddrAbleOf(dest); !ok { 512 logx.Fatal("dest is unaddressable") 513 } else { 514 buf = target 515 } 516 } 517 for i, key := range props { 518 if IsNil(buf) { 519 buf.Set(NewOf(buf)) 520 } 521 el := Indirect(buf) 522 switch el.Kind() { 523 case reflect.Map: 524 index := AsOf(el.Type().Key(), key) 525 buf = el.MapIndex(index) 526 if len(props)-i > 1 { 527 if !buf.IsValid() { 528 if IsInterface(el.Type().Elem()) { 529 next := props[i+1] 530 if IsNumber(next) || IsString(next) { 531 buf = NewOf(TMapStrAny) 532 } else { 533 buf = NewOf(reflect.MapOf(TypeOf(next), el.Type().Elem())) 534 } 535 } else { 536 buf = NewOf(el.Type().Elem()) 537 } 538 el.SetMapIndex(index, buf) 539 continue 540 } 541 } else { 542 el.SetMapIndex(index, value) 543 break 544 } 545 case reflect.Struct: 546 name := AsString(key) 547 if tf, ok := el.Type().FieldByName(name); ok && tf.IsExported() { 548 buf = el.FieldByName(name) 549 if IsPointer(buf) && buf.IsNil() { 550 buf.Set(NewOf(tf.Type)) 551 } 552 } else { 553 return false 554 } 555 case reflect.Slice, reflect.Array: 556 index := AsInt(key) 557 if index >= 0 && index < el.Len() { 558 buf = el.Index(index) 559 } else { 560 return false 561 } 562 } 563 if i == len(props)-1 { 564 if buf.IsValid() { 565 Assign(buf.Addr(), value) 566 } else { 567 return false 568 } 569 } 570 } 571 return true 572 } 573 574 func SetById(dest any, vl any, ident string) bool { 575 props := AsList(conv.StrToArr(ident, ".")) 576 if ok := Set(dest, vl, props...); ok { 577 return true 578 } else if IsMap(dest) && len(props) > 1 { 579 return Set(dest, vl, ident) 580 } else { 581 return false 582 } 583 } 584 585 func MethodOf(target any, props ...any) (reflect.Value, bool) { 586 vl := ValueOf(target) 587 if !vl.IsValid() || IsBasic(vl) || len(props) < 1 { 588 return Zero(), false 589 } 590 owner := vl 591 level := len(props) 592 if level > 1 { 593 if sf, ok := FieldOf(owner, props[:level-1]...); ok { 594 owner = sf 595 } else { 596 return Zero(), false 597 } 598 } 599 name := AsString(props[level-1]) 600 method := owner.MethodByName(name) 601 if method.IsValid() && method.CanInterface() { 602 return method, true 603 } 604 return Zero(), false 605 } 606 607 func MethodOfId(target any, ident string) (reflect.Value, bool) { 608 props := AsList(conv.StrToArr(ident, ".")) 609 return MethodOf(target, props...) 610 } 611 612 func ForEach(target any, fn func(key any, val any)) { 613 if IsBasic(target) || IsNil(target) { 614 return 615 } 616 vl := ValueOf(target) 617 el := Indirect(vl) 618 switch el.Kind() { 619 case reflect.Map: 620 for itr := el.MapRange(); itr.Next(); { 621 fn(itr.Key().Interface(), itr.Value().Interface()) 622 } 623 case reflect.Slice, reflect.Array: 624 for i := 0; i < el.Len(); i++ { 625 fn(i, el.Index(i).Interface()) 626 } 627 case reflect.Struct: 628 for i := 0; i < el.Type().NumField(); i++ { 629 tf := el.Type().Field(i) 630 field := el.Field(i) 631 if !tf.IsExported() { 632 continue 633 } 634 fn(tf.Name, field.Interface()) 635 } 636 } 637 } 638 639 func Cmp(x any, y any) int { 640 if IsNumber(x) && IsNumber(y) { 641 return big.NewFloat(AsFloat64(x)).Cmp(big.NewFloat(AsFloat64(y))) 642 } else if IsString(x) && IsString(y) { 643 str1 := AsString(x) 644 str2 := AsString(y) 645 if str1 == str2 { 646 return CmpEq 647 } else if str1 > str2 { 648 return CmpGtr 649 } else { 650 return CmpLss 651 } 652 } else if reflect.DeepEqual(x, y) { 653 return CmpEq 654 } 655 return CmpNeq 656 }