github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/ztype/conv.go (about) 1 package ztype 2 3 import ( 4 "errors" 5 "fmt" 6 "reflect" 7 "strconv" 8 "strings" 9 10 "github.com/sohaha/zlsgo/zreflect" 11 ) 12 13 type Conver struct { 14 MatchName func(mapKey, fieldName string) bool 15 ConvHook func(i reflect.Value, o reflect.Type) (reflect.Value, error) 16 TagName string 17 ZeroFields bool 18 Squash bool 19 Deep bool 20 Merge bool 21 } 22 23 var conv = Conver{TagName: tagName, Squash: true, MatchName: strings.EqualFold} 24 25 func To(input, out interface{}, opt ...func(*Conver)) error { 26 return ValueConv(input, zreflect.ValueOf(out), opt...) 27 } 28 29 func ValueConv(input interface{}, out reflect.Value, opt ...func(*Conver)) error { 30 o := conv 31 for _, f := range opt { 32 f(&o) 33 } 34 if out.Kind() != reflect.Ptr { 35 return errors.New("out must be a pointer") 36 } 37 if !out.Elem().CanAddr() { 38 return errors.New("out must be addressable (a pointer)") 39 } 40 return o.to("input", input, out) 41 } 42 43 func (d *Conver) to(name string, input interface{}, outVal reflect.Value) error { 44 var inputVal reflect.Value 45 if input != nil { 46 inputVal = zreflect.ValueOf(input) 47 if inputVal.Kind() == reflect.Ptr && inputVal.IsNil() { 48 input = nil 49 } 50 } 51 52 t := outVal.Type() 53 if input == nil { 54 if d.ZeroFields { 55 outVal.Set(reflect.Zero(t)) 56 } 57 return nil 58 } 59 60 if !inputVal.IsValid() { 61 outVal.Set(reflect.Zero(t)) 62 return nil 63 } 64 65 var err error 66 outputKind := zreflect.GetAbbrKind(outVal) 67 68 if d.ConvHook != nil { 69 if i, err := d.ConvHook(inputVal, t); err != nil { 70 return err 71 } else { 72 input = i.Interface() 73 } 74 } 75 76 switch outputKind { 77 case reflect.Bool: 78 outVal.SetBool(ToBool(input)) 79 case reflect.Interface: 80 err = d.basic(name, input, outVal) 81 case reflect.String: 82 outVal.SetString(ToString(input)) 83 case reflect.Int: 84 outVal.SetInt(ToInt64(input)) 85 case reflect.Uint: 86 outVal.SetUint(ToUint64(input)) 87 case reflect.Float64: 88 outVal.SetFloat(ToFloat64(input)) 89 case reflect.Struct: 90 err = d.toStruct(name, input, outVal) 91 case reflect.Map: 92 err = d.toMap(name, input, outVal) 93 case reflect.Ptr: 94 err = d.toPtr(name, input, outVal) 95 case reflect.Slice: 96 err = d.toSlice(name, input, outVal) 97 case reflect.Array: 98 err = d.toArray(name, input, outVal) 99 case reflect.Func: 100 err = d.toFunc(name, input, outVal) 101 default: 102 return errors.New(name + ": unsupported type: " + outputKind.String()) 103 } 104 105 return err 106 } 107 108 func (d *Conver) basic(name string, data interface{}, val reflect.Value) error { 109 if val.IsValid() && val.Elem().IsValid() { 110 elem, copied := val.Elem(), false 111 if !elem.CanAddr() { 112 copied = true 113 nVal := reflect.New(elem.Type()) 114 nVal.Elem().Set(elem) 115 elem = nVal 116 } 117 118 if err := d.to(name, data, elem); err != nil || !copied { 119 return err 120 } 121 122 val.Set(elem.Elem()) 123 return nil 124 } 125 126 dataVal := zreflect.ValueOf(data) 127 if dataVal.Kind() == reflect.Ptr && dataVal.Type().Elem() == val.Type() { 128 dataVal = reflect.Indirect(dataVal) 129 } 130 131 if !dataVal.IsValid() { 132 dataVal = reflect.Zero(val.Type()) 133 } 134 135 dataValType := dataVal.Type() 136 if !dataValType.AssignableTo(val.Type()) { 137 return fmt.Errorf( 138 "'%s' expected type '%s', got '%s'", 139 name, val.Type(), dataValType) 140 } 141 142 val.Set(dataVal) 143 return nil 144 } 145 146 func (d *Conver) toStruct(name string, data interface{}, val reflect.Value) error { 147 dataVal := reflect.Indirect(zreflect.ValueOf(data)) 148 if dataVal.Type() == val.Type() { 149 val.Set(dataVal) 150 return nil 151 } 152 153 switch dataVal.Kind() { 154 case reflect.Map: 155 return d.toStructFromMap(name, dataVal, val) 156 case reflect.Struct: 157 mapType := reflect.TypeOf((map[string]interface{})(nil)) 158 mval := reflect.MakeMap(mapType) 159 addrVal := reflect.New(mval.Type()) 160 reflect.Indirect(addrVal).Set(mval) 161 err := d.toMapFromStruct(name, dataVal, reflect.Indirect(addrVal), mval) 162 if err != nil { 163 return err 164 } 165 166 return d.toStructFromMap(name, reflect.Indirect(addrVal), val) 167 168 default: 169 return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) 170 } 171 } 172 173 func (d *Conver) toStructFromMap(name string, dataVal, val reflect.Value) error { 174 dataValType := dataVal.Type() 175 if kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface { 176 return fmt.Errorf( 177 "'%s' needs a map with string keys, has '%s' keys", 178 name, dataValType.Key().Kind()) 179 } 180 181 dataValKeys := make(map[reflect.Value]struct{}) 182 dataValKeysUnused := make(map[interface{}]struct{}) 183 for _, dataValKey := range dataVal.MapKeys() { 184 dataValKeys[dataValKey] = struct{}{} 185 dataValKeysUnused[dataValKey.Interface()] = struct{}{} 186 } 187 188 targetValKeysUnused, structs := make(map[interface{}]struct{}), make([]reflect.Value, 1, 5) 189 structs[0] = val 190 191 type field struct { 192 val reflect.Value 193 field reflect.StructField 194 } 195 196 var remainField *field 197 198 fields := make([]field, 0) 199 for len(structs) > 0 { 200 structVal := structs[0] 201 structs = structs[1:] 202 structType := structVal.Type() 203 204 for i := 0; i < structType.NumField(); i++ { 205 fieldType := structType.Field(i) 206 fieldVal := structVal.Field(i) 207 if fieldVal.Kind() == reflect.Ptr && fieldVal.Elem().Kind() == reflect.Struct { 208 fieldVal = fieldVal.Elem() 209 } 210 211 squash := d.Squash && fieldVal.Kind() == reflect.Struct && fieldType.Anonymous 212 remain := false 213 _, opt := zreflect.GetStructTag(fieldType, d.TagName, tagNameLesser) 214 tagParts := strings.Split(opt, ",") 215 for _, tag := range tagParts { 216 if tag == "squash" { 217 squash = true 218 break 219 } 220 221 if tag == "remain" { 222 remain = true 223 break 224 } 225 } 226 227 if squash { 228 if fieldVal.Kind() != reflect.Struct { 229 return fmt.Errorf("cannot squash non-struct type '%s'", fieldVal.Type()) 230 } else { 231 structs = append(structs, fieldVal) 232 } 233 continue 234 } 235 236 if remain { 237 remainField = &field{field: fieldType, val: fieldVal} 238 } else { 239 fields = append(fields, field{field: fieldType, val: fieldVal}) 240 } 241 } 242 } 243 244 for _, f := range fields { 245 field, fieldValue := f.field, f.val 246 fieldName, _ := zreflect.GetStructTag(field, d.TagName, tagNameLesser) 247 rawMapKey := zreflect.ValueOf(fieldName) 248 rawMapVal := dataVal.MapIndex(rawMapKey) 249 if !rawMapVal.IsValid() { 250 for dataValKey := range dataValKeys { 251 mK, ok := dataValKey.Interface().(string) 252 if !ok { 253 continue 254 } 255 256 if d.MatchName(mK, fieldName) { 257 rawMapKey = dataValKey 258 rawMapVal = dataVal.MapIndex(dataValKey) 259 break 260 } 261 } 262 263 if !rawMapVal.IsValid() { 264 targetValKeysUnused[fieldName] = struct{}{} 265 continue 266 } 267 } 268 269 if !fieldValue.IsValid() { 270 panic("field is not valid") 271 } 272 273 if !fieldValue.CanSet() { 274 continue 275 } 276 277 delete(dataValKeysUnused, rawMapKey.Interface()) 278 279 if name != "" { 280 fieldName = name + "." + fieldName 281 } 282 283 if err := d.to(fieldName, rawMapVal.Interface(), fieldValue); err != nil { 284 return err 285 } 286 } 287 288 if remainField != nil && len(dataValKeysUnused) > 0 { 289 remain := map[interface{}]interface{}{} 290 for key := range dataValKeysUnused { 291 remain[key] = dataVal.MapIndex(zreflect.ValueOf(key)).Interface() 292 } 293 294 if err := d.toMap(name, remain, remainField.val); err != nil { 295 return err 296 } 297 } 298 299 return nil 300 } 301 302 func (d *Conver) toMap(name string, data interface{}, val reflect.Value) error { 303 valType := val.Type() 304 valKeyType := valType.Key() 305 valElemType := valType.Elem() 306 valMap := val 307 308 if valMap.IsNil() || d.ZeroFields { 309 mapType := reflect.MapOf(valKeyType, valElemType) 310 valMap = reflect.MakeMap(mapType) 311 } 312 313 dataVal := reflect.Indirect(zreflect.ValueOf(data)) 314 switch dataVal.Kind() { 315 case reflect.Map: 316 return d.toMapFromMap(name, dataVal, val, valMap) 317 case reflect.Struct: 318 return d.toMapFromStruct(name, dataVal, val, valMap) 319 case reflect.Array, reflect.Slice: 320 return d.toMapFromSlice(name, dataVal, val, valMap) 321 default: 322 return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) 323 } 324 } 325 326 func (d *Conver) toMapFromSlice(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { 327 if dataVal.Len() == 0 { 328 val.Set(valMap) 329 return nil 330 } 331 332 for i := 0; i < dataVal.Len(); i++ { 333 err := d.to( 334 name+"["+strconv.Itoa(i)+"]", 335 dataVal.Index(i).Interface(), val) 336 if err != nil { 337 return err 338 } 339 } 340 341 return nil 342 } 343 344 func (d *Conver) toMapFromMap(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { 345 valType := val.Type() 346 valKeyType := valType.Key() 347 valElemType := valType.Elem() 348 349 if dataVal.Len() == 0 { 350 if dataVal.IsNil() { 351 if !val.IsNil() { 352 val.Set(dataVal) 353 } 354 } else { 355 val.Set(valMap) 356 } 357 358 return nil 359 } 360 361 for _, k := range dataVal.MapKeys() { 362 fieldName := name + "[" + k.String() + "]" 363 currentKey := reflect.Indirect(reflect.New(valKeyType)) 364 if err := d.to(fieldName, k.Interface(), currentKey); err != nil { 365 return err 366 } 367 368 v := dataVal.MapIndex(k).Interface() 369 currentVal := reflect.Indirect(reflect.New(valElemType)) 370 if err := d.to(fieldName, v, currentVal); err != nil { 371 return err 372 } 373 374 valMap.SetMapIndex(currentKey, currentVal) 375 } 376 377 val.Set(valMap) 378 379 return nil 380 } 381 382 func (d *Conver) toMapFromStruct(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { 383 typ := dataVal.Type() 384 for i := 0; i < typ.NumField(); i++ { 385 f := typ.Field(i) 386 387 fmt.Println(name, f.PkgPath, f.Name, dataVal.IsValid()) 388 if f.PkgPath != "" { 389 continue 390 } 391 392 v := dataVal.Field(i) 393 if !v.Type().AssignableTo(valMap.Type().Elem()) { 394 return fmt.Errorf("cannot assign type '%s' to map value field of type '%s'", v.Type(), valMap.Type().Elem()) 395 } 396 397 keyName, opt := zreflect.GetStructTag(f, d.TagName, tagNameLesser) 398 if keyName == "" { 399 continue 400 } 401 squash := d.Squash && v.Kind() == reflect.Struct && f.Anonymous 402 403 if !(v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct) { 404 nv := v.Elem() 405 for i := 0; i < typ.NumField(); i++ { 406 f := typ.Field(i) 407 keyName, _ := zreflect.GetStructTag(f, d.TagName, tagNameLesser) 408 if keyName != "" { 409 v = nv 410 break 411 } 412 } 413 } 414 415 if opt != "" { 416 if strings.Index(opt, "omitempty") != -1 && !zreflect.Nonzero(v) { 417 continue 418 } 419 420 squash = squash || strings.Index(opt, "squash") != -1 421 if squash { 422 if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct { 423 v = v.Elem() 424 } 425 if v.Kind() != reflect.Struct { 426 return fmt.Errorf("cannot squash non-struct type '%s'", v.Type()) 427 } 428 } 429 } 430 431 switch v.Kind() { 432 case reflect.Struct: 433 x := reflect.New(v.Type()) 434 x.Elem().Set(v) 435 vType := valMap.Type() 436 vKeyType := vType.Key() 437 vElemType := vType.Elem() 438 mType := reflect.MapOf(vKeyType, vElemType) 439 vMap := reflect.MakeMap(mType) 440 addrVal := reflect.New(vMap.Type()) 441 reflect.Indirect(addrVal).Set(vMap) 442 443 err := d.to(keyName, x.Interface(), reflect.Indirect(addrVal)) 444 if err != nil { 445 return err 446 } 447 448 vMap = reflect.Indirect(addrVal) 449 if squash { 450 for _, k := range vMap.MapKeys() { 451 valMap.SetMapIndex(k, vMap.MapIndex(k)) 452 } 453 } else { 454 valMap.SetMapIndex(zreflect.ValueOf(keyName), vMap) 455 } 456 457 default: 458 valMap.SetMapIndex(zreflect.ValueOf(keyName), v) 459 } 460 } 461 462 if val.CanAddr() { 463 val.Set(valMap) 464 } 465 466 return nil 467 } 468 469 func (d *Conver) toPtr(name string, data interface{}, val reflect.Value) error { 470 isNil := data == nil 471 if !isNil { 472 switch v := reflect.Indirect(zreflect.ValueOf(data)); v.Kind() { 473 case reflect.Chan, 474 reflect.Func, 475 reflect.Interface, 476 reflect.Map, 477 reflect.Ptr, 478 reflect.Slice: 479 isNil = v.IsNil() 480 } 481 } 482 483 if isNil { 484 if !val.IsNil() && val.CanSet() { 485 nilValue := reflect.New(val.Type()).Elem() 486 val.Set(nilValue) 487 } 488 489 return nil 490 } 491 492 valType := val.Type() 493 valElemType := valType.Elem() 494 if val.CanSet() { 495 realVal := val 496 if realVal.IsNil() || d.ZeroFields { 497 realVal = reflect.New(valElemType) 498 } 499 500 if err := d.to(name, data, reflect.Indirect(realVal)); err != nil { 501 return err 502 } 503 504 val.Set(realVal) 505 } else { 506 if err := d.to(name, data, reflect.Indirect(val)); err != nil { 507 return err 508 } 509 } 510 return nil 511 } 512 513 func (d *Conver) toSlice(name string, data interface{}, val reflect.Value) error { 514 dataVal := reflect.Indirect(zreflect.ValueOf(data)) 515 dataValKind := dataVal.Kind() 516 valType := val.Type() 517 valElemType := valType.Elem() 518 sliceType := reflect.SliceOf(valElemType) 519 520 if dataValKind != reflect.Array && dataValKind != reflect.Slice { 521 switch { 522 case dataValKind == reflect.Slice, dataValKind == reflect.Array: 523 break 524 case dataValKind == reflect.Map: 525 if dataVal.Len() == 0 { 526 val.Set(reflect.MakeSlice(sliceType, 0, 0)) 527 return nil 528 } 529 return d.toSlice(name, []interface{}{data}, val) 530 case dataValKind == reflect.String && valElemType.Kind() == reflect.Uint8: 531 return d.toSlice(name, []byte(dataVal.String()), val) 532 default: 533 return d.toSlice(name, []interface{}{data}, val) 534 } 535 } 536 537 if dataValKind != reflect.Array && dataVal.IsNil() { 538 return nil 539 } 540 541 valSlice := val 542 if valSlice.IsNil() || d.ZeroFields { 543 valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len()) 544 } else if valSlice.Len() > dataVal.Len() { 545 valSlice = valSlice.Slice(0, dataVal.Len()) 546 } 547 548 for i := 0; i < dataVal.Len(); i++ { 549 currentData := dataVal.Index(i).Interface() 550 for valSlice.Len() <= i { 551 valSlice = reflect.Append(valSlice, reflect.Zero(valElemType)) 552 } 553 currentField := valSlice.Index(i) 554 fieldName := name + "[" + strconv.Itoa(i) + "]" 555 if err := d.to(fieldName, currentData, currentField); err != nil { 556 return err 557 } 558 } 559 560 val.Set(valSlice) 561 562 return nil 563 } 564 565 func (d *Conver) toArray(name string, data interface{}, val reflect.Value) error { 566 dataVal := reflect.Indirect(zreflect.ValueOf(data)) 567 dataValKind, valType := dataVal.Kind(), val.Type() 568 valElemType := valType.Elem() 569 arrayType, valArray := reflect.ArrayOf(valType.Len(), valElemType), val 570 if valArray.Interface() == reflect.Zero(valArray.Type()).Interface() || d.ZeroFields { 571 if dataValKind != reflect.Array && dataValKind != reflect.Slice { 572 switch { 573 case dataValKind == reflect.Map: 574 if dataVal.Len() == 0 { 575 val.Set(reflect.Zero(arrayType)) 576 return nil 577 } 578 default: 579 return d.toArray(name, []interface{}{data}, val) 580 } 581 } 582 if dataVal.Len() > arrayType.Len() { 583 return fmt.Errorf( 584 "'%s': expected source data to have length less or equal to %d, got %d", name, arrayType.Len(), dataVal.Len()) 585 } 586 587 valArray = reflect.New(arrayType).Elem() 588 } 589 590 for i := 0; i < dataVal.Len(); i++ { 591 currentData := dataVal.Index(i).Interface() 592 currentField := valArray.Index(i) 593 594 fieldName := name + "[" + strconv.Itoa(i) + "]" 595 if err := d.to(fieldName, currentData, currentField); err != nil { 596 return err 597 } 598 } 599 600 val.Set(valArray) 601 602 return nil 603 } 604 605 func (d *Conver) toFunc(name string, data interface{}, val reflect.Value) error { 606 dataVal := reflect.Indirect(zreflect.ValueOf(data)) 607 if val.Type() != dataVal.Type() { 608 return fmt.Errorf( 609 "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", 610 name, val.Type(), dataVal.Type(), data) 611 } 612 val.Set(dataVal) 613 return nil 614 }