Skip to content

Repository files navigation

GoEnum - A Type-Safe Enum Library for Go

Go Version Go Report Card License: MIT Coverage GoDoc GitHub stars

GoEnum is a powerful, type-safe enumeration library for Go that leverages generics (Go 1.18+) to provide a clean, efficient, and maintainable way to work with enums. It offers a complete solution for defining enum types, managing sets of enum values, and handling common operations including JSON serialization.

🌟 Key Features

  • Type Safety: Leverages Go generics for compile-time type checking
  • Flexible Values: Support for both integer and string-based enum values
  • Rich Metadata: Built-in support for descriptions and aliases
  • Efficient Lookups: Fast value and name-based lookups using maps
  • JSON Support: Full JSON marshaling/unmarshaling support with multiple formats
  • Nil Safety: All methods handle nil cases gracefully
  • Validation: Built-in duplicate value/name checking
  • Extensible: Easy to extend for custom enum types
  • Well Tested: Comprehensive test coverage
  • Clean API: Idiomatic Go code with intuitive interface
  • Composite Enums: Support for bitwise operations and flag combinations
  • Dynamic Loading: Load enums from JSON files, maps, or slices

πŸ“‹ Table of Contents

πŸš€ Installation

go get github.com/abdorrahmani/goenum

Requirements:

  • Go 1.18 or higher (for generics support)

🎯 Quick Start

Here's a minimal example to get started:

package main

import (
    "fmt"
    "github.com/abdorrahmani/goenum"
)

// Define your enum type
type Color struct {
    *goenum.EnumBase
}

// Define enum values
var (
    ColorRed   = Color{goenum.NewEnumBase(1, "RED", "The color red", "CRIMSON")}
    ColorBlue  = Color{goenum.NewEnumBase(2, "BLUE", "The color blue", "AZURE")}
    ColorGreen = Color{goenum.NewEnumBase(3, "GREEN", "The color green", "EMERALD")}
)

// Create an enum set
var Colors = goenum.NewEnumSet[Color]()

func init() {
    // Register enum values
    Colors.Register(ColorRed)
    Colors.Register(ColorBlue)
    Colors.Register(ColorGreen)
}

func main() {
    // Basic usage
    fmt.Println(ColorRed.String())      // "RED"
    fmt.Println(ColorRed.Value())       // 1
    fmt.Println(ColorRed.Description()) // "The color red"
    
    // Lookup by name
    if color, exists := Colors.GetByName("BLUE"); exists {
        fmt.Println(color.Value()) // 2
    }
    
    // Lookup by value
    if color, exists := Colors.GetByValue(3); exists {
        fmt.Println(color.String()) // "GREEN"
    }
}

πŸ“– Basic Usage

1. Defining Enum Types

type Status struct {
    *goenum.EnumBase
}

var (
    StatusPending = Status{goenum.NewEnumBase(0, "PENDING", "Waiting to be processed", "WAITING")}
    StatusActive  = Status{goenum.NewEnumBase(1, "ACTIVE", "Currently active", "RUNNING")}
    StatusDeleted = Status{goenum.NewEnumBase(2, "DELETED", "The item has been deleted", "REMOVED")}
)

2. Creating Enum Sets

var Statuses = goenum.NewEnumSet[Status]()

func init() {
    // Using chainable Register method
    Statuses.Register(StatusPending).
        Register(StatusActive).
        Register(StatusDeleted)
}

// Or in a single line
var Colors = goenum.NewEnumSet[Color]().
    Register(ColorRed).
    Register(ColorBlue).
    Register(ColorGreen)

// Usage
if status, exists := Statuses.GetByName("ACTIVE"); exists {
    fmt.Println(status.Value()) // 1
}

3. Working with Aliases

// Check if an enum has a specific alias
fmt.Println(StatusActive.HasAlias("RUNNING")) // true

// Get all aliases
fmt.Println(StatusActive.Aliases()) // ["RUNNING"]

πŸ”₯ Advanced Features

1. JSON Serialization

The library supports three JSON serialization formats:

  • JSONFormatName (default): Serializes only the enum name
  • JSONFormatValue: Serializes only the enum value
  • JSONFormatFull: Serializes a complete struct with name, value, description, and aliases
// Default format (name only)
data, _ := json.Marshal(StatusActive)
fmt.Println(string(data)) // "ACTIVE"

// Value format
StatusActive.SetJSONConfig(&EnumJSONConfig{Format: JSONFormatValue})
data, _ = json.Marshal(StatusActive)
fmt.Println(string(data)) // 1

// Full format
StatusActive.SetJSONConfig(&EnumJSONConfig{Format: JSONFormatFull})
data, _ = json.Marshal(StatusActive)
fmt.Println(string(data)) // {"name":"ACTIVE","value":1,"description":"Currently active","aliases":["RUNNING"]}

// Unmarshal examples
var status Status
status.EnumBase = &EnumBase{}

// Unmarshal name format
json.Unmarshal([]byte(`"PENDING"`), &status)

// Unmarshal value format
status.SetJSONConfig(&EnumJSONConfig{Format: JSONFormatValue})
json.Unmarshal([]byte(`1`), &status)

// Unmarshal full format
status.SetJSONConfig(&EnumJSONConfig{Format: JSONFormatFull})
json.Unmarshal([]byte(`{"name":"ACTIVE","value":1,"description":"Currently active","aliases":["RUNNING"]}`), &status)

2. String-Based Enums

type Priority struct {
    *goenum.EnumBase
}

