go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/projects/nodes/pkg/incrutil/cast_value.go (about) 1 /* 2 3 Copyright (c) 2023 - Present. Will Charczuk. All rights reserved. 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository. 5 6 */ 7 8 package incrutil 9 10 import ( 11 "fmt" 12 "strconv" 13 "time" 14 15 "go.charczuk.com/projects/nodes/pkg/types" 16 "go.charczuk.com/sdk/errutil" 17 "go.charczuk.com/sdk/iter" 18 ) 19 20 // CastValue casts a value as an output given an ambiguous input. 21 func CastValue[Output any](input any) (output Output, err error) { 22 err = CastAny(&input, &output) 23 return 24 } 25 26 // CastAny casts an input to an output as non-generic references. 27 func CastAny(input, output any) error { 28 if input == nil { 29 return nil 30 } 31 32 switch inputTyped := input.(type) { 33 case *any: 34 input = *inputTyped 35 default: 36 } 37 38 switch inputTyped := input.(type) { 39 case bool: 40 switch outputTyped := output.(type) { 41 case *any: 42 *outputTyped = inputTyped 43 return nil 44 case *bool: 45 *outputTyped = inputTyped 46 return nil 47 case *int64: 48 *outputTyped = b2i64(inputTyped) 49 return nil 50 case *string: 51 *outputTyped = fmt.Sprint(inputTyped) 52 return nil 53 case *float64: 54 *outputTyped = b2f64(inputTyped) 55 return nil 56 case *[]any: 57 *outputTyped = []any{inputTyped} 58 return nil 59 case *[]bool: 60 *outputTyped = []bool{inputTyped} 61 return nil 62 case *[]int64: 63 *outputTyped = []int64{b2i64(inputTyped)} 64 return nil 65 case *[]string: 66 *outputTyped = []string{fmt.Sprint(inputTyped)} 67 return nil 68 case *[]float64: 69 *outputTyped = []float64{b2f64(inputTyped)} 70 return nil 71 default: 72 return fmt.Errorf("cast: invalid output type %T for input type %T", output, input) 73 } 74 case int64: 75 switch outputTyped := output.(type) { 76 case *any: 77 *outputTyped = inputTyped 78 return nil 79 case *bool: 80 *outputTyped = inputTyped != 0 81 return nil 82 case *int64: 83 *outputTyped = inputTyped 84 return nil 85 case *string: 86 *outputTyped = strconv.FormatInt(inputTyped, 10) 87 return nil 88 case *float64: 89 *outputTyped = float64(inputTyped) 90 return nil 91 case *time.Time: 92 *outputTyped = time.UnixMilli(inputTyped) 93 return nil 94 case *time.Duration: 95 *outputTyped = time.Duration(inputTyped) 96 return nil 97 case *[]any: 98 *outputTyped = []any{inputTyped} 99 return nil 100 case *[]bool: 101 *outputTyped = []bool{inputTyped > 0} 102 return nil 103 case *[]int64: 104 *outputTyped = []int64{inputTyped} 105 return nil 106 case *[]string: 107 *outputTyped = []string{strconv.FormatInt(inputTyped, 10)} 108 return nil 109 case *[]float64: 110 *outputTyped = []float64{float64(inputTyped)} 111 return nil 112 case *[]time.Time: 113 *outputTyped = []time.Time{time.UnixMilli(inputTyped)} 114 return nil 115 case *[]time.Duration: 116 *outputTyped = []time.Duration{time.Duration(inputTyped)} 117 return nil 118 default: 119 return fmt.Errorf("cast: invalid output type %T for input type %T", output, input) 120 } 121 case string: 122 switch outputTyped := output.(type) { 123 case *any: 124 *outputTyped = inputTyped 125 return nil 126 case *bool: 127 *outputTyped = inputTyped != "" 128 return nil 129 case *int64: 130 inputParsed, err := strconv.ParseInt(inputTyped, 10, 64) 131 if err != nil { 132 return err 133 } 134 *outputTyped = inputParsed 135 return nil 136 case *string: 137 *outputTyped = inputTyped 138 return nil 139 case *float64: 140 inputParsed, err := strconv.ParseFloat(inputTyped, 64) 141 if err != nil { 142 return err 143 } 144 *outputTyped = inputParsed 145 return nil 146 case *time.Time: 147 inputParsed, err := ParseTime(inputTyped) 148 if err != nil { 149 return err 150 } 151 *outputTyped = inputParsed 152 return nil 153 case *time.Duration: 154 inputParsed, err := parseDuration(inputTyped) 155 if err != nil { 156 return err 157 } 158 *outputTyped = inputParsed 159 return nil 160 case *[]any: 161 *outputTyped = []any{inputTyped} 162 return nil 163 case *[]bool: 164 *outputTyped = []bool{inputTyped != ""} 165 return nil 166 case *[]int64: 167 inputParsed, err := strconv.ParseInt(inputTyped, 10, 64) 168 if err != nil { 169 return err 170 } 171 *outputTyped = []int64{inputParsed} 172 return nil 173 case *[]string: 174 *outputTyped = []string{inputTyped} 175 return nil 176 case *[]float64: 177 inputParsed, err := strconv.ParseFloat(inputTyped, 64) 178 if err != nil { 179 return err 180 } 181 *outputTyped = []float64{inputParsed} 182 return nil 183 case *[]time.Time: 184 inputParsed, err := ParseTime(inputTyped) 185 if err != nil { 186 return err 187 } 188 *outputTyped = []time.Time{inputParsed} 189 return nil 190 case *[]time.Duration: 191 inputParsed, err := parseDuration(inputTyped) 192 if err != nil { 193 return err 194 } 195 *outputTyped = []time.Duration{inputParsed} 196 return nil 197 default: 198 return fmt.Errorf("cast: invalid output type %T for input type %T", output, input) 199 } 200 case float64: 201 switch outputTyped := output.(type) { 202 case *any: 203 *outputTyped = inputTyped 204 return nil 205 case *bool: 206 *outputTyped = inputTyped != 0 207 return nil 208 case *int64: 209 *outputTyped = int64(inputTyped) 210 return nil 211 case *string: 212 *outputTyped = fmt.Sprint(inputTyped) 213 return nil 214 case *float64: 215 *outputTyped = inputTyped 216 return nil 217 case *time.Time: 218 *outputTyped = time.UnixMilli(int64(inputTyped)) 219 return nil 220 case *time.Duration: 221 *outputTyped = time.Duration(int64(inputTyped)) 222 return nil 223 case *[]any: 224 *outputTyped = []any{inputTyped} 225 return nil 226 case *[]bool: 227 *outputTyped = []bool{inputTyped != 0} 228 return nil 229 case *[]int64: 230 *outputTyped = []int64{int64(inputTyped)} 231 return nil 232 case *[]string: 233 *outputTyped = []string{fmt.Sprint(inputTyped)} 234 return nil 235 case *[]float64: 236 *outputTyped = []float64{inputTyped} 237 return nil 238 case *[]time.Time: 239 *outputTyped = []time.Time{time.UnixMilli(int64(inputTyped))} 240 return nil 241 case *[]time.Duration: 242 *outputTyped = []time.Duration{time.Duration(int64(inputTyped))} 243 return nil 244 default: 245 return fmt.Errorf("cast: invalid output type %T for input type %T", output, input) 246 } 247 case time.Time: 248 switch outputTyped := output.(type) { 249 case *any: 250 *outputTyped = inputTyped 251 return nil 252 case *bool: 253 *outputTyped = !inputTyped.IsZero() 254 return nil 255 case *int64: 256 *outputTyped = inputTyped.UnixMilli() 257 return nil 258 case *string: 259 str := inputTyped.Format(time.RFC3339) 260 *outputTyped = str 261 return nil 262 case *float64: 263 *outputTyped = float64(inputTyped.Unix()) 264 return nil 265 case *time.Time: 266 *outputTyped = inputTyped 267 return nil 268 case *[]any: 269 *outputTyped = []any{inputTyped} 270 return nil 271 case *[]bool: 272 *outputTyped = []bool{!inputTyped.IsZero()} 273 return nil 274 case *[]int64: 275 *outputTyped = []int64{inputTyped.UnixMilli()} 276 return nil 277 case *[]string: 278 *outputTyped = []string{inputTyped.Format(time.RFC3339)} 279 return nil 280 case *[]float64: 281 *outputTyped = []float64{float64(inputTyped.UnixMilli())} 282 return nil 283 case *[]time.Time: 284 *outputTyped = []time.Time{inputTyped} 285 return nil 286 default: 287 return fmt.Errorf("cast: invalid output type %T for input type %T", output, input) 288 } 289 case time.Duration: 290 switch outputTyped := output.(type) { 291 case *any: 292 *outputTyped = inputTyped 293 return nil 294 case *bool: 295 *outputTyped = inputTyped != 0 296 return nil 297 case *int64: 298 *outputTyped = int64(inputTyped) 299 return nil 300 case *string: 301 *outputTyped = formatDuration(inputTyped) 302 return nil 303 case *float64: 304 *outputTyped = float64(inputTyped) 305 return nil 306 case *time.Duration: 307 *outputTyped = inputTyped 308 return nil 309 case *[]any: 310 *outputTyped = []any{inputTyped} 311 return nil 312 case *[]bool: 313 *outputTyped = []bool{inputTyped != 0} 314 return nil 315 case *[]int64: 316 *outputTyped = []int64{int64(inputTyped)} 317 return nil 318 case *[]string: 319 *outputTyped = []string{formatDuration(inputTyped)} 320 return nil 321 case *[]float64: 322 *outputTyped = []float64{float64(inputTyped)} 323 return nil 324 case *[]time.Duration: 325 *outputTyped = []time.Duration{inputTyped} 326 return nil 327 default: 328 return fmt.Errorf("cast: invalid output type %T for input type %T", output, input) 329 } 330 case []bool: 331 switch outputTyped := output.(type) { 332 case *any: 333 *outputTyped = inputTyped 334 return nil 335 case *[]any: 336 *outputTyped = iter.Apply(inputTyped, func(v bool) any { return v }) 337 return nil 338 case *[]bool: 339 *outputTyped = inputTyped 340 return nil 341 case *[]int64: 342 *outputTyped = iter.Apply(inputTyped, func(v bool) int64 { return b2i64(v) }) 343 return nil 344 case *[]string: 345 *outputTyped = iter.Apply(inputTyped, func(v bool) string { return fmt.Sprint(v) }) 346 return nil 347 case *[]float64: 348 *outputTyped = iter.Apply(inputTyped, func(v bool) float64 { return b2f64(v) }) 349 return nil 350 default: 351 return fmt.Errorf("cast: invalid output type %T for input type %T", output, input) 352 } 353 case []int64: 354 switch outputTyped := output.(type) { 355 case *any: 356 *outputTyped = inputTyped 357 return nil 358 case *[]any: 359 *outputTyped = iter.Apply(inputTyped, func(v int64) any { return v }) 360 return nil 361 case *[]int64: 362 *outputTyped = inputTyped 363 return nil 364 case *[]string: 365 *outputTyped = iter.Apply(inputTyped, func(v int64) string { return strconv.FormatInt(v, 10) }) 366 return nil 367 case *[]float64: 368 *outputTyped = iter.Apply(inputTyped, func(v int64) float64 { return float64(v) }) 369 return nil 370 case *[]time.Time: 371 *outputTyped = iter.Apply(inputTyped, func(v int64) time.Time { return time.UnixMilli(v) }) 372 return nil 373 case *[]time.Duration: 374 *outputTyped = iter.Apply(inputTyped, func(v int64) time.Duration { return time.Duration(v) }) 375 return nil 376 default: 377 return fmt.Errorf("cast: invalid output type %T for input type %T", output, input) 378 } 379 case []string: 380 switch outputTyped := output.(type) { 381 case *any: 382 *outputTyped = inputTyped 383 return nil 384 case *[]any: 385 *outputTyped = iter.Apply(inputTyped, func(v string) any { return v }) 386 return nil 387 case *[]bool: 388 *outputTyped = iter.Apply(inputTyped, func(v string) bool { return v == "true" }) 389 return nil 390 case *[]int64: 391 var err error 392 *outputTyped, err = iter.ApplyError(inputTyped, func(v string) (int64, error) { 393 return strconv.ParseInt(v, 10, 64) 394 }) 395 return err 396 case *[]string: 397 *outputTyped = inputTyped 398 return nil 399 case *[]float64: 400 var err error 401 *outputTyped, err = iter.ApplyError(inputTyped, func(v string) (float64, error) { 402 return strconv.ParseFloat(v, 64) 403 }) 404 return err 405 case *[]time.Time: 406 var err error 407 *outputTyped, err = iter.ApplyError(inputTyped, func(v string) (time.Time, error) { 408 parsed, parseError := ParseTime(v) 409 return parsed, parseError 410 }) 411 return err 412 case *[]time.Duration: 413 var err error 414 *outputTyped, err = iter.ApplyError(inputTyped, func(v string) (time.Duration, error) { 415 parsed, parseErr := parseDuration(v) 416 return parsed, parseErr 417 }) 418 return err 419 default: 420 return fmt.Errorf("cast: invalid output type %T for input type %T", output, input) 421 } 422 case []float64: 423 switch outputTyped := output.(type) { 424 case *any: 425 *outputTyped = inputTyped 426 return nil 427 case *[]any: 428 *outputTyped = iter.Apply(inputTyped, func(v float64) any { return v }) 429 return nil 430 case *[]bool: 431 *outputTyped = iter.Apply(inputTyped, func(v float64) bool { return v != 0 }) 432 return nil 433 case *[]int64: 434 *outputTyped = iter.Apply(inputTyped, func(v float64) int64 { 435 return int64(v) 436 }) 437 return nil 438 case *[]string: 439 *outputTyped = iter.Apply(inputTyped, func(v float64) string { 440 return fmt.Sprint(v) 441 }) 442 return nil 443 case *[]float64: 444 *outputTyped = inputTyped 445 return nil 446 case *[]time.Time: 447 *outputTyped = iter.Apply(inputTyped, func(v float64) time.Time { 448 parsed := time.UnixMilli(int64(v)) 449 return parsed 450 }) 451 return nil 452 case *[]time.Duration: 453 *outputTyped = iter.Apply(inputTyped, func(v float64) time.Duration { 454 parsed := time.Duration(int64(v)) 455 return parsed 456 }) 457 return nil 458 default: 459 return fmt.Errorf("cast: invalid output type %T for input type %T", output, input) 460 } 461 case []time.Time: 462 switch outputTyped := output.(type) { 463 case *any: 464 *outputTyped = inputTyped 465 return nil 466 case *[]any: 467 *outputTyped = iter.Apply(inputTyped, func(v time.Time) any { return v }) 468 return nil 469 case *[]int64: 470 *outputTyped = iter.Apply(inputTyped, func(v time.Time) int64 { 471 return v.UnixMilli() 472 }) 473 return nil 474 case *[]string: 475 *outputTyped = iter.Apply(inputTyped, func(v time.Time) string { 476 return v.Format(time.RFC3339) 477 }) 478 return nil 479 case *[]float64: 480 *outputTyped = iter.Apply(inputTyped, func(v time.Time) float64 { 481 return float64(v.UnixMilli()) 482 }) 483 return nil 484 case *[]time.Time: 485 *outputTyped = inputTyped 486 return nil 487 default: 488 return fmt.Errorf("cast: invalid output type %T for input type %T", output, input) 489 } 490 case []any: 491 switch outputTyped := output.(type) { 492 case *any: 493 *outputTyped = inputTyped 494 return nil 495 case *[]any: 496 *outputTyped = inputTyped 497 return nil 498 case *[]bool: 499 *outputTyped = iter.Apply(inputTyped, func(v any) bool { 500 var output bool 501 CastAny(v, &output) 502 return output 503 }) 504 return nil 505 case *[]int64: 506 *outputTyped = iter.Apply(inputTyped, func(v any) int64 { 507 var output int64 508 CastAny(v, &output) 509 return output 510 }) 511 return nil 512 case *[]string: 513 *outputTyped = iter.Apply(inputTyped, func(v any) string { 514 var output string 515 CastAny(v, &output) 516 return output 517 }) 518 return nil 519 case *[]float64: 520 *outputTyped = iter.Apply(inputTyped, func(v any) float64 { 521 var output float64 522 CastAny(v, &output) 523 return output 524 }) 525 return nil 526 case *[]time.Time: 527 *outputTyped = iter.Apply(inputTyped, func(v any) time.Time { 528 var output time.Time 529 CastAny(v, &output) 530 return output 531 }) 532 return nil 533 case *[]time.Duration: 534 *outputTyped = iter.Apply(inputTyped, func(v any) time.Duration { 535 var output time.Duration 536 CastAny(v, &output) 537 return output 538 }) 539 return nil 540 default: 541 return fmt.Errorf("cast: invalid output type %T for input type %T", output, input) 542 } 543 case *types.Table: 544 switch outputTyped := output.(type) { 545 case *types.Table: 546 *outputTyped = *inputTyped 547 return nil 548 case **types.Table: 549 *outputTyped = inputTyped 550 return nil 551 case *any: 552 *outputTyped = inputTyped 553 return nil 554 default: 555 return fmt.Errorf("cast: invalid output type %T for input type %T", output, input) 556 } 557 case types.SVG: 558 switch outputTyped := output.(type) { 559 case *types.SVG: 560 *outputTyped = inputTyped 561 return nil 562 case *any: 563 *outputTyped = inputTyped 564 return nil 565 default: 566 return fmt.Errorf("cast: invalid output type %T for input type %T", output, input) 567 } 568 case map[string]any: 569 switch outputTyped := output.(type) { 570 case *any: 571 *outputTyped = inputTyped 572 return nil 573 default: 574 return fmt.Errorf("cast: invalid output type %T for input type %T", output, input) 575 } 576 default: 577 return fmt.Errorf("cast: invalid input type %T\n%v", input, errutil.GetStackTrace()) 578 } 579 }