enum

package module
v1.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 17, 2025 License: MIT Imports: 4 Imported by: 43

README

enum

[ 📄 docs ] [ 🐙 github ] [ ❤️ sponsor ]

Type safe enums for Go without code generation or reflection.

😎 Features:

  • Type-safe, thanks to generics.
  • No code generation.
  • No reflection.
  • Well-documented, with working examples for every function.
  • Flexible, supports both static and runtime definitions.
  • Zero-dependency.

📦 Installation

go get github.com/orsinium-labs/enum

🛠️ Usage

Define:

type Color enum.Member[string]

var (
  Red    = Color{"red"}
  Green  = Color{"green"}
  Blue   = Color{"blue"}
  Colors = enum.New(Red, Green, Blue)
)

Parse a raw value (nil is returned for invalid value):

parsed := Colors.Parse("red")

Compare enum members:

parsed == Red
Red != Green

Accept enum members as function arguments:

func SetPixel(x, i int, c Color)

Loop over all enum members:

for _, color := range Colors.Members() {
  // ...
}

Ensure that the enum member belongs to an enum (can be useful for defensive programming to ensure that the caller doesn't construct an enum member manually):

func f(color Color) {
  if !colors.Contains(color) {
    panic("invalid color")
  }
  // ...
}

Define custom methods on enum members:

func (c Color) UnmarshalJSON(b []byte) error {
  return nil
}

Dynamically create enums to pass multiple members in a function:

func SetPixel2(x, y int, colors enum.Enum[Color, string]) {
  if colors.Contains(Red) {
    // ...
  }
}

purple := enum.New(Red, Blue)
SetPixel2(0, 0, purple)

Enum members can be any comparable type, not just strings:

type ColorValue struct {
  UI string
  DB int
}
type Color enum.Member[ColorValue]
var (
  Red    = Color{ColorValue{"red", 1}}
  Green  = Color{ColorValue{"green", 2}}
  Blue   = Color{ColorValue{"blue", 3}}
  Colors = enum.New(Red, Green, Blue)
)

fmt.Println(Red.Value.UI)

If the enum has lots of members and new ones may be added over time, it's easy to forget to register all members in the enum. To prevent this, use enum.Builder to define an enum:

type Color enum.Member[string]

var (
  b      = enum.NewBuilder[string, Color]()
  Red    = b.Add(Color{"red"})
  Green  = b.Add(Color{"green"})
  Blue   = b.Add(Color{"blue"})
  Colors = b.Enum()
)

🤔 QnA

  1. What happens when enums are added in Go itself? I'll keep it alive until someone uses it but I expect the project popularity to quickly die out when there is native language support for enums. When you can mess with the compiler itself, you can do more. For example, this package can't provide an exhaustiveness check for switch statements using enums (maybe only by implementing a linter) but proper language-level enums would most likely have it.
  2. Is it reliable? Yes, pretty much. It has good tests but most importantly it's a small project with just a bit of the actual code that is hard to mess up.
  3. Is it maintained? The project is pretty much feature-complete, so there is nothing for me to commit and release daily. However, I accept contributions (see below).
  4. What if I found a bug? Fork the project, fix the bug, write some tests, and open a Pull Request. I usually merge and release any contributions within a day.

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Parse added in v1.4.0

func Parse[M iMember[V], V Equaler[V]](e Enum[M, V], value V) *M

Parse is like Enum.Parse but finds the member for the value using Equaler comparator.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/orsinium-labs/enum"
)

type FoldedString string

// Equal implements [enum.Equaler].
//
// Compare strings ignoring the case.
func (s FoldedString) Equal(other FoldedString) bool {
	return strings.EqualFold(string(s), string(other))
}

func main() {
	type Color enum.Member[FoldedString]

	var (
		Red    = Color{"red"}
		Green  = Color{"green"}
		Blue   = Color{"blue"}
		Colors = enum.New(Red, Green, Blue)
	)

	parsed := enum.Parse(Colors, "RED")
	fmt.Printf("%#v\n", parsed)
}
Output:
&enum_test.Color{Value:"red"}

Types

type Builder added in v1.3.0

type Builder[M iMember[V], V comparable] struct {
	// contains filtered or unexported fields
}

Builder is a constructor for an Enum.

Use Builder.Add or Builder.AddValue to add new members to the future enum and then call Builder.Enum to create a new Enum with all added members.

Builder is useful for when you have lots of enum members, and new ones are added over time, as the project grows. In such scenario, it's easy to forget to add in the Enum a newly created Member. The builder is designed to prevent that.

