-
Notifications
You must be signed in to change notification settings - Fork 1
/
to.float.go
115 lines (104 loc) · 2.49 KB
/
to.float.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package cast
import (
"fmt"
"reflect"
"strconv"
"strings"
"github.com/bdlm/errors/v2"
"golang.org/x/exp/constraints"
)
// toFloat casts an interface to a float type.
//
// Options:
// - DEFAULT: float32 or float64, default 0.0. Default return value on error.
func toFloat[TTo constraints.Float](from reflect.Value, ops Ops) (TTo, error) {
var ret TTo
var ok bool
if _, ok = ops[DEFAULT]; ok {
if ret, ok = ops[DEFAULT].(TTo); !ok {
return ret, errors.Errorf(ErrorInvalidOption, "DEFAULT", ops[DEFAULT])
}
}
fromVal := reflect.ValueOf(from)
if !fromVal.IsValid() || !fromVal.CanInterface() {
return ret, errors.Errorf("unable to cast %#.10v of type %T to %T", from, from, TTo(0))
}
to := reflect.Indirect(reflect.ValueOf(new(TTo)))
switch typ := from.Interface().(type) {
case nil:
return TTo(0), nil
case bool:
if typ {
return TTo(1), nil
}
return TTo(0), nil
case float64:
return TTo(typ), nil
case float32:
return TTo(typ), nil
case int:
return TTo(typ), nil
case int64:
return TTo(typ), nil
case int32:
return TTo(typ), nil
case int16:
return TTo(typ), nil
case int8:
return TTo(typ), nil
case uint:
return TTo(typ), nil
case uint64:
return TTo(typ), nil
case uint32:
return TTo(typ), nil
case uint16:
return TTo(typ), nil
case uint8:
return TTo(typ), nil
case fmt.Stringer:
return strToFloat[TTo](to, typ.String())
case string:
return strToFloat[TTo](to, typ)
}
ret, err := toFloat[TTo](reflect.ValueOf(fmt.Sprintf("%v", from.Interface())), ops)
if nil != err {
return ret, errors.Wrap(err, ErrorStrUnableToCast, from.Interface(), from.Interface(), to.Interface())
}
return ret, nil
}
// strToFloat converts a string to a float type.
func strToFloat[TTo constraints.Float](to reflect.Value, from string) (TTo, error) {
var e, err error
var val any
var bitSize = 64
if to.Type().Kind() == reflect.Float32 {
bitSize = 32
}
if val, e = strconv.ParseFloat(from, bitSize); e != nil {
err = e
from = strings.ReplaceAll(
strings.Split(
strings.Trim(from, "\r\n\t "),
".",
)[0],
",", "",
)
if val, e = strconv.ParseFloat(from, bitSize); e != nil {
err = errors.WrapE(err, e)
_, e := strconv.ParseComplex(from, bitSize)
if e != nil {
err = errors.WrapE(err, e)
} else {
err = errors.Wrap(err, ErrorStrUnableToCast, from, from, to.Interface())
val = float64(0)
}
} else {
err = nil
}
}
if to.Type().Kind() == reflect.Float32 {
val = float32(val.(float64))
}
return val.(TTo), err
}