Home

Awesome

go-enum-encoding

Go Report Card Go Reference codecov go-recipes OpenSSF Scorecard

go install github.com/nikolaydubina/go-enum-encoding@latest
type Color struct{ c uint8 }

//go:generate go-enum-encoding -type=Color
var (
	UndefinedColor = Color{} 	// json:""
	Red            = Color{1}	// json:"red"
	Green          = Color{2}	// json:"green"
	Blue           = Color{3}	// json:"blue"
)

It also works with raw iota enums:

type Size uint8

//go:generate go-enum-encoding -type=Size
const (
	UndefinedSize Size = iota // json:""
	Small                     // json:"small"
	Large                     // json:"large"
	XLarge                    // json:"xlarge"
)

Related Work and References

<details><summary>Appendix: Performance</summary>

@mishak87 proposed to use array instead of map for performance. Similarly, @nikolaydubina faced degradation in performance for loop based array for large enum sets (256 values) while working on fpmoney2 and iso42173.

$ go test -bench=Benchmark -benchmem ./internal/research/map >  map.bench
$ go test -bench=Benchmark -benchmem ./internal/research/inline > inline.bench
$ go test -bench=Benchmark -benchmem ./internal/research/array-loop > array-loop.bench 
$ go test -bench=Benchmark -benchmem ./internal/research/array-index > array-index.bench
$ go test -bench=Benchmark -benchmem ./internal/research/uint-array > uint-array.bench
$ go test -bench=Benchmark -benchmem ./internal/research/uint-inline > uint-inline.bench
$ benchstat -split="XYZ" map.bench inline.bench array-loop.bench array-index.bench uint-array.bench uint-inline.bench
name \ time/op          map.bench    inline.bench  array-loop.bench  array-index.bench  uint-array.bench  uint-inline.bench
MarshalText_Color-16    22.3ns ± 0%    5.3ns ± 0%        7.5ns ± 0%         2.2ns ± 0%        1.9ns ± 0%         5.0ns ± 0%
UnmarshalText_Color-16  11.9ns ± 0%    5.7ns ± 0%       14.5ns ± 0%        11.8ns ± 0%       14.3ns ± 0%         5.7ns ± 0%

name \ alloc/op         map.bench    inline.bench  array-loop.bench  array-index.bench  uint-array.bench  uint-inline.bench
MarshalText_Color-16     0.00B         0.00B             0.00B              0.00B             0.00B              0.00B     
UnmarshalText_Color-16   0.00B         0.00B             0.00B              0.00B             0.00B              0.00B     

name \ allocs/op        map.bench    inline.bench  array-loop.bench  array-index.bench  uint-array.bench  uint-inline.bench
MarshalText_Color-16      0.00          0.00              0.00               0.00              0.00               0.00     
UnmarshalText_Color-16    0.00          0.00              0.00               0.00              0.00               0.00 
</details> <details><summary>Appendix: Stringer</summary>

String() string method is very similar to encoding, howver it does not return error and returns string instead of []byte. To avoid malloc and convenience, stringer option is added to generate it accompanied with tests and benchmarks. First used in tailscale.

</details> </details> <details><summary>Appendix: Custom Methods</summary>

Some enums are encoded directly as underlying basic type, however they have dual custom use through String() string methods and alike. To assist safe migration, custom encode and decode method names are added. First used in tailscale.

</details>

Footnotes

  1. Comparison to other enums methods: http://github.com/nikolaydubina/go-enum-example 2

  2. iso4217 enums performance loop vs map: https://github.com/ferdypruis/iso4217/issues/4

  3. fpmoney: https://github.com/nikolaydubina/fpmoney?tab=readme-ov-file#appendix-a-jsonunmarshal-optimizations