func NewBuilder added in v1.3.0

func NewBuilder[V comparable, M iMember[V]]() Builder[M, V]

NewBuilder creates a new Builder, a constructor for an Enum.

Example
package main

import (
	"fmt"

	"github.com/orsinium-labs/enum"
)

func main() {
	type Color enum.Member[string]
	var (
		b      = enum.NewBuilder[string, Color]()
		Red    = b.Add(Color{"red"})
		Green  = b.Add(Color{"green"})
		Blue   = b.Add(Color{"blue"})
		Colors = b.Enum()
	)

	fmt.Println(
		Colors.Contains(Red),
		Colors.Contains(Green),
		Colors.Contains(Blue),
	)
}
Output:
true true true

func NewStrictBuilder added in v1.5.0

func NewStrictBuilder[V comparable, M iMember[V]]() Builder[M, V]

NewStrictBuilder creates a new Builder, a constructor for an Enum, that panics if two members share the same value.

func (*Builder[M, V]) Add added in v1.3.0

func (b *Builder[M, V]) Add(m M) M

Add registers a new Member in the builder.

func (*Builder[M, V]) AddValue added in v1.5.0

func (b *Builder[M, V]) AddValue(v V) M

AddValue registers a new Member in the builder.

func (*Builder[M, V]) Enum added in v1.3.0

func (b *Builder[M, V]) Enum() Enum[M, V]

Enum creates a new Enum with all members registered using Builder.Add.

type Enum

type Enum[M iMember[V], V comparable] struct {
	// contains filtered or unexported fields
}

Enum is a collection of enum members.

Use New to construct a new Enum from a list of members.

func New

func New[V comparable, M iMember[V]](members ...M) Enum[M, V]

New constructs a new Enum wrapping the given enum members.

Example
package main

import (
	"fmt"

	"github.com/orsinium-labs/enum"
)

func main() {
	type Color enum.Member[string]

	var (
		Red    = Color{"red"}
		Green  = Color{"green"}
		Blue   = Color{"blue"}
		Colors = enum.New(Red, Green, Blue)
	)

	fmt.Printf("%#v\n", Colors)
}
Output:
enum.New(enum_test.Color{"red"}, enum_test.Color{"green"}, enum_test.Color{"blue"})

func (Enum[M, V]) Choice added in v1.2.0

func (e Enum[M, V]) Choice(seed int64) *M

Choice returns a randomly selected member of the enum.

A random seed can be given (or be 0 to use time.Now().UnixNano() as the seed). nil is returned only if the Enum contains no members.

func (Enum[M, V]) Contains

func (e Enum[M, V]) Contains(member M) bool

Contains returns true if the enum has the given member.

Example
package main

import (
	"fmt"

	"github.com/orsinium-labs/enum"
)

func main() {
	type Color enum.Member[string]

	var (
		Red    = Color{"red"}
		Green  = Color{"green"}
		Blue   = Color{"blue"}
		Colors = enum.New(Red, Green, Blue)
	)

	contains := Colors.Contains(Red)
	fmt.Println(contains)
}
Output:
true

func (Enum[M, V]) Empty

func (e Enum[M, V]) Empty() bool

Empty returns true if the enum doesn't have any members.

Example
package main

import (
	"fmt"

	"github.com/orsinium-labs/enum"
)

func main() {
	type Color enum.Member[string]

	var (
		Red    = Color{"red"}
		Green  = Color{"green"}
		Blue   = Color{"blue"}
		Colors = enum.New(Red, Green, Blue)
	)

	empty := Colors.Empty()
	fmt.Println(empty)
}
Output:
false

func (Enum[M, V]) GoString

func (e Enum[M, V]) GoString() string

GoString implements fmt.GoStringer interface.

When you print a member using "%#v" format, it will show the enum representation as a valid Go syntax.

Example
package main

import (
	"fmt"

	"github.com/orsinium-labs/enum"
)

func main() {
	type Color enum.Member[string]

	var (
		Red    = Color{"red"}
		Green  = Color{"green"}
		Blue   = Color{"blue"}
		Colors = enum.New(Red, Green, Blue)
	)

	fmt.Printf("%#v\n", Colors)
}
Output:
enum.New(enum_test.Color{"red"}, enum_test.Color{"green"}, enum_test.Color{"blue"})

func (Enum[M, V]) Index

func (e Enum[M, V]) Index(member M) int

Index returns the index of the given member in the enum.

If the given member is not in the enum, it panics. Use Enum.Contains first if you don't know for sure if the member belongs to the enum.

