Skip to content

lvyahui8/goenum

Repository files navigation

Go enumeration template implementation

License Go Report Card codecov

中文文档

How to define and use enumerations?

Simply embed goenum.Enum into a struct to define an enumeration type and automatically obtain a set of instance methods and utility functions.

go get github.com/lvyahui8/goenum
import "github.com/lvyahui8/goenum" // Declaring an enumeration type type State struct { goenum.Enum } // Defines a set of enumeration instances var ( Created = goenum.NewEnum[State]("Created") Running = goenum.NewEnum[State]("Running") Success = goenum.NewEnum[State]("Success") ) // Usage Created.Name() // string "Created" Created.Ordinal() // int 0 Created.Compare(Running) // < 0 : Created < Running Created.String() // Created json.Marshal(Created) // \"Created\" IsValidEnum[State]("Created") // true s,valid := goenum.ValueOf[State]("Created") // s: Created(struct instance) ,valid = true Created.Equals(s) // true s,valid := goenum.ValueOf[State]("cReaTed") // s: Created(struct instance) ,valid = true Created.Equals(s) // true goenum.Values[State]() // equals []State{Created,Running,Success} Size[State]() // = 3

More Examples examples

Instance Methods

type EnumDefinition interface { fmt.Stringer json.Marshaler encoding.TextMarshaler // Name The name of the enumeration. The enumeration names of the same Type must be unique. Name() string // Equals Compare with another enumeration. Only return true if both Type and Name are the same Equals(other EnumDefinition) bool // Type String representation of enumeration type Type() string // Ordinal Get the ordinal of the enumeration, starting from zero and increasing in declared order. Ordinal() int // Compare -Compare with the ordinal value of another enumeration Compare(other EnumDefinition) int }

Utility functions

  • ValueOf: Find an enumeration instance based on the string, and return a zero value if not found
  • ValueOfIgnoreCase: Ignoring case to obtain enumeration instances.
  • Values: Return all enumeration instances. The returned slice are sorted by ordinal
  • Size: Number of instances of specified enumeration type
  • GetEnumMap: Get all enumeration instances of the specified type.
  • EnumNames: Get the names of a batch of enumerations.
  • GetEnums: Obtain a batch of enumeration instances based on the enumeration name list
  • IsValidEnum: Determine if the incoming string is a valid enumeration
func TestHelpers(t *testing.T) { t.Run("NewEnum", func(t *testing.T) { defer func() { err := recover() require.NotNil(t, err) require.Equal(t, "Enum must be unique", err)	}() _ = goenum.NewEnum[Role]("Owner")	}) t.Run("ValueOf", func(t *testing.T) { r, valid := goenum.ValueOf[Role]("Owner") require.True(t, valid) require.True(t, Owner.Equals(r)) r, valid = goenum.ValueOf[Role]("Owner") require.True(t, valid) require.False(t, Developer.Equals(r))	}) t.Run("ValueOfIgnoreCase", func(t *testing.T) { r, valid := goenum.ValueOfIgnoreCase[Role]("oWnEr") require.True(t, valid) require.True(t, Owner.Equals(r)) r, valid = goenum.ValueOfIgnoreCase[Role]("oWnEr") require.True(t, valid) require.False(t, Reporter.Equals(r))	}) t.Run("Values", func(t *testing.T) { require.True(t, reflect.DeepEqual([]Role{Reporter, Developer, Owner}, goenum.Values[Role]()))	}) t.Run("GetEnumMap", func(t *testing.T) { enumMap := goenum.GetEnumMap[Role]() require.True(t, len(enumMap) == 3) role, exist := enumMap["Owner"] require.True(t, exist) require.True(t, role.Equals(Owner))	}) t.Run("EnumNames", func(t *testing.T) { require.True(t, reflect.DeepEqual([]string{"Owner", "Developer"}, goenum.EnumNames(Owner, Developer)))	}) t.Run("GetEnums", func(t *testing.T) { res, valid := goenum.GetEnums[Role]("Owner", "Developer") require.True(t, valid) require.True(t, reflect.DeepEqual([]Role{Owner, Developer}, res)) _, valid = goenum.GetEnums[Role]("a", "b") require.False(t, valid)	}) t.Run("IsValidEnum", func(t *testing.T) { require.True(t, goenum.IsValidEnum[Role]("Owner")) require.False(t, goenum.IsValidEnum[Role]("Test"))	}) }

More features

Complex enumeration initialization

The second parameter in the NewEnum function, if a Src is passed in, NewEnum will use the passed object to construct an enumeration instance.

example code gitlab_role_perms

type Module struct {	goenum.Enum perms []Permission basePath string } func (m Module) GetPerms() []Permission { return m.perms } func (m Module) BasePath() string { return m.basePath } // 定义模块 var ( Issues = goenum.NewEnum[Module]("Issues", Module{perms: []Permission{AddLabels, AddTopic}, basePath: "/issues/"}) MergeRequests = goenum.NewEnum[Module]("MergeRequests", Module{perms: []Permission{ViewMergeRequest, ApproveMergeRequest, DeleteMergeRequest}, basePath: "/merge/"}) )

JSON serialization and deserialization support for enumerating instances

JSON serialization is already supported by default. Restricted by the implementation of the go JSON library, enumeration classes are required to implement JSON Unmarshaler interface to realize deserialization. Call Unmarshal tool function in the interface to obtain enumeration instances.

type Member struct { Roles []Role } type Role struct {	goenum.Enum perms []Permission } func (r *Role) UnmarshalJSON(data []byte) (err error) { role, err := goenum.Unmarshal[Role](data) if err == nil { *r = role	} return } t.Run("jsonMarshal", func(t *testing.T) { bytes, err := json.Marshal(Developer) require.Nil(t, err) require.Equal(t, "\"Developer\"", string(bytes)) member := Member{Roles: []Role{Reporter, Owner}} bytes, err = json.Marshal(member) require.Nil(t, err) require.Equal(t, "{\"Roles\":[\"Reporter\",\"Owner\"]}", string(bytes)) }) t.Run("jsonUnmarshal", func(t *testing.T) { newMember := Member{} err := json.Unmarshal([]byte("{\"Roles\":[\"Reporter\",\"Owner\"]}"), &newMember) require.Nil(t, err) require.True(t, reflect.DeepEqual([]Role{Reporter, Owner}, newMember.Roles)) })

EnumSet

api声明

// EnumSet Enumerate sets. Usually used for high-performance lookup when // there are many instances of a certain type of enumeration. type EnumSet[E EnumDefinition] interface { fmt.Stringer json.Marshaler // Add -Add an element to Set. If successful, return true. If it already exists, return false Add(e E) bool // AddRange According to the ordinal of the enumeration, // add a continuous section of the enumeration and // return the actual number added (excluding those that already exist) AddRange(begin, end E) int // Remove Delete element. If the deletion is successful, return true. // If the element does not exist, return false Remove(e E) bool // RemoveRange According to the ordinal of the enumeration, // continuously delete a segment of the enumeration and // return the actual number of deletions (excluding those that non-exist) RemoveRange(begin, end E) int // IsEmpty Is Set empty IsEmpty() bool // Clear -Clear set Clear() // Len The current number of enumeration instances within the Set Len() int // Contains Does it contain the specified enumeration? // Returns false if there is only one that does not exist in the Set Contains(enums ...E) bool // ContainsAll Determine if it contains another enumSet (subset relationship) ContainsAll(set EnumSet[E]) bool // Equals Determine if two EnumSets are the same Equals(set EnumSet[E]) bool // Each Set iteration method, if f method returns false, abort iteration Each(f func(e E) bool) // Names Returns the Name representation of an existing enumeration instance in the set Names() []string // Clone Deep copy to obtain a new set Clone() EnumSet[E] }

EnumSet usage

stmtSet := NewUnsafeEnumSet[Statement]() stmtSet.Add(Decl) stmtSet.IsEmpty() stmtSet.Contains(Decl) stmtSet.Len() == 1 stmtSet.AddRange(Comm, Range) stmtSet.Remove(Decl)

Example code enum_set_test

ValueOf Performance

Don't worry about any performance issues, reflection calls are mostly only used in NewEnum methods, and other methods will try to avoid reflection calls as much as possible.

goos: linux goarch: arm64 pkg: github.com/lvyahui8/goenum/internal BenchmarkValueOf/ValueOf-4 1000000000 0.0002492 ns/op 0 B/op 0 allocs/op BenchmarkValueOf/ValueOf-4 1000000000 0.0002966 ns/op 0 B/op 0 allocs/op BenchmarkValueOf/ValueOf-4 1000000000 0.0002713 ns/op 0 B/op 0 allocs/op BenchmarkValueOf/ValueOfIgnoreCase-4 1000000000 0.002228 ns/op 0 B/op 0 allocs/op BenchmarkValueOf/ValueOfIgnoreCase-4 1000000000 0.002611 ns/op 0 B/op 0 allocs/op BenchmarkValueOf/ValueOfIgnoreCase-4 1000000000 0.002606 ns/op 0 B/op 0 allocs/op PASS ok github.com/lvyahui8/goenum/internal 0.097s 

Packages

 
 
 

Contributors

Languages