Skip to content

Commit 371156a

Browse files
committed
feat: float32, float64
1 parent c6c5804 commit 371156a

File tree

6 files changed

+424
-26
lines changed

6 files changed

+424
-26
lines changed

args.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,9 @@ func (a *ArgumentsBase[T, C, VC]) Get() any {
226226
}
227227

228228
type (
229-
FloatArg = ArgumentBase[float64, NoConfig, floatValue]
229+
FloatArg = ArgumentBase[float64, NoConfig, floatValue[float64]]
230+
Float32Arg = ArgumentBase[float32, NoConfig, floatValue[float32]]
231+
Float64Arg = ArgumentBase[float64, NoConfig, floatValue[float64]]
230232
IntArg = ArgumentBase[int, IntegerConfig, intValue[int]]
231233
Int8Arg = ArgumentBase[int8, IntegerConfig, intValue[int8]]
232234
Int16Arg = ArgumentBase[int16, IntegerConfig, intValue[int16]]
@@ -241,7 +243,9 @@ type (
241243
Uint32Arg = ArgumentBase[uint32, IntegerConfig, uintValue[uint32]]
242244
Uint64Arg = ArgumentBase[uint64, IntegerConfig, uintValue[uint64]]
243245

244-
FloatArgs = ArgumentsBase[float64, NoConfig, floatValue]
246+
FloatArgs = ArgumentsBase[float64, NoConfig, floatValue[float64]]
247+
Float32Args = ArgumentsBase[float32, NoConfig, floatValue[float32]]
248+
Float64Args = ArgumentsBase[float64, NoConfig, floatValue[float64]]
245249
IntArgs = ArgumentsBase[int, IntegerConfig, intValue[int]]
246250
Int8Args = ArgumentsBase[int8, IntegerConfig, intValue[int8]]
247251
Int16Args = ArgumentsBase[int16, IntegerConfig, intValue[int16]]
@@ -293,6 +297,22 @@ func (c *Command) FloatArgs(name string) []float64 {
293297
return arg[[]float64](name, c)
294298
}
295299

300+
func (c *Command) Float32Arg(name string) float32 {
301+
return arg[float32](name, c)
302+
}
303+
304+
func (c *Command) Float32Args(name string) []float32 {
305+
return arg[[]float32](name, c)
306+
}
307+
308+
func (c *Command) Float64Arg(name string) float64 {
309+
return arg[float64](name, c)
310+
}
311+
312+
func (c *Command) Float64Args(name string) []float64 {
313+
return arg[[]float64](name, c)
314+
}
315+
296316
func (c *Command) IntArg(name string) int {
297317
return arg[int](name, c)
298318
}

flag_float.go

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,44 +2,71 @@ package cli
22

33
import (
44
"strconv"
5+
"unsafe"
56
)
67

7-
type FloatFlag = FlagBase[float64, NoConfig, floatValue]
8+
type (
9+
FloatFlag = FlagBase[float64, NoConfig, floatValue[float64]]
10+
Float32Flag = FlagBase[float32, NoConfig, floatValue[float32]]
11+
Float64Flag = FlagBase[float64, NoConfig, floatValue[float64]]
12+
)
813

9-
// -- float64 Value
10-
type floatValue float64
14+
// -- float Value
15+
type floatValue[T float32 | float64] struct {
16+
val *T
17+
}
1118

1219
// Below functions are to satisfy the ValueCreator interface
1320

14-
func (f floatValue) Create(val float64, p *float64, c NoConfig) Value {
21+
func (f floatValue[T]) Create(val T, p *T, c NoConfig) Value {
1522
*p = val
16-
return (*floatValue)(p)
23+
24+
return &floatValue[T]{val: p}
1725
}
1826

19-
func (f floatValue) ToString(b float64) string {
20-
return strconv.FormatFloat(b, 'g', -1, 64)
27+
func (f floatValue[T]) ToString(b T) string {
28+
return strconv.FormatFloat(float64(b), 'g', -1, int(unsafe.Sizeof(T(0))*8))
2129
}
2230

2331
// Below functions are to satisfy the flag.Value interface
2432

25-
func (f *floatValue) Set(s string) error {
26-
v, err := strconv.ParseFloat(s, 64)
33+
func (f *floatValue[T]) Set(s string) error {
34+
v, err := strconv.ParseFloat(s, int(unsafe.Sizeof(T(0))*8))
2735
if err != nil {
2836
return err
2937
}
30-
*f = floatValue(v)
31-
return err
38+
*f.val = T(v)
39+
return nil
3240
}
3341

34-
func (f *floatValue) Get() any { return float64(*f) }
42+
func (f *floatValue[T]) Get() any { return *f.val }
3543

36-
func (f *floatValue) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 64) }
44+
func (f *floatValue[T]) String() string {
45+
return strconv.FormatFloat(float64(*f.val), 'g', -1, int(unsafe.Sizeof(T(0))*8))
46+
}
3747

3848
// Float looks up the value of a local FloatFlag, returns
3949
// 0 if not found
4050
func (cmd *Command) Float(name string) float64 {
41-
if v, ok := cmd.Value(name).(float64); ok {
51+
return getFloat[float64](cmd, name)
52+
}
53+
54+
// Float32 looks up the value of a local Float32Flag, returns
55+
// 0 if not found
56+
func (cmd *Command) Float32(name string) float32 {
57+
return getFloat[float32](cmd, name)
58+
}
59+
60+
// Float64 looks up the value of a local Float32Flag, returns
61+
// 0 if not found
62+
func (cmd *Command) Float64(name string) float64 {
63+
return getFloat[float64](cmd, name)
64+
}
65+
66+
func getFloat[T float32 | float64](cmd *Command, name string) T {
67+
if v, ok := cmd.Value(name).(T); ok {
4268
tracef("float available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", name, v, cmd.Name)
69+
4370
return v
4471
}
4572

flag_float_slice.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,42 @@
11
package cli
22

33
type (
4-
FloatSlice = SliceBase[float64, NoConfig, floatValue]
5-
FloatSliceFlag = FlagBase[[]float64, NoConfig, FloatSlice]
4+
FloatSlice = SliceBase[float64, NoConfig, floatValue[float64]]
5+
Float32Slice = SliceBase[float32, NoConfig, floatValue[float32]]
6+
Float64Slice = SliceBase[float64, NoConfig, floatValue[float64]]
7+
FloatSliceFlag = FlagBase[[]float64, NoConfig, FloatSlice]
8+
Float32SliceFlag = FlagBase[[]float32, NoConfig, Float32Slice]
9+
Float64SliceFlag = FlagBase[[]float64, NoConfig, Float64Slice]
610
)
711

8-
var NewFloatSlice = NewSliceBase[float64, NoConfig, floatValue]
12+
var (
13+
NewFloatSlice = NewSliceBase[float64, NoConfig, floatValue[float64]]
14+
NewFloat32Slice = NewSliceBase[float32, NoConfig, floatValue[float32]]
15+
NewFloat64Slice = NewSliceBase[float64, NoConfig, floatValue[float64]]
16+
)
917

1018
// FloatSlice looks up the value of a local FloatSliceFlag, returns
1119
// nil if not found
1220
func (cmd *Command) FloatSlice(name string) []float64 {
13-
if v, ok := cmd.Value(name).([]float64); ok {
21+
return getFloatSlice[float64](cmd, name)
22+
}
23+
24+
// Float32Slice looks up the value of a local Float32Slice, returns
25+
// nil if not found
26+
func (cmd *Command) Float32Slice(name string) []float32 {
27+
return getFloatSlice[float32](cmd, name)
28+
}
29+
30+
// Float64Slice looks up the value of a local Float64SliceFlag, returns
31+
// nil if not found
32+
func (cmd *Command) Float64Slice(name string) []float64 {
33+
return getFloatSlice[float64](cmd, name)
34+
}
35+
36+
func getFloatSlice[T float32 | float64](cmd *Command, name string) []T {
37+
if v, ok := cmd.Value(name).([]T); ok {
1438
tracef("float slice available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", name, v, cmd.Name)
39+
1540
return v
1641
}
1742

flag_float_slice_test.go

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package cli
2+
3+
import (
4+
"io"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
func TestCommand_FloatSlice(t *testing.T) {
12+
tests := []struct {
13+
name string
14+
flag Flag
15+
arguments []string
16+
expect []float64
17+
expectErr bool
18+
}{
19+
{
20+
flag: &FloatSliceFlag{
21+
Name: "numbers",
22+
},
23+
arguments: []string{"--numbers", "1,2,3,4"},
24+
expect: []float64{1, 2, 3, 4},
25+
},
26+
{
27+
flag: &FloatSliceFlag{
28+
Name: "numbers",
29+
},
30+
arguments: []string{"--numbers", "1,2", "--numbers", "3,4"},
31+
expect: []float64{1, 2, 3, 4},
32+
},
33+
}
34+
for _, tt := range tests {
35+
t.Run(tt.name, func(t *testing.T) {
36+
cmd := &Command{
37+
Name: "mock",
38+
Flags: []Flag{tt.flag},
39+
Writer: io.Discard,
40+
ErrWriter: io.Discard,
41+
}
42+
43+
err := cmd.Run(buildTestContext(t), append([]string{"mock"}, tt.arguments...))
44+
45+
if tt.expectErr {
46+
require.Error(t, err)
47+
48+
return
49+
}
50+
51+
require.NoError(t, err)
52+
53+
for _, name := range tt.flag.Names() {
54+
assert.Equalf(t, tt.expect, cmd.FloatSlice(name), "FloatSlice(%v)", name)
55+
}
56+
})
57+
}
58+
}
59+
60+
func TestCommand_Float32Slice(t *testing.T) {
61+
tests := []struct {
62+
name string
63+
flag Flag
64+
arguments []string
65+
expect []float32
66+
expectErr bool
67+
}{
68+
{
69+
flag: &Float32SliceFlag{
70+
Name: "numbers",
71+
},
72+
arguments: []string{"--numbers", "1,2,3,4"},
73+
expect: []float32{1, 2, 3, 4},
74+
},
75+
{
76+
flag: &Float32SliceFlag{
77+
Name: "numbers",
78+
},
79+
arguments: []string{"--numbers", "1,2", "--numbers", "3,4"},
80+
expect: []float32{1, 2, 3, 4},
81+
},
82+
}
83+
for _, tt := range tests {
84+
t.Run(tt.name, func(t *testing.T) {
85+
cmd := &Command{
86+
Name: "mock",
87+
Flags: []Flag{tt.flag},
88+
Writer: io.Discard,
89+
ErrWriter: io.Discard,
90+
}
91+
92+
err := cmd.Run(buildTestContext(t), append([]string{"mock"}, tt.arguments...))
93+
94+
if tt.expectErr {
95+
require.Error(t, err)
96+
97+
return
98+
}
99+
100+
require.NoError(t, err)
101+
102+
for _, name := range tt.flag.Names() {
103+
assert.Equalf(t, tt.expect, cmd.Float32Slice(name), "Float32Slice(%v)", name)
104+
}
105+
})
106+
}
107+
}
108+
109+
func TestCommand_Float64Slice(t *testing.T) {
110+
tests := []struct {
111+
name string
112+
flag Flag
113+
arguments []string
114+
expect []float64
115+
expectErr bool
116+
}{
117+
{
118+
flag: &Float64SliceFlag{
119+
Name: "numbers",
120+
},
121+
arguments: []string{"--numbers", "1,2,3,4"},
122+
expect: []float64{1, 2, 3, 4},
123+
},
124+
{
125+
flag: &Float64SliceFlag{
126+
Name: "numbers",
127+
},
128+
arguments: []string{"--numbers", "1,2", "--numbers", "3,4"},
129+
expect: []float64{1, 2, 3, 4},
130+
},
131+
}
132+
for _, tt := range tests {
133+
t.Run(tt.name, func(t *testing.T) {
134+
cmd := &Command{
135+
Name: "mock",
136+
Flags: []Flag{tt.flag},
137+
Writer: io.Discard,
138+
ErrWriter: io.Discard,
139+
}
140+
141+
err := cmd.Run(buildTestContext(t), append([]string{"mock"}, tt.arguments...))
142+
143+
if tt.expectErr {
144+
require.Error(t, err)
145+
146+
return
147+
}
148+
149+
require.NoError(t, err)
150+
151+
for _, name := range tt.flag.Names() {
152+
assert.Equalf(t, tt.expect, cmd.Float64Slice(name), "Float64Slice(%v)", name)
153+
}
154+
})
155+
}
156+
}

0 commit comments

Comments
 (0)