Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/vendor/github.com/spf13/cast/number.go
2875 views
1
// Copyright © 2014 Steve Francia <[email protected]>.
2
//
3
// Use of this source code is governed by an MIT-style
4
// license that can be found in the LICENSE file.
5
6
package cast
7
8
import (
9
"encoding/json"
10
"errors"
11
"fmt"
12
"regexp"
13
"strconv"
14
"strings"
15
"time"
16
)
17
18
var errNegativeNotAllowed = errors.New("unable to cast negative value")
19
20
type float64EProvider interface {
21
Float64() (float64, error)
22
}
23
24
type float64Provider interface {
25
Float64() float64
26
}
27
28
// Number is a type parameter constraint for functions accepting number types.
29
//
30
// It represents the supported number types this package can cast to.
31
type Number interface {
32
int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | float32 | float64
33
}
34
35
type integer interface {
36
int | int8 | int16 | int32 | int64
37
}
38
39
type unsigned interface {
40
uint | uint8 | uint16 | uint32 | uint64
41
}
42
43
type float interface {
44
float32 | float64
45
}
46
47
// ToNumberE casts any value to a [Number] type.
48
func ToNumberE[T Number](i any) (T, error) {
49
var t T
50
51
switch any(t).(type) {
52
case int:
53
return toNumberE[T](i, parseNumber[T])
54
case int8:
55
return toNumberE[T](i, parseNumber[T])
56
case int16:
57
return toNumberE[T](i, parseNumber[T])
58
case int32:
59
return toNumberE[T](i, parseNumber[T])
60
case int64:
61
return toNumberE[T](i, parseNumber[T])
62
case uint:
63
return toUnsignedNumberE[T](i, parseNumber[T])
64
case uint8:
65
return toUnsignedNumberE[T](i, parseNumber[T])
66
case uint16:
67
return toUnsignedNumberE[T](i, parseNumber[T])
68
case uint32:
69
return toUnsignedNumberE[T](i, parseNumber[T])
70
case uint64:
71
return toUnsignedNumberE[T](i, parseNumber[T])
72
case float32:
73
return toNumberE[T](i, parseNumber[T])
74
case float64:
75
return toNumberE[T](i, parseNumber[T])
76
default:
77
return 0, fmt.Errorf("unknown number type: %T", t)
78
}
79
}
80
81
// ToNumber casts any value to a [Number] type.
82
func ToNumber[T Number](i any) T {
83
v, _ := ToNumberE[T](i)
84
85
return v
86
}
87
88
// toNumber's semantics differ from other "to" functions.
89
// It returns false as the second parameter if the conversion fails.
90
// This is to signal other callers that they should proceed with their own conversions.
91
func toNumber[T Number](i any) (T, bool) {
92
i, _ = indirect(i)
93
94
switch s := i.(type) {
95
case T:
96
return s, true
97
case int:
98
return T(s), true
99
case int8:
100
return T(s), true
101
case int16:
102
return T(s), true
103
case int32:
104
return T(s), true
105
case int64:
106
return T(s), true
107
case uint:
108
return T(s), true
109
case uint8:
110
return T(s), true
111
case uint16:
112
return T(s), true
113
case uint32:
114
return T(s), true
115
case uint64:
116
return T(s), true
117
case float32:
118
return T(s), true
119
case float64:
120
return T(s), true
121
case bool:
122
if s {
123
return 1, true
124
}
125
126
return 0, true
127
case nil:
128
return 0, true
129
case time.Weekday:
130
return T(s), true
131
case time.Month:
132
return T(s), true
133
}
134
135
return 0, false
136
}
137
138
func toNumberE[T Number](i any, parseFn func(string) (T, error)) (T, error) {
139
n, ok := toNumber[T](i)
140
if ok {
141
return n, nil
142
}
143
144
i, _ = indirect(i)
145
146
switch s := i.(type) {
147
case string:
148
if s == "" {
149
return 0, nil
150
}
151
152
v, err := parseFn(s)
153
if err != nil {
154
return 0, fmt.Errorf(errorMsgWith, i, i, n, err)
155
}
156
157
return v, nil
158
case json.Number:
159
if s == "" {
160
return 0, nil
161
}
162
163
v, err := parseFn(string(s))
164
if err != nil {
165
return 0, fmt.Errorf(errorMsgWith, i, i, n, err)
166
}
167
168
return v, nil
169
case float64EProvider:
170
if _, ok := any(n).(float64); !ok {
171
return 0, fmt.Errorf(errorMsg, i, i, n)
172
}
173
174
v, err := s.Float64()
175
if err != nil {
176
return 0, fmt.Errorf(errorMsg, i, i, n)
177
}
178
179
return T(v), nil
180
case float64Provider:
181
if _, ok := any(n).(float64); !ok {
182
return 0, fmt.Errorf(errorMsg, i, i, n)
183
}
184
185
return T(s.Float64()), nil
186
default:
187
if i, ok := resolveAlias(i); ok {
188
return toNumberE(i, parseFn)
189
}
190
191
return 0, fmt.Errorf(errorMsg, i, i, n)
192
}
193
}
194
195
func toUnsignedNumber[T Number](i any) (T, bool, bool) {
196
i, _ = indirect(i)
197
198
switch s := i.(type) {
199
case T:
200
return s, true, true
201
case int:
202
if s < 0 {
203
return 0, false, false
204
}
205
206
return T(s), true, true
207
case int8:
208
if s < 0 {
209
return 0, false, false
210
}
211
212
return T(s), true, true
213
case int16:
214
if s < 0 {
215
return 0, false, false
216
}
217
218
return T(s), true, true
219
case int32:
220
if s < 0 {
221
return 0, false, false
222
}
223
224
return T(s), true, true
225
case int64:
226
if s < 0 {
227
return 0, false, false
228
}
229
230
return T(s), true, true
231
case uint:
232
return T(s), true, true
233
case uint8:
234
return T(s), true, true
235
case uint16:
236
return T(s), true, true
237
case uint32:
238
return T(s), true, true
239
case uint64:
240
return T(s), true, true
241
case float32:
242
if s < 0 {
243
return 0, false, false
244
}
245
246
return T(s), true, true
247
case float64:
248
if s < 0 {
249
return 0, false, false
250
}
251
252
return T(s), true, true
253
case bool:
254
if s {
255
return 1, true, true
256
}
257
258
return 0, true, true
259
case nil:
260
return 0, true, true
261
case time.Weekday:
262
if s < 0 {
263
return 0, false, false
264
}
265
266
return T(s), true, true
267
case time.Month:
268
if s < 0 {
269
return 0, false, false
270
}
271
272
return T(s), true, true
273
}
274
275
return 0, true, false
276
}
277
278
func toUnsignedNumberE[T Number](i any, parseFn func(string) (T, error)) (T, error) {
279
n, valid, ok := toUnsignedNumber[T](i)
280
if ok {
281
return n, nil
282
}
283
284
i, _ = indirect(i)
285
286
if !valid {
287
return 0, errNegativeNotAllowed
288
}
289
290
switch s := i.(type) {
291
case string:
292
if s == "" {
293
return 0, nil
294
}
295
296
v, err := parseFn(s)
297
if err != nil {
298
return 0, fmt.Errorf(errorMsgWith, i, i, n, err)
299
}
300
301
return v, nil
302
case json.Number:
303
if s == "" {
304
return 0, nil
305
}
306
307
v, err := parseFn(string(s))
308
if err != nil {
309
return 0, fmt.Errorf(errorMsgWith, i, i, n, err)
310
}
311
312
return v, nil
313
case float64EProvider:
314
if _, ok := any(n).(float64); !ok {
315
return 0, fmt.Errorf(errorMsg, i, i, n)
316
}
317
318
v, err := s.Float64()
319
if err != nil {
320
return 0, fmt.Errorf(errorMsg, i, i, n)
321
}
322
323
if v < 0 {
324
return 0, errNegativeNotAllowed
325
}
326
327
return T(v), nil
328
case float64Provider:
329
if _, ok := any(n).(float64); !ok {
330
return 0, fmt.Errorf(errorMsg, i, i, n)
331
}
332
333
v := s.Float64()
334
335
if v < 0 {
336
return 0, errNegativeNotAllowed
337
}
338
339
return T(v), nil
340
default:
341
if i, ok := resolveAlias(i); ok {
342
return toUnsignedNumberE(i, parseFn)
343
}
344
345
return 0, fmt.Errorf(errorMsg, i, i, n)
346
}
347
}
348
349
func parseNumber[T Number](s string) (T, error) {
350
var t T
351
352
switch any(t).(type) {
353
case int:
354
v, err := parseInt[int](s)
355
356
return T(v), err
357
case int8:
358
v, err := parseInt[int8](s)
359
360
return T(v), err
361
case int16:
362
v, err := parseInt[int16](s)
363
364
return T(v), err
365
case int32:
366
v, err := parseInt[int32](s)
367
368
return T(v), err
369
case int64:
370
v, err := parseInt[int64](s)
371
372
return T(v), err
373
case uint:
374
v, err := parseUint[uint](s)
375
376
return T(v), err
377
case uint8:
378
v, err := parseUint[uint8](s)
379
380
return T(v), err
381
case uint16:
382
v, err := parseUint[uint16](s)
383
384
return T(v), err
385
case uint32:
386
v, err := parseUint[uint32](s)
387
388
return T(v), err
389
case uint64:
390
v, err := parseUint[uint64](s)
391
392
return T(v), err
393
case float32:
394
v, err := strconv.ParseFloat(s, 32)
395
396
return T(v), err
397
case float64:
398
v, err := strconv.ParseFloat(s, 64)
399
400
return T(v), err
401
402
default:
403
return 0, fmt.Errorf("unknown number type: %T", t)
404
}
405
}
406
407
func parseInt[T integer](s string) (T, error) {
408
v, err := strconv.ParseInt(trimDecimal(s), 0, 0)
409
if err != nil {
410
return 0, err
411
}
412
413
return T(v), nil
414
}
415
416
func parseUint[T unsigned](s string) (T, error) {
417
v, err := strconv.ParseUint(strings.TrimLeft(trimDecimal(s), "+"), 0, 0)
418
if err != nil {
419
return 0, err
420
}
421
422
return T(v), nil
423
}
424
425
func parseFloat[T float](s string) (T, error) {
426
var t T
427
428
var v any
429
var err error
430
431
switch any(t).(type) {
432
case float32:
433
n, e := strconv.ParseFloat(s, 32)
434
435
v = float32(n)
436
err = e
437
case float64:
438
n, e := strconv.ParseFloat(s, 64)
439
440
v = float64(n)
441
err = e
442
}
443
444
return v.(T), err
445
}
446
447
// ToFloat64E casts an interface to a float64 type.
448
func ToFloat64E(i any) (float64, error) {
449
return toNumberE[float64](i, parseFloat[float64])
450
}
451
452
// ToFloat32E casts an interface to a float32 type.
453
func ToFloat32E(i any) (float32, error) {
454
return toNumberE[float32](i, parseFloat[float32])
455
}
456
457
// ToInt64E casts an interface to an int64 type.
458
func ToInt64E(i any) (int64, error) {
459
return toNumberE[int64](i, parseInt[int64])
460
}
461
462
// ToInt32E casts an interface to an int32 type.
463
func ToInt32E(i any) (int32, error) {
464
return toNumberE[int32](i, parseInt[int32])
465
}
466
467
// ToInt16E casts an interface to an int16 type.
468
func ToInt16E(i any) (int16, error) {
469
return toNumberE[int16](i, parseInt[int16])
470
}
471
472
// ToInt8E casts an interface to an int8 type.
473
func ToInt8E(i any) (int8, error) {
474
return toNumberE[int8](i, parseInt[int8])
475
}
476
477
// ToIntE casts an interface to an int type.
478
func ToIntE(i any) (int, error) {
479
return toNumberE[int](i, parseInt[int])
480
}
481
482
// ToUintE casts an interface to a uint type.
483
func ToUintE(i any) (uint, error) {
484
return toUnsignedNumberE[uint](i, parseUint[uint])
485
}
486
487
// ToUint64E casts an interface to a uint64 type.
488
func ToUint64E(i any) (uint64, error) {
489
return toUnsignedNumberE[uint64](i, parseUint[uint64])
490
}
491
492
// ToUint32E casts an interface to a uint32 type.
493
func ToUint32E(i any) (uint32, error) {
494
return toUnsignedNumberE[uint32](i, parseUint[uint32])
495
}
496
497
// ToUint16E casts an interface to a uint16 type.
498
func ToUint16E(i any) (uint16, error) {
499
return toUnsignedNumberE[uint16](i, parseUint[uint16])
500
}
501
502
// ToUint8E casts an interface to a uint type.
503
func ToUint8E(i any) (uint8, error) {
504
return toUnsignedNumberE[uint8](i, parseUint[uint8])
505
}
506
507
func trimZeroDecimal(s string) string {
508
var foundZero bool
509
for i := len(s); i > 0; i-- {
510
switch s[i-1] {
511
case '.':
512
if foundZero {
513
return s[:i-1]
514
}
515
case '0':
516
foundZero = true
517
default:
518
return s
519
}
520
}
521
return s
522
}
523
524
var stringNumberRe = regexp.MustCompile(`^([-+]?\d*)(\.\d*)?$`)
525
526
// see [BenchmarkDecimal] for details about the implementation
527
func trimDecimal(s string) string {
528
if !strings.Contains(s, ".") {
529
return s
530
}
531
532
matches := stringNumberRe.FindStringSubmatch(s)
533
if matches != nil {
534
// matches[1] is the captured integer part with sign
535
s = matches[1]
536
537
// handle special cases
538
switch s {
539
case "-", "+":
540
s += "0"
541
case "":
542
s = "0"
543
}
544
545
return s
546
}
547
548
return s
549
}
550
551