Skip to content

Commit

Permalink
Map with generics
Browse files Browse the repository at this point in the history
  • Loading branch information
butzopower committed Mar 21, 2022
1 parent c27d3c1 commit ee426ad
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 12 deletions.
75 changes: 63 additions & 12 deletions adt/adt.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,23 @@ type Atd struct {
v union
}

// Of

func Of[T ofUnion](union T) *Atd {
var t interface{}
t = union
switch v := t.(type) {
case lib.TypeA:
return &Atd{TypeAContainer{v}}
case lib.TypeB:
return &Atd{TypeBContainer{v}}
default:
panic("called Of with disallowed type")
}
}

// Do

type doFnTypeAFn func(aType lib.TypeA)
type doFnTypeBFn func(aType lib.TypeB)

Expand Down Expand Up @@ -56,10 +73,6 @@ func (chain *doChainA) WithTypeA(fn doFnTypeAFn) *doChainB {
return &doChainB{chain.doBuilder}
}

func Do() *doChainA {
return &doChainA{doFns{}}
}

func (e doChainExecutor) Exec(of *Atd) {
switch container := of.v.(type) {
case TypeAContainer:
Expand All @@ -69,15 +82,53 @@ func (e doChainExecutor) Exec(of *Atd) {
}
}

func Of[T ofUnion](union T) *Atd {
var t interface{}
t = union
switch v := t.(type) {
case lib.TypeA:
return &Atd{TypeAContainer{v}}
case lib.TypeB:
return &Atd{TypeBContainer{v}}
func Do() *doChainA {
return &doChainA{doFns{}}
}

// Map

type mapFnTypeAFn[T any] func(aType lib.TypeA) T
type mapFnTypeBFn[T any] func(aType lib.TypeB) T

type mapFns[T any] struct {
mapFnTypeA mapFnTypeAFn[T]
mapFnTypeB mapFnTypeBFn[T]
}

type mapChainA[T any] struct {
fns mapFns[T]
}

type mapChainB[T any] struct {
fns mapFns[T]
}

type mapChainMapper[T any] struct {
fns mapFns[T]
}

func (chain mapChainA[T]) WithTypeA(fn mapFnTypeAFn[T]) *mapChainB[T] {
chain.fns.mapFnTypeA = fn
return &mapChainB[T]{chain.fns}
}

func (chain mapChainB[T]) WithTypeB(fn mapFnTypeBFn[T]) *mapChainMapper[T] {
chain.fns.mapFnTypeB = fn
return &mapChainMapper[T]{chain.fns}
}

func (mapper mapChainMapper[T]) Map(of *Atd) T {
switch container := of.v.(type) {
case TypeAContainer:
return mapper.fns.mapFnTypeA(container.v)
case TypeBContainer:
return mapper.fns.mapFnTypeB(container.v)
default:
panic("called Of with disallowed type")
}
}

func Mapper[T any]() *mapChainA[T] {
return &mapChainA[T]{mapFns[T]{}}
}
12 changes: 12 additions & 0 deletions adt/adt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,15 @@ func TestExecutingWithTwoTypes(t *testing.T) {
require.Equal(t, typeACalled, false)
require.Equal(t, typeBCalled, true)
}

func TestMapWithTwoTypes(t *testing.T) {
mapper := adt.Mapper[string]().
WithTypeA(func(typeA lib.TypeA) string { return "type-a" }).
WithTypeB(func(typeB lib.TypeB) string { return "type-b" })

typeAMapped := mapper.Map(adt.Of(lib.TypeA{}))
typeBMapped := mapper.Map(adt.Of(lib.TypeB{}))

require.Equal(t, "type-a", typeAMapped)
require.Equal(t, "type-b", typeBMapped)
}

0 comments on commit ee426ad

Please sign in to comment.