An open API service indexing awesome lists of open source software.

https://github.com/xybor-x/enum

Elegant and powerful Go enums with zero code generation
https://github.com/xybor-x/enum

enum go go-enum golang-library serialization

Last synced: 1 day ago
JSON representation

Elegant and powerful Go enums with zero code generation

Awesome Lists containing this project

README

          

[![Go Reference](https://pkg.go.dev/badge/github.com/xybor-x/enum.svg)](https://pkg.go.dev/github.com/xybor-x/enum)
[![GitHub top language](https://img.shields.io/github/languages/top/xybor-x/enum?color=lightblue)](https://go.dev/)
[![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/xybor-x/enum)](https://go.dev/blog/go1.21)
[![GitHub release (release name instead of tag name)](https://img.shields.io/github/v/release/xybor-x/enum?include_prereleases)](https://github.com/xybor-x/enum/releases/latest)
[![GitHub Repo stars](https://img.shields.io/github/stars/xybor-x/enum?color=blue)](https://github.com/xybor-x/enum)

![Golang](./.github/go-enum.png)

# ⚙️ Go Enum

**Elegant, powerful, and dependency-free enums for Go with zero code generation!**

> [!TIP]
> This is just a ⚡ quick tutorial for general use cases.
> See more advanced features at the [documentation](./docs.md).

## 🔧 Installation

```sh
go get -u github.com/xybor-x/enum
```

## ⚡ Quick start

### Define enums

```go
package main

import "github.com/xybor-x/enum"

type role any
type Role = enum.WrapEnum[role]

const (
RoleUser Role = iota
RoleAdmin
)

func init() {
enum.Map(RoleUser, "user")
enum.Map(RoleAdmin, "admin")
enum.Finalize[Role]()
}
```

> [!CAUTION]
> Enum definitions are not thread-safe.
> Therefore, they should be finalized during initialization (at the global scope).

### Usage

```go
package main

import (
"encoding/json"
"fmt"
)

type User struct {
Role Role `json:"role"`
}

func main() {
// Print out the string representation of enum.
fmt.Println(RoleAdmin) // Output: admin

// Serialize a user to json.
user := User{Role: RoleUser}
data, _ := json.Marshal(user)
fmt.Println(string(data)) // Output: {"role": "user"}
}
```

### Nullable fields

```go
package main

import (
"encoding/json"
"fmt"
)

// NullRole is similar to sql.NullXXX, designed to handle nullable SQL and JSON fields.
type NullRole = enum.Nullable[Role]

type User struct {
Role NullRole `json:"role"`
}

func main() {
// Serialize a nullable role with a non-null value.
user := User{Role: NullRole{Enum: RoleUser, Valid: true}}
data, _ := json.Marshal(user)
fmt.Println(string(data)) // Output: {"role": "user"}

// Serialize a nullable role with a null value.
data, _ = json.Marshal(User{})
fmt.Println(string(data)) // Output: {"role": null}
}
```

### Integrate with protobuf

*Refer to the [Integration Guide](./docs.md#-integrate-with-other-enum-systems) for details.*

Suppose we have a protobuf enum defined as follows:

```go
// Code generated by protoc-gen-go.
package proto

type Role int32

const (
Role_User Role = 0
Role_Admin Role = 1
)

...
```

We can integrate them into `xybor-x/enum`. Here's an example:

```go
package main

import (
"path/to/proto"
"github.com/xybor-x/enum"
)

type Role = enum.WrapEnum[proto.Role]

const (
RoleUser Role = iota
RoleAdmin
)

func init() {
// Map the enum to protobuf enum value.
enum.Map(RoleUser, proto.Role_User)
enum.Map(RoleAdmin, proto.Role_Admin)
enum.Finalize[Role]()
}

func main() {
// Convert from the protobuf enum to the Role enum.
role, ok := enum.From[Role](proto.Role_User)
// ok == true && role == RoleUser

// Convert from the Role enum to the protobuf enum.
role = RoleAdmin.To()
// role == proto.Role_Admin

// The string representation of these enums is inherited from proto.Role.
fmt.Println(RoleUser) // Output: User
}
```

## 📈 Performance

While it's true that the `xybor-x/enum` approach will generally be slower than the code generation approaches, I still want to highlight the difference.

The benchmark results are based on defining an enum with 10 values at [bench](./bench).

| | Code generation | `xybor-x/enum` |
| ----------------- | --------------: | -------------: |
| ToString | 6 ns | 17 ns |
| FromString | 15 ns | 22 ns |
| json.Marshal | 113 ns | 148 ns |
| json.Unmarshal | 147 ns | 144 ns |
| SQL Value | 29 ns | 38 ns |
| SQL Scan (bytes) | 29 ns | 41 ns |
| SQL Scan (string) | 15 ns | 22 ns |