enum

package module
v1.4.0 Latest Latest
Warning

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

Go to latest
Published: Apr 12, 2024 License: MIT Imports: 4 Imported by: 16

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 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 (*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]) 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