Example
package main

import (
	"fmt"

	"github.com/orsinium-labs/enum"
)

func main() {
	type Color enum.Member[string]

	var (
		Red    = Color{"red"}
		Green  = Color{"green"}
		Blue   = Color{"blue"}
		Colors = enum.New(Red, Green, Blue)
	)

	index := Colors.Index(Green)
	fmt.Println(index)
}
Output:
1

func (Enum[M, V]) Len

func (e Enum[M, V]) Len() int

Len returns how many members the enum has.

Example
package main

import (
	"fmt"

	"github.com/orsinium-labs/enum"
)

func main() {
	type Color enum.Member[string]

	var (
		Red    = Color{"red"}
		Green  = Color{"green"}
		Blue   = Color{"blue"}
		Colors = enum.New(Red, Green, Blue)
	)

	length := Colors.Len()
	fmt.Println(length)
}
Output:
3

func (Enum[M, V]) Members

func (e Enum[M, V]) Members() []M

Members returns a slice of the members in the enum.

Example
package main

import (
	"fmt"

	"github.com/orsinium-labs/enum"
)

func main() {
	type Color enum.Member[string]

	var (
		Red    = Color{"red"}
		Green  = Color{"green"}
		Blue   = Color{"blue"}
		Colors = enum.New(Red, Green, Blue)
	)

	members := Colors.Members()
	fmt.Println(members)
}
Output:
[{red} {green} {blue}]

func (Enum[M, V]) Parse

func (e Enum[M, V]) Parse(value V) *M

Parse converts a raw value into a member of the enum.

If none of the enum members has the given value, nil is returned.

Example
package main

import (
	"fmt"

	"github.com/orsinium-labs/enum"
)

func main() {
	type Color enum.Member[string]

	var (
		Red    = Color{"red"}
		Green  = Color{"green"}
		Blue   = Color{"blue"}
		Colors = enum.New(Red, Green, Blue)
	)

	parsed := Colors.Parse("red")
	fmt.Printf("%#v\n", parsed)
}
Output:
&enum_test.Color{Value:"red"}

func (Enum[M, V]) String

func (e Enum[M, V]) String() string

String implements fmt.Stringer interface.

It returns a comma-separated list of values of the enum members.

Example
package main

import (
	"fmt"

	"github.com/orsinium-labs/enum"
)

func main() {
	type Color enum.Member[string]

	var (
		Red    = Color{"red"}
		Green  = Color{"green"}
		Blue   = Color{"blue"}
		Colors = enum.New(Red, Green, Blue)
	)

	fmt.Println(Colors)
}
Output:
red, green, blue

func (Enum[M, V]) TypeName

func (Enum[M, V]) TypeName() string

TypeName is a string representation of the wrapped type.

Example
package main

import (
	"fmt"

	"github.com/orsinium-labs/enum"
)

func main() {
	type Color enum.Member[string]

	var (
		Red    = Color{"red"}
		Green  = Color{"green"}
		Blue   = Color{"blue"}
		Colors = enum.New(Red, Green, Blue)
	)

	tname := Colors.TypeName()
	fmt.Println(tname)
}
Output:
string

func (Enum[M, V]) Value

func (e Enum[M, V]) Value(member M) V

Value returns the wrapped value of the given enum member.

Example
package main

import (
	"fmt"

	"github.com/orsinium-labs/enum"
)

func main() {
	type Color enum.Member[string]

	var (
		Red    = Color{"red"}
		Green  = Color{"green"}
		Blue   = Color{"blue"}
		Colors = enum.New(Red, Green, Blue)
	)

	value := Colors.Value(Green)
	fmt.Println(value)
}
Output:
green

func (Enum[M, V]) Values

func (e Enum[M, V]) Values() []V

Values returns a slice of values of all members of the enum.

Example
package main

import (
	"fmt"

	"github.com/orsinium-labs/enum"
)

func main() {
	type Color enum.Member[string]

	var (
		Red    = Color{"red"}
		Green  = Color{"green"}
		Blue   = Color{"blue"}
		Colors = enum.New(Red, Green, Blue)
	)

	values := Colors.Values()
	fmt.Println(values)
}
Output:
[red green blue]

type Equaler added in v1.4.0

type Equaler[V comparable] interface {
	Equal(other V) bool
	comparable
}

Equaler check if the two values of the same type are equal.

type Member

type Member[T comparable] struct {
	Value T
}

Member is an enum member, a specific value bound to a variable.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL