Skip to content

Commit

Permalink
summoner dependency injection
Browse files Browse the repository at this point in the history
  • Loading branch information
Comcx committed May 21, 2023
1 parent 8676f89 commit 2097ef9
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 0 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/ireina7/summoner

go 1.20
108 changes: 108 additions & 0 deletions summoner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package summoner

import (
"fmt"
"reflect"
)

type Typeclass[A any] interface {
Given(A) error
GivenType(any, reflect.Type) error

Summon() (A, error)
SummonType(reflect.Type) (any, error)
}

type Summoner[A any] struct {
instances map[reflect.Type]any
}

func TypeOf[A any]() reflect.Type {
return reflect.TypeOf((*A)(nil)).Elem()
}

func Summon[I any]() (I, error) {
return Transfrom[any, I](&global).Summon()
}

func SummonType(t reflect.Type) (any, error) {
return global.SummonType(t)
}

func Given[I any](instance I) error {
return Transfrom[any, I](&global).Given(instance)
}

func Transfrom[A, B any](s *Summoner[A]) *Summoner[B] {
return &Summoner[B]{
instances: s.instances,
}
}

func (self *Summoner[A]) tryBuild() (A, error) {
t := TypeOf[A]()
r := reflect.New(t)
i := 0
var a A
for i < r.Elem().NumField() {
field := r.Elem().Field(i)
instance, err := self.SummonType(field.Type())
if err != nil {
return a, err
}
dependency := reflect.ValueOf(instance)
field.Set(dependency)
i += 1
}
ans, ok := r.Interface().(*A)
if !ok {
return a, fmt.Errorf("Type conversion error: %v", r)
}
return *ans, nil
}

func (self *Summoner[A]) Summon() (A, error) {
t := TypeOf[A]()
ev, ok := self.instances[t]
if ok {
return ev.(A), nil
}
// var a A
// return a, fmt.Errorf("Instance of %v not found", t)
return self.tryBuild()
}

func (self *Summoner[A]) SummonType(t reflect.Type) (any, error) {
ev, ok := self.instances[t]
if ok {
return ev, nil
}
return nil, fmt.Errorf("Instance of %v not found", t)
}

func (self *Summoner[A]) Given(ev A) error {
t := TypeOf[A]()
return self.GivenType(ev, t)
}

func (self *Summoner[A]) GivenType(ev any, t reflect.Type) error {
self.instances[t] = ev
return nil
}

var global Summoner[any] = Summoner[any]{
instances: map[reflect.Type]any{},
}

type RType = reflect.Type
type Type struct {
RType
params []Type
}

func fromReflect(t reflect.Type) Type {
return Type{
RType: t,
params: []Type{},
}
}
60 changes: 60 additions & 0 deletions summoner_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package summoner

import (
"fmt"
"testing"
)

func TestSummoner(t *testing.T) {

Given[Show[Person]](new(ShowPerson))
Given[Show[int]](new(ShowInt))

ev, err := Summon[Show[Person]]()
if err != nil {
panic(err)
}
t.Log(ev.Show(Person{0, "Tom", 10}))

ee, err := Summon[Show[int]]()
if err != nil {
panic(err)
}
t.Log(ee.Show(7))

es, err := Summon[Debug[Person]]()
if err != nil {
panic(err)
}
t.Log(es.Debug(Person{0, "Tom", 10}))
}

type Person struct {
id int
name string
age int
}

type Show[A any] interface {
Show(a A) string
}

type ShowPerson struct{}

func (ev *ShowPerson) Show(p Person) string {
return fmt.Sprintf("Person: %v", p)
}

type ShowInt struct{}

func (ev *ShowInt) Show(i int) string {
return fmt.Sprintf("Integer: %v", i)
}

type Debug[A any] struct {
Show Show[A]
}

func (self *Debug[A]) Debug(a A) string {
return fmt.Sprintf("Debug: %s", self.Show.Show(a))
}

0 comments on commit 2097ef9

Please sign in to comment.