package fsimport ( "encoding/json" "fmt" "strings")// Enum is an option which can only be one of the Choices.//// Suggested implementation is something like this://// type choice = Enum[choices]//// const (// choiceA choice = iota// choiceB// choiceC// )//// type choices struct{}//// func (choices) Choices() []string {// return []string{// choiceA: "A",// choiceB: "B",// choiceC: "C",// }// }type Enum[C Choices] byte// Choices returns the valid choices for this type.//// It must work on the zero value.//// Note that when using this in an Option the ExampleChoices will be// filled in automatically.type Choices interface { // Choices returns the valid choices for this type Choices() []string}// String renders the Enum as a stringfunc (e Enum[C]) String() string { choices := e.Choices() if int(e) >= len(choices) { return fmt.Sprintf("Unknown(%d)", e) } return choices[e]}// Choices returns the possible values of the Enum.func (e Enum[C]) Choices() []string { var c C return c.Choices()}// Help returns a comma separated list of all possible states.func (e Enum[C]) Help() string { return strings.Join(e.Choices(), ", ")}// Set the Enum entriesfunc (e *Enum[C]) Set(s string) error { for i, choice := range e.Choices() { if strings.EqualFold(s, choice) { *e = Enum[C](i) return nil } } return fmt.Errorf("invalid choice %q from: %s", s, e.Help())}// Type of the value.//// If C has a Type() string method then it will be used instead.func (e Enum[C]) Type() string { var c C if do, ok := any(c).(typer); ok { return do.Type() } return strings.Join(e.Choices(), "|")}// Scan implements the fmt.Scanner interfacefunc (e *Enum[C]) Scan(s fmt.ScanState, ch rune) error { token, err := s.Token(true, nil) if err != nil { return err } return e.Set(string(token))}// UnmarshalJSON parses it as a string or an integerfunc (e *Enum[C]) UnmarshalJSON(in []byte) error { choices := e.Choices() return UnmarshalJSONFlag(in, e, func(i int64) error { if i < 0 || i >= int64(len(choices)) { return fmt.Errorf("%d is out of range: must be 0..%d", i, len(choices)) } *e = Enum[C](i) return nil })}// MarshalJSON encodes it as stringfunc (e *Enum[C]) MarshalJSON() ([]byte, error) { return json.Marshal(e.String())}
package fs
import (
"encoding/json"
"fmt"
"strings"
)
// Enum is an option which can only be one of the Choices.
//
// Suggested implementation is something like this:
//
// type choice = Enum[choices]
//
// const (
// choiceA choice = iota
// choiceB
// choiceC
// )
//
// type choices struct{}
//
// func (choices) Choices() []string {
// return []string{
// choiceA: "A",
// choiceB: "B",
// choiceC: "C",
// }
// }
type Enum[C Choices] byte
// Choices returns the valid choices for this type.
//
// It must work on the zero value.
//
// Note that when using this in an Option the ExampleChoices will be
// filled in automatically.
type Choices interface {
// Choices returns the valid choices for this type
Choices() []string
}
// String renders the Enum as a string
func (e Enum[C]) String() string {
choices := e.Choices()
if int(e) >= len(choices) {
return fmt.Sprintf("Unknown(%d)", e)
}
return choices[e]
}
// Choices returns the possible values of the Enum.
func (e Enum[C]) Choices() []string {
var c C
return c.Choices()
}
// Help returns a comma separated list of all possible states.
func (e Enum[C]) Help() string {
return strings.Join(e.Choices(), ", ")
}
// Set the Enum entries
func (e *Enum[C]) Set(s string) error {
for i, choice := range e.Choices() {
if strings.EqualFold(s, choice) {
*e = Enum[C](i)
return nil
}
}
return fmt.Errorf("invalid choice %q from: %s", s, e.Help())
}
// Type of the value.
//
// If C has a Type() string method then it will be used instead.
func (e Enum[C]) Type() string {
var c C
if do, ok := any(c).(typer); ok {
return do.Type()
}
return strings.Join(e.Choices(), "|")
}
// Scan implements the fmt.Scanner interface
func (e *Enum[C]) Scan(s fmt.ScanState, ch rune) error {
token, err := s.Token(true, nil)
if err != nil {
return err
}
return e.Set(string(token))
}
// UnmarshalJSON parses it as a string or an integer
func (e *Enum[C]) UnmarshalJSON(in []byte) error {
choices := e.Choices()
return UnmarshalJSONFlag(in, e, func(i int64) error {
if i < 0 || i >= int64(len(choices)) {
return fmt.Errorf("%d is out of range: must be 0..%d", i, len(choices))
}
*e = Enum[C](i)
return nil
})
}
// MarshalJSON encodes it as string
func (e *Enum[C]) MarshalJSON() ([]byte, error) {
return json.Marshal(e.String())
}