Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ enumeration values either with a single flag `--mode=foo,bar` or multiple flag
calls, such as `--mode=foo --mode=bar`.

Application programmers then simply deal with enumeration values in form of
uints (or ints, _erm_, anything that satisfies `constraints.Integer`s),
uints (or ints, _erm_, anything that satisfies `constraints.Ordered`s),
liberated from parsing strings and validating enumeration flags.

For devcontainer instructions, please see the [section "DevContainer"
Expand Down Expand Up @@ -76,7 +76,7 @@ import (
)

// ① Define your new enum flag type. It can be derived from enumflag.Flag,
// but it doesn't need to be as long as it satisfies constraints.Integer.
// but it doesn't need to be as long as it satisfies constraints.Ordered.
type FooMode enumflag.Flag

// ② Define the enumeration values for FooMode.
Expand Down Expand Up @@ -306,7 +306,7 @@ import (
)

// ① Define your new enum flag type. It can be derived from enumflag.Flag,
// but it doesn't need to be as long as it satisfies constraints.Integer.
// but it doesn't need to be as long as it satisfies constraints.Ordered.
type MooMode enumflag.Flag

// ② Define the enumeration values for FooMode.
Expand Down
2 changes: 1 addition & 1 deletion completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
// value prefix. The reason is that enumflag will automatically register the
// correct (erm, “complete”) completion text. Please note that it isn't
// necessary to supply any help texts in order to register enum flag completion.
type Help[E constraints.Integer] map[E]string
type Help[E constraints.Ordered] map[E]string

// Completor tells cobra how to complete a flag. See also cobra's [dynamic flag
// completion] documentation.
Expand Down
3 changes: 2 additions & 1 deletion example_nodefault_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import (
"fmt"

"github.com/spf13/cobra"

"github.com/thediveo/enumflag/v2"
)

// ① Define your new enum flag type. It can be derived from enumflag.Flag,
// but it doesn't need to be as long as it satisfies constraints.Integer.
// but it doesn't need to be as long as it satisfies constraints.Ordered.
type BarMode enumflag.Flag

// ② Define the enumeration values for BarMode.
Expand Down
3 changes: 2 additions & 1 deletion example_slice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import (
"fmt"

"github.com/spf13/cobra"

"github.com/thediveo/enumflag/v2"
)

// ① Define your new enum flag type. It can be derived from enumflag.Flag,
// but it doesn't need to be as long as it satisfies constraints.Integer.
// but it doesn't need to be as long as it satisfies constraints.Ordered.
type MooMode enumflag.Flag

// ② Define the enumeration values for FooMode.
Expand Down
3 changes: 2 additions & 1 deletion example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import (
"fmt"

"github.com/spf13/cobra"

"github.com/thediveo/enumflag/v2"
)

// ① Define your new enum flag type. It can be derived from enumflag.Flag,
// but it doesn't need to be as long as it satisfies constraints.Integer.
// but it doesn't need to be as long as it satisfies constraints.Ordered.
type FooMode enumflag.Flag

// ② Define the enumeration values for FooMode.
Expand Down
26 changes: 13 additions & 13 deletions flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import (
// However, applications don't need to base their own enum types on Flag. The
// only requirement for user-defined enumeration flags is that they must be
// (“somewhat”) compatible with the Flag type, or more precise: user-defined
// enumerations must satisfy [constraints.Integer].
// enumerations must satisfy [constraints.Ordered].
type Flag uint

// EnumCaseSensitivity specifies whether the textual representations of enum
Expand All @@ -46,11 +46,11 @@ const (
)

// EnumFlagValue wraps a user-defined enum type value satisfying
// [constraints.Integer] or [][constraints.Integer]. It implements the
// [constraints.Ordered] or [][constraints.Ordered]. It implements the
// [github.com/spf13/pflag.Value] interface, so the user-defined enum type value
// can directly be used with the fine pflag drop-in package for Golang CLI
// flags.
type EnumFlagValue[E constraints.Integer] struct {
type EnumFlagValue[E constraints.Ordered] struct {
value enumValue[E] // enum value of a user-defined enum scalar or slice type.
enumtype string // user-friendly name of the user-defined enum type.
names enumMapper[E] // enum value names.
Expand All @@ -63,26 +63,26 @@ type EnumFlagValue[E constraints.Integer] struct {
// code”: by just moving the interface type from the source file with the struct
// types to the source file with the consumer we achieve immediate Go
// perfectness! Strike!
type enumValue[E constraints.Integer] interface {
type enumValue[E constraints.Ordered] interface {
Get() any
Set(val string, names enumMapper[E]) error
String(names enumMapper[E]) string
NewCompletor(enums EnumIdentifiers[E], help Help[E]) Completor
}

// New wraps a given enum variable (satisfying [constraints.Integer]) so that it
// New wraps a given enum variable (satisfying [constraints.Ordered]) so that it
// can be used as a flag Value with [github.com/spf13/pflag.Var] and
// [github.com/spf13/pflag.VarP]. In case no default enum value should be set
// and therefore no default shown in [spf13/cobra], use [NewWithoutDefault]
// instead.
//
// [spf13/cobra]: https://github.com/spf13/cobra
func New[E constraints.Integer](flag *E, typename string, mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) *EnumFlagValue[E] {
func New[E constraints.Ordered](flag *E, typename string, mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) *EnumFlagValue[E] {
return new("New", flag, typename, mapping, sensitivity, false)
}

// NewWithoutDefault wraps a given enum variable (satisfying
// [constraints.Integer]) so that it can be used as a flag Value with
// [constraints.Ordered]) so that it can be used as a flag Value with
// [github.com/spf13/pflag.Var] and [github.com/spf13/pflag.VarP]. Please note
// that the zero enum value must not be mapped and thus not be assigned to any
// enum value textual representation.
Expand All @@ -91,14 +91,14 @@ func New[E constraints.Integer](flag *E, typename string, mapping EnumIdentifier
// created with NewWithoutDefault.
//
// [spf13/cobra]: https://github.com/spf13/cobra
func NewWithoutDefault[E constraints.Integer](flag *E, typename string, mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) *EnumFlagValue[E] {
func NewWithoutDefault[E constraints.Ordered](flag *E, typename string, mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) *EnumFlagValue[E] {
return new("NewWithoutDefault", flag, typename, mapping, sensitivity, true)
}

// new returns a new enum variable to be used with pflag.Var and pflag.VarP.
func new[E constraints.Integer](ctor string, flag *E, typename string, mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity, nodefault bool) *EnumFlagValue[E] {
func new[E constraints.Ordered](ctor string, flag *E, typename string, mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity, nodefault bool) *EnumFlagValue[E] {
if flag == nil {
panic(fmt.Sprintf("%s requires flag to be a non-nil pointer to an enum value satisfying constraints.Integer", ctor))
panic(fmt.Sprintf("%s requires flag to be a non-nil pointer to an enum value satisfying constraints.Ordered", ctor))
}
if mapping == nil {
panic(fmt.Sprintf("%s requires mapping not to be nil", ctor))
Expand All @@ -110,12 +110,12 @@ func new[E constraints.Integer](ctor string, flag *E, typename string, mapping E
}
}

// NewSlice wraps a given enum slice variable (satisfying [constraints.Integer])
// NewSlice wraps a given enum slice variable (satisfying [constraints.Ordered])
// so that it can be used as a flag Value with [github.com/spf13/pflag.Var] and
// [github.com/spf13/pflag.VarP].
func NewSlice[E constraints.Integer](flag *[]E, typename string, mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) *EnumFlagValue[E] {
func NewSlice[E constraints.Ordered](flag *[]E, typename string, mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) *EnumFlagValue[E] {
if flag == nil {
panic("NewSlice requires flag to be a non-nil pointer to an enum value slice satisfying []constraints.Integer")
panic("NewSlice requires flag to be a non-nil pointer to an enum value slice satisfying []any")
}
if mapping == nil {
panic("NewSlice requires mapping not to be nil")
Expand Down
9 changes: 5 additions & 4 deletions mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@ import (
// representation (identifier). If more than one textual representation exists
// for the same enumeration value, then the first textual representation is
// considered to be the canonical one.
type EnumIdentifiers[E constraints.Integer] map[E][]string
type EnumIdentifiers[E constraints.Ordered] map[E][]string

// enumMapper is an optionally case insensitive map from enum values to their
// corresponding textual representations.
type enumMapper[E constraints.Integer] struct {
type enumMapper[E constraints.Ordered] struct {
m EnumIdentifiers[E]
sensitivity EnumCaseSensitivity
}

// newEnumMapper returns a new enumMapper for the given mapping and case
// sensitivity or insensitivity.
func newEnumMapper[E constraints.Integer](mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) enumMapper[E] {
func newEnumMapper[E constraints.Ordered](mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) enumMapper[E] {
return enumMapper[E]{
m: mapping,
sensitivity: sensitivity,
Expand Down Expand Up @@ -81,7 +81,8 @@ func (m enumMapper[E]) ValueOf(name string) (E, error) {
allids = append(allids, strings.Join(s, "/"))
}
sort.Strings(allids)
return 0, fmt.Errorf("must be %s", strings.Join(allids, ", "))
var zero E
return zero, fmt.Errorf("must be %s", strings.Join(allids, ", "))
}

// Mapping returns the mapping of enum values to their names.
Expand Down
5 changes: 3 additions & 2 deletions value_scalar.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const unknown = "<unknown>"

// enumScalar represents a mutable, single enumeration value that can be
// retrieved, set, and stringified.
type enumScalar[E constraints.Integer] struct {
type enumScalar[E constraints.Ordered] struct {
v *E
nodefault bool // opts in to accepting a zero enum value as the "none"
}
Expand Down Expand Up @@ -60,7 +60,8 @@ func (s *enumScalar[E]) String(names enumMapper[E]) string {
if ids := names.Lookup(*s.v); len(ids) > 0 {
return ids[0]
}
if *s.v == 0 && s.nodefault {
var zero E
if *s.v == zero && s.nodefault {
return ""
}
return unknown
Expand Down
2 changes: 1 addition & 1 deletion value_slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (

// enumSlice represents a slice of enumeration values that can be retrieved,
// set, and stringified.
type enumSlice[E constraints.Integer] struct {
type enumSlice[E constraints.Ordered] struct {
v *[]E
merge bool // replace the complete slice or merge values?
}
Expand Down