diff --git a/README.md b/README.md index aba950f..1241dde 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ > dix是一个依赖注入框架 > 它参考了dig的设计, 但是它能够完成更加复杂的依赖注入管理和namespace依赖隔离 +> https://github.com/uber-go/dig ## 功能描述 diff --git a/dix.go b/dix.go index 9d55e84..a9bdb00 100644 --- a/dix.go +++ b/dix.go @@ -1,6 +1,8 @@ package dix import ( + "reflect" + "github.com/pubgo/dix/internal/dix_inter" ) @@ -24,7 +26,13 @@ func New(opts ...Option) *Dix { } func Inject[T any](di *Dix, data T, opts ...Option) T { - _ = di.Inject(data, opts...) + vp := reflect.ValueOf(data) + if vp.Kind() == reflect.Struct { + _ = di.Inject(&data, opts...) + } else { + _ = di.Inject(data, opts...) + } + return data } diff --git a/example/cycle/main.go b/example/cycle/main.go index 2164b34..5b25feb 100644 --- a/example/cycle/main.go +++ b/example/cycle/main.go @@ -17,14 +17,11 @@ func main() { }() type ( - A struct { - } + A struct{} - B struct { - } + B struct{} - C struct { - } + C struct{} ) di.Provide(func(*B) *A { @@ -35,7 +32,7 @@ func main() { return new(B) }) - var err = try.Try(func() error { + err := try.Try(func() error { di.Provide(func(*A) *C { return new(C) }) diff --git a/example/handler/main.go b/example/handler/main.go index 57e3863..9c4c87e 100644 --- a/example/handler/main.go +++ b/example/handler/main.go @@ -32,7 +32,8 @@ func main() { di.Provide(func(p struct { L *log.Logger - }) *Redis { + }, + ) *Redis { p.L.Println("init redis") return &Redis{name: "hello"} }) diff --git a/example/inject_method/main.go b/example/inject_method/main.go index f88e21e..47ed197 100644 --- a/example/inject_method/main.go +++ b/example/inject_method/main.go @@ -7,8 +7,7 @@ import ( "github.com/pubgo/funk/errors" ) -type handler struct { -} +type handler struct{} func (h *handler) DixInjectA(err *errors.Err) { fmt.Println("A: ", err.Msg) @@ -16,7 +15,8 @@ func (h *handler) DixInjectA(err *errors.Err) { func (h *handler) DixInjectD(p struct { Err *errors.Err -}) { +}, +) { fmt.Println("D: ", p.Err.Msg) } diff --git a/example/struct-in/main.go b/example/struct-in/main.go index fe3266e..8d5e722 100644 --- a/example/struct-in/main.go +++ b/example/struct-in/main.go @@ -2,11 +2,11 @@ package main import ( "fmt" - "github.com/pubgo/funk/recovery" "github.com/pubgo/dix" "github.com/pubgo/dix/di" "github.com/pubgo/funk/assert" + "github.com/pubgo/funk/recovery" ) type a struct { diff --git a/example/struct-out/main.go b/example/struct-out/main.go index f0ae7a5..47d8f18 100644 --- a/example/struct-out/main.go +++ b/example/struct-out/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "github.com/pubgo/dix/di" "github.com/pubgo/funk/pretty" "github.com/pubgo/funk/recovery" @@ -15,10 +16,12 @@ type D struct { M C } -type C interface{} -type C1 struct { - Name string -} +type ( + C interface{} + C1 struct { + Name string + } +) type Conf struct { Inline @@ -68,7 +71,7 @@ func main() { }, }, D4: map[string][]*D{ - "default4": []*D{ + "default4": { { M: "hello d4", }, diff --git a/go.mod b/go.mod index 59b1131..2b95722 100644 --- a/go.mod +++ b/go.mod @@ -2,21 +2,21 @@ module github.com/pubgo/dix go 1.19 -require github.com/pubgo/funk v0.5.32-3 +require github.com/pubgo/funk v0.5.40 require ( github.com/alecthomas/repr v0.2.0 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/k0kubun/pp/v3 v3.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/phuslu/goid v1.0.0 // indirect github.com/rs/zerolog v1.30.0 // indirect golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c // indirect google.golang.org/grpc v1.51.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect ) diff --git a/go.sum b/go.sum index 42ecc85..aefd89c 100644 --- a/go.sum +++ b/go.sum @@ -5,10 +5,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/k0kubun/pp/v3 v3.2.0 h1:h33hNTZ9nVFNP3u2Fsgz8JXiF5JINoZfFq4SvKJwNcs= github.com/k0kubun/pp/v3 v3.2.0/go.mod h1:ODtJQbQcIRfAD3N+theGCV1m/CBxweERz2dapdz1EwA= @@ -23,8 +21,8 @@ github.com/phuslu/goid v1.0.0 h1:Cgcvd/R54UO1fCtyt+iKXAi+yZQ/KWlAm6MmZNizCLM= github.com/phuslu/goid v1.0.0/go.mod h1:txc2fUIdrdnn+v9Vq+QpiPQ3dnrXEchjoVDgic+r+L0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pubgo/funk v0.5.32-3 h1:91saMP3Eq9GQDzEwK3w3kN45ABeqO7zP1RrPtr+MHMg= -github.com/pubgo/funk v0.5.32-3/go.mod h1:Z5Wp7OoxjmSlWH+6waFSbao5MSD942LVhkBSlUu4s4s= +github.com/pubgo/funk v0.5.40 h1:uLN637YY/ljykp5R+bmBGl47wMzsUENW/ZvYG1APNGE= +github.com/pubgo/funk v0.5.40/go.mod h1:gKCw72+MK7xPiUGY1Z/bdGJMrSfVi87r0x/7d1GtKU4= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= @@ -32,22 +30,19 @@ github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiS github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb h1:mIKbk8weKhSeLH2GmUTrvx8CjkyJmnU1wFmg59CUjFA= golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c h1:QgY/XxIAIeccR+Ca/rDdKubLIU9rcJ3xfy1DC/Wd2Oo= google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/dix_inter/aaa.go b/internal/dix_inter/aaa.go index 63b95ce..32ffa5b 100644 --- a/internal/dix_inter/aaa.go +++ b/internal/dix_inter/aaa.go @@ -1,6 +1,10 @@ package dix_inter -import "reflect" +import ( + "reflect" + + "github.com/pubgo/funk/log" +) const ( // defaultKey 默认的 namespace @@ -20,3 +24,5 @@ type Graph struct { Objects string `json:"objects"` Providers string `json:"providers"` } + +var logger = log.GetLogger("dix") diff --git a/internal/dix_inter/cycle-check.go b/internal/dix_inter/cycle-check.go index ea9728e..29f0706 100644 --- a/internal/dix_inter/cycle-check.go +++ b/internal/dix_inter/cycle-check.go @@ -8,7 +8,7 @@ import ( // isCycle Check whether type circular dependency func (x *Dix) isCycle() (string, bool) { - var types = make(map[reflect.Type]map[reflect.Type]bool) + types := make(map[reflect.Type]map[reflect.Type]bool) for _, nodes := range x.providers { for _, n := range nodes { if types[n.output.typ] == nil { @@ -16,7 +16,9 @@ func (x *Dix) isCycle() (string, bool) { } for i := range n.input { - types[n.output.typ][n.input[i].typ] = true + for _, v := range x.getAllProvideInput(n.input[i].typ) { + types[n.output.typ][v.typ] = true + } } } } @@ -37,7 +39,7 @@ func (x *Dix) isCycle() (string, bool) { return false } - var nodes = list.New() + nodes := list.New() for root := range types { nodes.PushBack(root) if check(root, types[root], nodes) { diff --git a/internal/dix_inter/dix.go b/internal/dix_inter/dix.go index 4044cae..4a611d2 100644 --- a/internal/dix_inter/dix.go +++ b/internal/dix_inter/dix.go @@ -12,7 +12,7 @@ import ( ) func newDix(opts ...Option) *Dix { - var option = Options{AllowValuesNull: true} + option := Options{AllowValuesNull: true} defer recovery.Raise(func(err error) error { return errors.WrapKV(err, "options", option) }) @@ -46,86 +46,6 @@ func (x *Dix) Option() Options { return x.option } -func (x *Dix) handleOutput(outType outputType, out reflect.Value) map[outputType]map[group][]value { - var rr = make(map[outputType]map[group][]value) - if !out.IsValid() || out.IsZero() { - return rr - } - - switch out.Kind() { - case reflect.Map: - outType = out.Type().Elem() - isList := outType.Kind() == reflect.Slice - if isList { - outType = outType.Elem() - } - - if rr[outType] == nil { - rr[outType] = make(map[group][]value) - } - - for _, k := range out.MapKeys() { - var mapK = strings.TrimSpace(k.String()) - if mapK == "" { - mapK = defaultKey - } - - var val = out.MapIndex(k) - if !val.IsValid() || val.IsNil() { - continue - } - - if isList { - for i := 0; i < val.Len(); i++ { - var vv = val.Index(i) - if !vv.IsValid() || vv.IsNil() { - continue - } - - rr[outType][mapK] = append(rr[outType][mapK], vv) - } - } else { - rr[outType][mapK] = append(rr[outType][mapK], val) - } - } - case reflect.Slice: - outType = out.Type().Elem() - if rr[outType] == nil { - rr[outType] = make(map[group][]value) - } - - for i := 0; i < out.Len(); i++ { - var val = out.Index(i) - if !val.IsValid() || val.IsNil() { - continue - } - - rr[outType][defaultKey] = append(rr[outType][defaultKey], val) - } - case reflect.Struct: - for i := 0; i < out.NumField(); i++ { - for typ, vv := range x.handleOutput(out.Field(i).Type(), out.Field(i)) { - if rr[typ] == nil { - rr[typ] = vv - } else { - for g, v := range vv { - rr[typ][g] = append(rr[typ][g], v...) - } - } - } - } - default: - if rr[outType] == nil { - rr[outType] = make(map[group][]value) - } - - if out.IsValid() && !out.IsNil() { - rr[outType][defaultKey] = []value{out} - } - } - return rr -} - func (x *Dix) evalProvider(typ outputType, opt Options) map[group][]value { switch typ.Kind() { case reflect.Ptr, reflect.Interface, reflect.Func: @@ -141,7 +61,7 @@ func (x *Dix) evalProvider(typ outputType, opt Options) map[group][]value { Str("type", typ.String()). Str("kind", typ.Kind().String()). Msg("provider not found, please check whether the provider imports or type error") - return make(map[group][]value) + // return make(map[group][]value) } if x.objects[typ] == nil { @@ -161,14 +81,14 @@ func (x *Dix) evalProvider(typ outputType, opt Options) map[group][]value { var input []reflect.Value for _, in := range n.input { - var val = x.getValue(in.typ, opt, in.isMap, in.isList) + val := x.getValue(in.typ, opt, in.isMap, in.isList) input = append(input, val) } - var fnCall = n.call(input) + fnCall := n.call(input) x.initializer[n.fn] = true - for k, oo := range x.handleOutput(typ, fnCall[0]) { + for k, oo := range handleOutput(typ, fnCall[0]) { if n.output.isMap { if _, ok := objects[k]; ok { log.Info(). @@ -201,7 +121,7 @@ func (x *Dix) evalProvider(typ outputType, opt Options) map[group][]value { return x.objects[typ] } -func (x *Dix) getValue(typ reflect.Type, opt Options, isMap bool, isList bool) reflect.Value { +func (x *Dix) getValue(typ reflect.Type, opt Options, isMap, isList bool) reflect.Value { switch { case isMap: valMap := x.evalProvider(typ, opt) @@ -218,7 +138,7 @@ func (x *Dix) getValue(typ reflect.Type, opt Options, isMap bool, isList bool) r case isList: valMap := x.evalProvider(typ, opt) if !opt.AllowValuesNull && len(valMap[defaultKey]) == 0 { - var err = &errors.Err{ + err := &errors.Err{ Msg: "provider value not found", Detail: fmt.Sprintf("type=%s kind=%s allValues=%v", typ, typ.Kind(), valMap), } @@ -233,7 +153,7 @@ func (x *Dix) getValue(typ reflect.Type, opt Options, isMap bool, isList bool) r return makeList(typ, valMap[defaultKey]) case typ.Kind() == reflect.Struct: - var v = reflect.New(typ) + v := reflect.New(typ) x.injectStruct(v.Elem(), opt) return v.Elem() default: @@ -247,9 +167,9 @@ func (x *Dix) getValue(typ reflect.Type, opt Options, isMap bool, isList bool) r Msg("provider value not found") } else { // 最后一个value - var val = valList[len(valList)-1] + val := valList[len(valList)-1] if val.IsZero() { - var err = &errors.Err{ + err := &errors.Err{ Msg: "provider value is nil", Detail: fmt.Sprintf("type=%s kind=%s value=%v", typ, typ.Kind(), val.Interface()), } @@ -275,7 +195,7 @@ func (x *Dix) injectFunc(vp reflect.Value, opt Options) { case reflect.Interface, reflect.Ptr, reflect.Func, reflect.Struct: inTypes = append(inTypes, &inType{typ: inTyp}) case reflect.Map: - var isList = inTyp.Elem().Kind() == reflect.Slice + isList := inTyp.Elem().Kind() == reflect.Slice typ := inTyp.Elem() if isList { typ = typ.Elem() @@ -312,7 +232,7 @@ func (x *Dix) injectStruct(vp reflect.Value, opt Options) { case reflect.Interface, reflect.Ptr, reflect.Func: vp.Field(i).Set(x.getValue(field.Type, opt, false, false)) case reflect.Map: - var isList = field.Type.Elem().Kind() == reflect.Slice + isList := field.Type.Elem().Kind() == reflect.Slice typ := field.Type.Elem() if isList { typ = typ.Elem() @@ -320,6 +240,11 @@ func (x *Dix) injectStruct(vp reflect.Value, opt Options) { vp.Field(i).Set(x.getValue(typ, opt, true, isList)) case reflect.Slice: vp.Field(i).Set(x.getValue(field.Type.Elem(), opt, false, true)) + default: + panic(&errors.Err{ + Msg: "incorrect input type", + Detail: fmt.Sprintf("inTyp=%s kind=%s", field.Type, field.Type.Kind()), + }) } } } @@ -354,7 +279,7 @@ func (x *Dix) inject(param interface{}, opts ...Option) interface{} { }) for i := 0; i < vp.NumMethod(); i++ { - var name = vp.Type().Method(i).Name + name := vp.Type().Method(i).Name if !strings.HasPrefix(name, InjectMethodPrefix) { continue } @@ -388,7 +313,7 @@ func (x *Dix) handleProvide(fnVal reflect.Value, out reflect.Type, in []*inType) } x.providers[n.output.typ] = append(x.providers[n.output.typ], n) case reflect.Ptr, reflect.Interface, reflect.Func: - n.output = &outType{isList: true, typ: outTyp} + n.output = &outType{typ: outTyp} x.providers[n.output.typ] = append(x.providers[n.output.typ], n) case reflect.Struct: log.Debug().Str("name", outTyp.Name()).Msg("struct info") @@ -403,6 +328,54 @@ func (x *Dix) handleProvide(fnVal reflect.Value, out reflect.Type, in []*inType) } } +func (x *Dix) getAllProvideInput(typ reflect.Type) []*inType { + var input []*inType + switch inTye := typ; inTye.Kind() { + case reflect.Interface, reflect.Ptr, reflect.Func: + input = append(input, &inType{typ: inTye}) + case reflect.Struct: + for j := 0; j < inTye.NumField(); j++ { + input = append(input, x.getAllProvideInput(inTye.Field(j).Type)...) + } + case reflect.Map: + tt := &inType{typ: inTye.Elem(), isMap: true, isList: inTye.Elem().Kind() == reflect.Slice} + if tt.isList { + tt.typ = tt.typ.Elem() + } + input = append(input, tt) + case reflect.Slice: + input = append(input, &inType{typ: inTye.Elem(), isList: true}) + default: + panic(&errors.Err{ + Msg: "incorrect input type", + Detail: fmt.Sprintf("inTyp=%s kind=%s", inTye, inTye.Kind()), + }) + } + return input +} + +func (x *Dix) getProvideInput(typ reflect.Type) []*inType { + var input []*inType + switch inTye := typ; inTye.Kind() { + case reflect.Interface, reflect.Ptr, reflect.Func, reflect.Struct: + input = append(input, &inType{typ: inTye}) + case reflect.Map: + tt := &inType{typ: inTye.Elem(), isMap: true, isList: inTye.Elem().Kind() == reflect.Slice} + if tt.isList { + tt.typ = tt.typ.Elem() + } + input = append(input, tt) + case reflect.Slice: + input = append(input, &inType{typ: inTye.Elem(), isList: true}) + default: + panic(&errors.Err{ + Msg: "incorrect input type", + Detail: fmt.Sprintf("inTyp=%s kind=%s", inTye, inTye.Kind()), + }) + } + return input +} + func (x *Dix) provide(param interface{}) { defer recovery.Raise(func(err error) error { return errors.WrapKV(err, "param", fmt.Sprintf("%#v", param)) @@ -425,33 +398,15 @@ func (x *Dix) provide(param interface{}) { var input []*inType for i := 0; i < typ.NumIn(); i++ { - switch inTye := typ.In(i); inTye.Kind() { - case reflect.Interface, reflect.Ptr, reflect.Func, reflect.Struct: - input = append(input, &inType{typ: inTye}) - case reflect.Map: - tt := &inType{typ: inTye.Elem(), isMap: true, isList: inTye.Elem().Kind() == reflect.Slice} - if tt.isList { - tt.typ = tt.typ.Elem() - } - input = append(input, tt) - case reflect.Slice: - input = append(input, &inType{typ: inTye.Elem(), isList: true}) - default: - panic(&errors.Err{ - Msg: "incorrect input type", - Detail: fmt.Sprintf("inTyp=%s kind=%s", inTye, inTye.Kind()), - }) - } + input = append(input, x.getProvideInput(typ.In(i))...) } - // 返回值只能有一个 + // The return value can only have one + // TODO Add the second parameter, support for error x.handleProvide(fnVal, typ.Out(0), input) dep, ok := x.isCycle() - err := &errors.Err{ - Msg: "provider circular dependency", - Detail: dep, + if ok { + log.Fatal().Str("cycle", dep).Msg("provider circular dependency") } - log.Err(err).Msg(err.Detail) - assert.Err(ok, err) } diff --git a/internal/dix_inter/graph.go b/internal/dix_inter/graph.go index b42ea3f..40e97ef 100644 --- a/internal/dix_inter/graph.go +++ b/internal/dix_inter/graph.go @@ -40,7 +40,9 @@ func (x *Dix) objectGraph() string { fPrintln(b, "\t\tlabel=objects") for k, objects := range x.objects { for g, values := range objects { - fPrintln(b, fmt.Sprintf("\t\t"+`object -> "%s" -> "%s" -> %v`, k, g, reflectValueToString(values))) + for _, v := range values { + fPrintln(b, fmt.Sprintf("\t\t"+`"%s" -> "%s -> %s"`, k, g, v.Type().String())) + } } } fPrintln(b, "\t}") diff --git a/internal/dix_inter/option.go b/internal/dix_inter/option.go index 19aebeb..9b723c6 100644 --- a/internal/dix_inter/option.go +++ b/internal/dix_inter/option.go @@ -1,10 +1,12 @@ package dix_inter -type Option func(opts *Options) -type Options struct { - // 允许结果为nil - AllowValuesNull bool -} +type ( + Option func(opts *Options) + Options struct { + // 允许结果为nil + AllowValuesNull bool + } +) func (o Options) Merge(opt Options) Options { if o.AllowValuesNull { diff --git a/internal/dix_inter/util.go b/internal/dix_inter/util.go index 05f00d6..de7236c 100644 --- a/internal/dix_inter/util.go +++ b/internal/dix_inter/util.go @@ -3,6 +3,7 @@ package dix_inter import ( "fmt" "reflect" + "strings" ) func checkType(p reflect.Kind) bool { @@ -15,7 +16,7 @@ func checkType(p reflect.Kind) bool { } func makeList(typ reflect.Type, data []reflect.Value) reflect.Value { - var val = reflect.MakeSlice(reflect.SliceOf(typ), 0, 0) + val := reflect.MakeSlice(reflect.SliceOf(typ), 0, 0) return reflect.Append(val, data...) } @@ -24,10 +25,10 @@ func makeMap(typ reflect.Type, data map[string][]reflect.Value, valueList bool) typ = reflect.SliceOf(typ) } - var mapVal = reflect.MakeMap(reflect.MapOf(reflect.TypeOf(""), typ)) + mapVal := reflect.MakeMap(reflect.MapOf(reflect.TypeOf(""), typ)) for index, values := range data { // 最后一个值作为默认值 - var val = values[len(values)-1] + val := values[len(values)-1] if valueList { val = reflect.MakeSlice(typ, 0, len(values)) val = reflect.Append(val, values...) @@ -44,3 +45,83 @@ func reflectValueToString(values []reflect.Value) []string { } return data } + +func handleOutput(outType outputType, out reflect.Value) map[outputType]map[group][]value { + rr := make(map[outputType]map[group][]value) + if !out.IsValid() || out.IsZero() { + return rr + } + + switch out.Kind() { + case reflect.Map: + outType = out.Type().Elem() + isList := outType.Kind() == reflect.Slice + if isList { + outType = outType.Elem() + } + + if rr[outType] == nil { + rr[outType] = make(map[group][]value) + } + + for _, k := range out.MapKeys() { + mapK := strings.TrimSpace(k.String()) + if mapK == "" { + mapK = defaultKey + } + + val := out.MapIndex(k) + if !val.IsValid() || val.IsNil() { + continue + } + + if isList { + for i := 0; i < val.Len(); i++ { + vv := val.Index(i) + if !vv.IsValid() || vv.IsNil() { + continue + } + + rr[outType][mapK] = append(rr[outType][mapK], vv) + } + } else { + rr[outType][mapK] = append(rr[outType][mapK], val) + } + } + case reflect.Slice: + outType = out.Type().Elem() + if rr[outType] == nil { + rr[outType] = make(map[group][]value) + } + + for i := 0; i < out.Len(); i++ { + val := out.Index(i) + if !val.IsValid() || val.IsNil() { + continue + } + + rr[outType][defaultKey] = append(rr[outType][defaultKey], val) + } + case reflect.Struct: + for i := 0; i < out.NumField(); i++ { + for typ, vv := range handleOutput(out.Field(i).Type(), out.Field(i)) { + if rr[typ] == nil { + rr[typ] = vv + } else { + for g, v := range vv { + rr[typ][g] = append(rr[typ][g], v...) + } + } + } + } + default: + if rr[outType] == nil { + rr[outType] = make(map[group][]value) + } + + if out.IsValid() && !out.IsNil() { + rr[outType][defaultKey] = []value{out} + } + } + return rr +}