Skip to content

Commit

Permalink
add injection
Browse files Browse the repository at this point in the history
  • Loading branch information
ireina7 committed Sep 30, 2023
1 parent aa02eaf commit 4e98087
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 33 deletions.
Empty file added go.sum
Empty file.
5 changes: 5 additions & 0 deletions lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ func IsRule[A any]() bool {
return TypeOf[A]().Kind() == reflect.Struct
}

func Rules() string {
return global.Rules()
}

func Summon[I any]() (I, error) {
return Transfrom[any, I](&global).Summon()
}
Expand All @@ -31,5 +35,6 @@ func GivenType(instance any, t reflect.Type) error {
func Transfrom[A, B any](s *Summoner[A]) *Summoner[B] {
return &Summoner[B]{
instances: s.instances,
rules: s.rules,
}
}
118 changes: 88 additions & 30 deletions summoner.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package summoner
import (
"fmt"
"reflect"
// "github.com/traefik/yaegi/stdlib"
)

type Typeclass[A any] interface {
Expand All @@ -17,8 +18,23 @@ type Transmute[A any] interface {
Transform() A
}

// func ValueFromTypeName(tname string) (any, error) {
// i := interp.New(interp.Options{GoPath: "/Users/comcx/go"})
// // i.CompilePath(".")
// _, err := i.Eval(`.`)
// if err != nil {
// return nil, err
// }
// x, err := i.Eval(fmt.Sprintf(`%s{}`, tname))
// if err != nil {
// return nil, err
// }
// return x.Interface(), nil
// }

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

type summonError struct {
Expand All @@ -29,36 +45,6 @@ func (err *summonError) Error() string {
return fmt.Sprintf("Summon error: expected type %v", err.want)
}

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

// func IsRule[A any]() bool {
// return TypeOf[A]().Kind() == reflect.Struct
// }

// 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 GivenType(instance any, t reflect.Type) error {
// return global.GivenType(instance, t)
// }

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

func (self *Summoner[A]) tryBuild(t reflect.Type) (any, error) {
if t.Kind() == reflect.Interface {
return nil, &summonError{t}
Expand Down Expand Up @@ -132,8 +118,20 @@ func (self *Summoner[A]) Inspect() string {
)
}

func (self *Summoner[A]) Rules() string {
rules := ""
for k, v := range self.rules {
rules += fmt.Sprintf("\t%v: %v\n", k, v)
}
return fmt.Sprintf("Rules[%d] {\n%v}",
len(self.rules),
rules,
)
}

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

type RType = reflect.Type
Expand All @@ -148,3 +146,63 @@ func fromReflect(t reflect.Type) Type {
params: []Type{},
}
}

func (self *Summoner[A]) Inject(structPtr any) error {
t := reflect.TypeOf(structPtr)
if t.Kind() != reflect.Pointer {
return fmt.Errorf("t.Kind(%v) is not reflect.Pointer", t.Kind())
}
v := reflect.ValueOf(structPtr).Elem()
for i := 0; i < v.NumField(); i += 1 {
field := v.Field(i)
ft := field.Type()
tag := t.Elem().Field(i).Tag.Get("summon")
if len(tag) == 0 {
switch ft.Kind() {
case reflect.Pointer:
self.Inject(field.Interface()) //recursively
case reflect.Struct:
self.Inject(field.Addr().Interface()) //recursively
default:
//pass
}
continue
}

//It's leave node
switch ft.Kind() {
case reflect.Struct:
x, err := self.tryBuild(field.Type())
if err != nil {
return err
}
field.Set(reflect.ValueOf(x))
case reflect.Interface:
x, err := self.SummonType(field.Type())
if err != nil {
return err
}
field.Set(reflect.ValueOf(x))
case reflect.Pointer:
x, err := self.tryBuild(field.Type().Elem())
if err != nil {
return err
}
p := reflect.New(ft.Elem())
val := reflect.ValueOf(x)
p.Elem().Set(val)
field.Set(p)
default:
x, err := self.SummonType(field.Type())
if err != nil {
return err
}
field.Set(reflect.ValueOf(x))
}
}
return nil
}

func main() {
fmt.Println("Hello, summoner")
}
82 changes: 79 additions & 3 deletions summoner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package summoner

import (
"fmt"
"reflect"
"testing"
)

Expand All @@ -11,6 +12,13 @@ func TestSummoner(t *testing.T) {
GivenType(new(ShowPerson), TypeOf[Show[Person]]())
Given[Show[int]](new(ShowInt))
Given[Show[string]](new(ShowString))
test()
global.GivenRule(
TypeOf[Debug[A]](),
TypeOf[Debug[A]](),
)

fmt.Println(Rules())

ev, err := Summon[Show[Person]]()
if err != nil {
Expand Down Expand Up @@ -43,7 +51,13 @@ func TestSummoner(t *testing.T) {
xx := ea.(App[Person])
xx.Execute(Person{1, "Jack", 14})

t.Log(global.Inspect())
// t.Log(global.Inspect())

// x, err := ValueFromTypeName("Person")
// if err != nil {
// panic(err)
// }
// fmt.Printf("%#v\n", x)
}

type Person struct {
Expand Down Expand Up @@ -71,11 +85,11 @@ func (ev *ShowInt) Show(i int) string {
type ShowString struct{}

func (ev *ShowString) Show(s string) string {
return s
return "[str] " + s
}

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

func (self *Debug[A]) Debug(a A) string {
Expand All @@ -101,3 +115,65 @@ func (app *App[A]) Execute(a A) {
fmt.Println(app.Show.Show("This is a test!"))
app.Recursive.Log(a)
}

type Monoid[A any] interface {
Zero() A
Plus(A, A) A
}

type ForAll[A any] struct{}

type MonoidSlice[A any] struct{}

func (self *MonoidSlice[A]) Zero() []A {
return []A{}
}

func (self *MonoidSlice[A]) Plus(a, b []A) []A {
c := a
c = append(c, b...)
return c
}

// t: the rule name
func (self *Summoner[A]) GivenRule(from reflect.Type, to reflect.Type) error {
self.rules[from] = to
return nil
}

func test() {
global.GivenRule(
TypeOf[MonoidSlice[A]](),
TypeOf[Monoid[[]A]](),
)
}

type Service struct {
Version string
Debugger *Debug[string] `summon:"true"`
Device Device
}

type Device struct {
Id int `summon:"true"`
Name string
Show Show[string] `summon:"type"`
}

func TestInject(t *testing.T) {
Given[Show[string]](new(ShowString))
Given[int](-7)
device := &Device{
Name: "sp",
}
service := &Service{
Version: "0.1.0",
Device: *device,
}
err := global.Inject(service)
if err != nil {
t.Error(err)
}
t.Logf("Service: %#v", service)
t.Log(service.Debugger.Debug("sss"))
}
31 changes: 31 additions & 0 deletions type_var.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package summoner

type TypeVar interface {
GetName() string
}

type A struct{}
type B struct{}
type C struct{}
type D struct{}
type E struct{}
type F struct{}

func (t A) GetName() string {
return "A"
}
func (t B) GetName() string {
return "B"
}
func (t C) GetName() string {
return "C"
}
func (t D) GetName() string {
return "D"
}
func (t E) GetName() string {
return "E"
}
func (t F) GetName() string {
return "F"
}

0 comments on commit 4e98087

Please sign in to comment.