Skip to content

Commit 9f5a1a6

Browse files
committed
utils: expose ParseFloat via new public utils package
1 parent 8ba559c commit 9f5a1a6

File tree

3 files changed

+81
-0
lines changed

3 files changed

+81
-0
lines changed

helper/helper.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package helper
2+
3+
import "github.com/redis/go-redis/v9/internal/util"
4+
5+
func ParseFloat(s string) (float64, error) {
6+
return util.ParseStringToFloat(s)
7+
}
8+
9+
func MustParseFloat(s string) float64 {
10+
return util.MustParseFloat(s)
11+
}

internal/util/convert.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package util
2+
3+
import (
4+
"fmt"
5+
"math"
6+
"strconv"
7+
)
8+
9+
// ParseFloat parses a Redis RESP3 float reply into a Go float64,
10+
// handling "inf", "-inf", "nan" per Redis conventions.
11+
func ParseStringToFloat(s string) (float64, error) {
12+
switch s {
13+
case "inf":
14+
return math.Inf(1), nil
15+
case "-inf":
16+
return math.Inf(-1), nil
17+
case "nan", "-nan":
18+
return math.NaN(), nil
19+
}
20+
return strconv.ParseFloat(s, 64)
21+
}
22+
23+
// MustParseFloat is like ParseFloat but panics on parse errors.
24+
func MustParseFloat(s string) float64 {
25+
f, err := ParseStringToFloat(s)
26+
if err != nil {
27+
panic(fmt.Sprintf("redis: failed to parse float %q: %v", s, err))
28+
}
29+
return f
30+
}

internal/util/convert_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package util
2+
3+
import (
4+
"math"
5+
"testing"
6+
)
7+
8+
func TestParseStringToFloat(t *testing.T) {
9+
tests := []struct {
10+
in string
11+
want float64
12+
ok bool
13+
}{
14+
{"1.23", 1.23, true},
15+
{"inf", math.Inf(1), true},
16+
{"-inf", math.Inf(-1), true},
17+
{"nan", math.NaN(), true},
18+
{"oops", 0, false},
19+
}
20+
21+
for _, tc := range tests {
22+
got, err := ParseStringToFloat(tc.in)
23+
if tc.ok {
24+
if err != nil {
25+
t.Fatalf("ParseFloat(%q) error: %v", tc.in, err)
26+
}
27+
if math.IsNaN(tc.want) {
28+
if !math.IsNaN(got) {
29+
t.Errorf("ParseFloat(%q) = %v; want NaN", tc.in, got)
30+
}
31+
} else if got != tc.want {
32+
t.Errorf("ParseFloat(%q) = %v; want %v", tc.in, got, tc.want)
33+
}
34+
} else {
35+
if err == nil {
36+
t.Errorf("ParseFloat(%q) expected error, got nil", tc.in)
37+
}
38+
}
39+
}
40+
}

0 commit comments

Comments
 (0)