diff --git a/cvte_test.go b/cvte_test.go index db77187..2a0a705 100644 --- a/cvte_test.go +++ b/cvte_test.go @@ -45,8 +45,9 @@ var ( aliasTypeUint0 AliasTypeUint = 0 aliasTypeUint1 AliasTypeUint = 1 - aliasTypeFloat0 AliasTypeFloat64 = 0 - aliasTypeFloat1 AliasTypeFloat64 = 1 + aliasTypeFloat0 AliasTypeFloat64 = 0 + aliasTypeFloat1 AliasTypeFloat64 = 1 + aliasTypeFloat8d15 AliasTypeFloat64 = 8.15 aliasTypeString0 AliasTypeString = "0" aliasTypeString1 AliasTypeString = "1" @@ -62,6 +63,7 @@ var ( pointerIntNil *AliasTypeInt aliasTypeBytesNil AliasTypeBytes aliasTypeBytesTrue AliasTypeBytes = []byte("true") + aliasTypeBytes8d15 AliasTypeBytes = []byte("8.15") ) // custom type diff --git a/float.go b/float.go index 2c3f2e2..8545587 100644 --- a/float.go +++ b/float.go @@ -1,9 +1,11 @@ package cvt import ( + "encoding/json" "fmt" "math" "strconv" + "time" ) // Float64 convert an interface to a float64 type, with default value @@ -27,6 +29,59 @@ func Float64P(v interface{}, def ...float64) *float64 { // Float64E convert an interface to a float64 type func Float64E(val interface{}) (float64, error) { + v, e := convFloat64E(val) + if e := catch("float64", val, e); e != nil { + return 0, e + } + return v, nil +} + +func convFloat64E(val interface{}) (float64, error) { + // direct type(for improve performance) + switch vv := val.(type) { + case nil: + return 0, nil + case bool: + if vv { + return 1, nil + } + return 0, nil + case string: + vvv, err := strconv.ParseFloat(vv, 64) + if err == nil { + return vvv, nil + } + return 0, errConvFail + case []byte: + vvv, err := strconv.ParseFloat(string(vv), 64) + if err == nil { + return vvv, nil + } + return 0, errConvFail + case uint, uint8, uint16, uint32, uint64, uintptr: + return float64(Uint64(vv)), nil + case int, int8, int16, int32, int64: + return float64(Int(vv)), nil + case float32: + // use fmt to fix float32 -> float64 precision loss + // eg: cvt.Float64E(float32(8.31)) + vvv, err := strconv.ParseFloat(fmt.Sprintf("%f", vv), 64) + if err == nil { + return vvv, nil + } + case float64: + return vv, nil + case json.Number: + vvv, err := vv.Float64() + if err == nil { + return vvv, nil + } + return 0, errConvFail + case time.Duration: + return float64(vv), nil + } + + // indirect type v, rv := indirect(val) switch vv := v.(type) { @@ -86,7 +141,7 @@ func Float32P(v interface{}, def ...float32) *float32 { // Float32E convert an interface to a float32 type func Float32E(val interface{}) (float32, error) { - v, e := Float64E(val) + v, e := convFloat64E(val) if e := catch("float32", val, e); e != nil { return 0, e } diff --git a/float_test.go b/float_test.go index fa332a6..060f778 100644 --- a/float_test.go +++ b/float_test.go @@ -1,9 +1,11 @@ package cvt_test import ( + "encoding/json" "fmt" "math" "testing" + "time" "github.com/shockerli/cvt" ) @@ -278,6 +280,8 @@ func TestFloat64E(t *testing.T) { {&aliasTypeInt0, 0, false}, {aliasTypeInt1, 1, false}, {&aliasTypeInt1, 1, false}, + {aliasTypeUint1, 1, false}, + {&aliasTypeUint0, 0, false}, {aliasTypeString0, 0, false}, {&aliasTypeString0, 0, false}, {aliasTypeString1, 1, false}, @@ -296,6 +300,13 @@ func TestFloat64E(t *testing.T) { {&pointerIntNil, 0, false}, {(*AliasTypeInt)(nil), 0, false}, {(*PointerTypeInt)(nil), 0, false}, + {json.Number("-.1"), -.1, false}, + {json.Number("12"), 12, false}, + {aliasTypeBytes8d15, 8.15, false}, + {aliasTypeUint1, 1, false}, + {aliasTypeFloat8d15, 8.15, false}, + {&aliasTypeFloat8d15, 8.15, false}, + {time.Duration(1), 1, false}, // errors {"10a", 0, true}, @@ -303,6 +314,10 @@ func TestFloat64E(t *testing.T) { {"8.01a", 0, true}, {"8.01 ", 0, true}, {"hello", 0, true}, + {[]byte("hello"), 0, true}, + {json.Number("hello"), 0, true}, + {aliasTypeBytesTrue, 0, true}, + {aliasTypeBytesNil, 0, true}, {testing.T{}, 0, true}, {&testing.T{}, 0, true}, {[]int{}, 0, true}, @@ -390,6 +405,7 @@ func TestFloat32E(t *testing.T) { {&pointerIntNil, 0, false}, {(*AliasTypeInt)(nil), 0, false}, {(*PointerTypeInt)(nil), 0, false}, + {AliasTypeFloat32(8.15), 8.15, false}, // errors {"10a", 0, true}, @@ -404,6 +420,10 @@ func TestFloat32E(t *testing.T) { {[]string{}, 0, true}, {[...]string{}, 0, true}, {map[int]string{}, 0, true}, + {[]byte("hello"), 0, true}, + {json.Number("hello"), 0, true}, + {aliasTypeBytesTrue, 0, true}, + {aliasTypeBytesNil, 0, true}, } for i, tt := range tests {