var (
    PriorityLow    = Priority{goenum.NewEnumBase("low", "LOW", "Low priority task", "MINOR")}
    PriorityMedium = Priority{goenum.NewEnumBase("medium", "MEDIUM", "Medium priority task", "NORMAL")}
    PriorityHigh   = Priority{goenum.NewEnumBase("high", "HIGH", "High priority task", "URGENT", "CRITICAL")}
)

3. Multiple Aliases

// Define enum with multiple aliases
StatusActive = Status{goenum.NewEnumBase(1, "ACTIVE", "Currently active", "RUNNING", "LIVE", "ONLINE")}

// Check aliases
fmt.Println(StatusActive.HasAlias("LIVE"))    // true
fmt.Println(StatusActive.HasAlias("ONLINE"))  // true
fmt.Println(StatusActive.Aliases())           // ["RUNNING", "LIVE", "ONLINE"]

4. Dynamic Enum Loading

The library supports loading enums from various sources:

// Create a loader
loader := goenum.NewDynamicEnumLoader()

// Load from JSON file
err := loader.LoadFromJSON("enums.json")
if err != nil {
    log.Fatal(err)
}

// Load from directory (all JSON files)
err = loader.LoadFromDirectory("enums/")
if err != nil {
    log.Fatal(err)
}

// Load from map
definitions := map[string]goenum.EnumDefinition{
    "TEST_A": {
        Name:        "TEST_A",
        Value:       1,
        Description: "Test enum A",
        Aliases:     []string{"ALPHA"},
    },
}
err = loader.LoadFromMap(definitions)

// Load from slice
definitions := []goenum.EnumDefinition{
    {
        Name:        "TEST_A",
        Value:       1,
        Description: "Test enum A",
        Aliases:     []string{"ALPHA"},
    },
}
err = loader.LoadFromSlice(definitions)

// Export to JSON
err = loader.ExportToJSON("exported_enums.json")

Example JSON format for enum definitions:

[
  {
    "name": "TEST_A",
    "value": 1,
    "description": "Test enum A",
    "aliases": ["ALPHA"]
  },
  {
    "name": "TEST_B",
    "value": 2,
    "description": "Test enum B",
    "aliases": ["BETA"]
  }
]

Composite Enum Support

The library supports composite enums that can be combined using bitwise operations. This is particularly useful for flag-based enums where multiple values can be combined.

Creating Composite Enums

var (
    FlagA = NewCompositeEnumBase(0, "FLAG_A", "First flag")
    FlagB = NewCompositeEnumBase(1, "FLAG_B", "Second flag")
    FlagC = NewCompositeEnumBase(2, "FLAG_C", "Third flag")
)

Bitwise Operations

Composite enums support the following bitwise operations:

  • Or(other CompositeEnum): Combines two flags using bitwise OR
  • And(other CompositeEnum): Combines two flags using bitwise AND
  • Xor(other CompositeEnum): Combines two flags using bitwise XOR
  • Not(): Inverts the flags using bitwise NOT

Example:

// Combine flags
combined := FlagA.Or(FlagB)  // Results in "FLAG_A|FLAG_B"

// Check if a flag is set
if combined.HasFlag(FlagA) {
    // FlagA is set
}

// Check if flags are empty
if !combined.IsEmpty() {
    // Flags are not empty
}

Type Conversion

The NewCompositeEnumBase function accepts various types for the flag value:

  • uint64: Direct flag value
  • int: Bit position (value will be 1 << position)
  • Other types: Will result in a zero value

πŸ“š API Reference

Enum Interface

type Enum interface {
    String() string
    Value() interface{}
    IsValid() bool
    Description() string
    HasAlias(alias string) bool
    Aliases() []string
}

EnumSet Methods

  • NewEnumSet[T Enum]() *EnumSet[T]: Creates a new enum set
  • Register(enum T) error: Adds an enum to the set
  • GetByName(name string) (T, bool): Retrieves enum by name or alias
  • GetByValue(value interface{}) (T, bool): Retrieves enum by value
  • Contains(enum T) bool: Checks if enum exists in set
  • Values() []T: Returns all registered enum values
  • Names() []string: Returns a slice of all enum names
  • Map() map[string]interface{}: Returns a map of enum names to their values
  • Filter(predicate func(T) bool) []T: Returns a slice of enums that satisfy the given predicate

πŸ’‘ Best Practices

  1. Initialization: Always register enum values in an init() function
  2. Naming: Use uppercase names for enum values (e.g., StatusActive)
  3. Descriptions: Provide meaningful descriptions for better documentation
  4. Aliases: Use aliases for common alternative names
  5. Error Handling: Check registration errors in init()
  6. Type Safety: Use type-safe enums for better compile-time checking
  7. JSON: Implement custom JSON methods when embedding in structs
  8. Validation: Keep enum values unique within a set
  9. Composite Enums: Use bitwise operations for flag combinations
  10. Dynamic Loading: Validate enum definitions before loading

🀝 Contributing

We welcome contributions! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Add tests for your changes
  4. Commit your changes (git commit -m 'feat: add amazing feature')
  5. Push to the branch (git push origin feature/amazing-feature)
  6. Open a Pull Request

Please ensure:

  • Code follows Go conventions
  • Tests pass
  • Documentation is updated

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Acknowledgments

  • Built with Go 1.18+ generics
  • Inspired by enum implementations in Java and C#
  • Uses github.com/stretchr/testify for testing
  • Created with ❀️ by abdorrahmani

About

GoEnum is a powerful, type-safe enumeration library for Go that leverages generics (Go 1.18+) to provide a clean, efficient, and maintainable way to work with enums. It offers a complete solution for defining enum types, managing sets of enum values, and handling common operations including JSON serialization.

Topics

Resources

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

Used by

Contributors

Languages