Skip to content

Commit 75f6015

Browse files
authored
Merge pull request #14 from coxley/builder-value
builder: Less repetitive 'b.AddValue' + strict mode
2 parents 4d8fb06 + 0a40ceb commit 75f6015

2 files changed

Lines changed: 70 additions & 3 deletions

File tree

enum.go

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,8 @@ func Parse[M iMember[V], V Equaler[V]](e Enum[M, V], value V) *M {
168168

169169
// Builder is a constructor for an [Enum].
170170
//
171-
// Use [Builder.Add] to add new members to the future enum
172-
// and then call [Builder.Enum] to create a new [Enum] with all added members.
171+
// Use [Builder.Add] or [Builder.AddValue] to add new members to the future enum and
172+
// then call [Builder.Enum] to create a new [Enum] with all added members.
173173
//
174174
// Builder is useful for when you have lots of enum members, and new ones
175175
// are added over time, as the project grows. In such scenario, it's easy to forget
@@ -178,11 +178,26 @@ func Parse[M iMember[V], V Equaler[V]](e Enum[M, V], value V) *M {
178178
type Builder[M iMember[V], V comparable] struct {
179179
members []M
180180
finished bool
181+
strict bool
181182
}
182183

183184
// NewBuilder creates a new [Builder], a constructor for an [Enum].
184185
func NewBuilder[V comparable, M iMember[V]]() Builder[M, V] {
185-
return Builder[M, V]{make([]M, 0), false}
186+
return Builder[M, V]{
187+
members: make([]M, 0),
188+
finished: false,
189+
strict: false,
190+
}
191+
}
192+
193+
// NewStrictBuilder creates a new [Builder], a constructor for an [Enum], that panics
194+
// if two members share the same value.
195+
func NewStrictBuilder[V comparable, M iMember[V]]() Builder[M, V] {
196+
return Builder[M, V]{
197+
members: make([]M, 0),
198+
finished: false,
199+
strict: true,
200+
}
186201
}
187202

188203
// Add registers a new [Member] in the builder.
@@ -191,9 +206,29 @@ func (b *Builder[M, V]) Add(m M) M {
191206
return m
192207
}
193208

209+
// AddValue registers a new [Member] in the builder.
210+
func (b *Builder[M, V]) AddValue(v V) M {
211+
m := M{v}
212+
b.members = append(b.members, m)
213+
return m
214+
}
215+
194216
// Enum creates a new [Enum] with all members registered using [Builder.Add].
195217
func (b *Builder[M, V]) Enum() Enum[M, V] {
196218
b.finished = true
219+
if b.strict {
220+
b.panicOnDupe()
221+
}
197222
e := New(b.members...)
198223
return e
199224
}
225+
226+
func (b *Builder[M, V]) panicOnDupe() {
227+
seen := make(map[M]struct{})
228+
for _, m := range b.members {
229+
if _, ok := seen[m]; ok {
230+
panic(fmt.Sprintf("'%v' appears more than once", m))
231+
}
232+
seen[m] = struct{}{}
233+
}
234+
}

enum_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,38 @@ func TestBuilder(t *testing.T) {
126126
is.Equal(Countries.Members(), []Country{NL, FR, BE})
127127
}
128128

129+
func TestBuilderValue(t *testing.T) {
130+
is := is.New(t)
131+
type Country enum.Member[string]
132+
var (
133+
b = enum.NewBuilder[string, Country]()
134+
NL = b.AddValue("Netherlands")
135+
FR = b.AddValue("France")
136+
BE = b.AddValue("Belgium")
137+
Countries = b.Enum()
138+
)
139+
is.Equal(Countries.Members(), []Country{NL, FR, BE})
140+
}
141+
142+
func TestStrictBuilder(t *testing.T) {
143+
// Recover from expected panic
144+
defer func() {
145+
if r := recover(); r != nil {
146+
return
147+
}
148+
}()
149+
150+
type SomeType enum.Member[int]
151+
var (
152+
b = enum.NewStrictBuilder[int, SomeType]()
153+
_ = b.AddValue(1)
154+
_ = b.AddValue(1)
155+
_ = b.Enum()
156+
)
157+
158+
t.Fatal("expected panic with strict builder")
159+
}
160+
129161
type BookValue struct {
130162
Title string
131163
ISBN string

0 commit comments

Comments
 (0)