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
- Host: GitHub
- URL: https://github.com/xybor-x/enum
- Owner: xybor-x
- License: apache-2.0
- Created: 2024-12-06T12:33:56.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2025-01-02T15:00:54.000Z (about 1 year ago)
- Last Synced: 2025-11-15T14:12:10.107Z (2 months ago)
- Topics: enum, go, go-enum, golang-library, serialization
- Language: Go
- Homepage:
- Size: 298 KB
- Stars: 41
- Watchers: 3
- Forks: 4
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
[](https://pkg.go.dev/github.com/xybor-x/enum)
[](https://go.dev/)
[](https://go.dev/blog/go1.21)
[](https://github.com/xybor-x/enum/releases/latest)
[](https://github.com/xybor-x/enum)

# ⚙️ 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 |