diff --git a/enum.go b/enum.go index 79413ff..e2cb040 100644 --- a/enum.go +++ b/enum.go @@ -12,6 +12,12 @@ type Member[T comparable] struct { Value T } +// Equaler provides the customr comparator for value type. +type Equaler[V comparable] interface { + Equal(v V) bool + comparable +} + // iMember is the type constraint for Member used by Enum. // // We can't use Member directly in type constraints @@ -150,6 +156,20 @@ func (e Enum[M, V]) GoString() string { return fmt.Sprintf("enum.New(%s)", joined) } +// Parse converts a raw value into a member like Enum.Parse. But, +// this returns the equal member by Equal(). +// +// This is especially beneficial when the value type is struct, which +// means that be able to implement a custom comparator. +func Parse[M iMember[V], V Equaler[V]](e Enum[M, V], value V) *M { + for v, m := range e.v2m { + if v.Equal(value) { + return m + } + } + return nil +} + // Builder is a constructor for an [Enum]. // // Use [Builder.Add] to add new members to the future enum diff --git a/enum_test.go b/enum_test.go index 5c696ad..4b36889 100644 --- a/enum_test.go +++ b/enum_test.go @@ -125,3 +125,38 @@ func TestBuilder(t *testing.T) { ) is.Equal(Countries.Members(), []Country{NL, FR, BE}) } + +type BookValue struct { + Title string + ISBN string +} +type Book enum.Member[BookValue] + +var ( + EfficientGo = Book{BookValue{"Efficient Go", "978-1098105716"}} + ConcurrencyInGo = Book{BookValue{"Concurrency in Go", "978-1491941195"}} + Books = enum.New(EfficientGo, ConcurrencyInGo) +) + +func (b BookValue) Equal(v BookValue) bool { + return b.ISBN == v.ISBN +} + +func TestParse(t *testing.T) { + is := is.New(t) + tests := []struct { + isbn string + want *Book + }{ + {"978-1098105716", &EfficientGo}, + {"978-1491941195", &ConcurrencyInGo}, + {"invalid-isbn", nil}, + } + for _, tt := range tests { + t.Run(tt.isbn, func(t *testing.T) { + v := BookValue{ISBN: tt.isbn} + got := enum.Parse(Books, v) + is.Equal(got, tt.want) + }) + } +}