Skip to content

Commit

Permalink
switch auto-group and one-per-scope types to interfaces as opposed to…
Browse files Browse the repository at this point in the history
… options
  • Loading branch information
aaronc committed Sep 24, 2021
1 parent 4a62e8f commit 8748aeb
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 163 deletions.
9 changes: 2 additions & 7 deletions container/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ import (
)

type config struct {
autoGroupTypes map[reflect.Type]bool
onePerScopeTypes map[reflect.Type]bool

// logging
loggers []func(string)
indentStr string
Expand All @@ -35,10 +32,8 @@ func newConfig() (*config, error) {
}

return &config{
autoGroupTypes: map[reflect.Type]bool{},
onePerScopeTypes: map[reflect.Type]bool{},
graphviz: g,
graph: graph,
graphviz: g,
graph: graph,
}, nil
}

Expand Down
132 changes: 89 additions & 43 deletions container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,37 +27,13 @@ type resolveFrame struct {
}

func newContainer(cfg *config) *container {
ctr := &container{
return &container{
config: cfg,
resolvers: map[reflect.Type]resolver{},
scopes: map[string]Scope{},
callerStack: nil,
callerMap: map[Location]bool{},
}

for typ := range cfg.autoGroupTypes {
sliceType := reflect.SliceOf(typ)
r := &groupResolver{
typ: typ,
sliceType: sliceType,
}
ctr.resolvers[typ] = r
ctr.resolvers[sliceType] = &sliceGroupResolver{r}
}

for typ := range cfg.onePerScopeTypes {
mapType := reflect.MapOf(stringType, typ)
r := &onePerScopeResolver{
typ: typ,
mapType: mapType,
providers: map[Scope]*simpleProvider{},
idxMap: map[Scope]int{},
}
ctr.resolvers[typ] = r
ctr.resolvers[mapType] = &mapOfOnePerScopeResolver{r}
}

return ctr
}

func (c *container) call(constructor *ProviderDescriptor, scope Scope) ([]reflect.Value, error) {
Expand Down Expand Up @@ -101,7 +77,7 @@ func (c *container) call(constructor *ProviderDescriptor, scope Scope) ([]reflec
return out, nil
}

func (c *container) addNode(constructor *ProviderDescriptor, scope Scope, noLog bool) (interface{}, error) {
func (c *container) addNode(constructor *ProviderDescriptor, scope Scope) (interface{}, error) {
constructorGraphNode, err := c.locationGraphNode(constructor.Location, scope)
if err != nil {
return reflect.Value{}, err
Expand All @@ -122,9 +98,10 @@ func (c *container) addNode(constructor *ProviderDescriptor, scope Scope, noLog
}

if scope != nil || !hasScopeParam {
if !noLog {
c.logf("Registering provider: %s", constructor.Location.String())
}
c.logf("Registering %s", constructor.Location.String())
c.indentLogger()
defer c.dedentLogger()

node := &simpleProvider{
provider: constructor,
scope: scope,
Expand All @@ -137,26 +114,88 @@ func (c *container) addNode(constructor *ProviderDescriptor, scope Scope, noLog

for i, out := range constructor.Outputs {
typ := out.Type

// one-per-scope maps can't be used as a return type
if typ.Kind() == reflect.Map && isOnePerScopeType(typ.Elem()) && typ.Key().Kind() == reflect.String {
return nil, fmt.Errorf("%v cannot be used as a return type because %v is a one-per-scope type",
typ, typ.Elem())
}

// auto-group slices of auto-group types
if typ.Kind() == reflect.Slice && c.autoGroupTypes[typ.Elem()] {
if typ.Kind() == reflect.Slice && isAutoGroupType(typ.Elem()) {
typ = typ.Elem()
}

vr, ok := c.resolvers[typ]
if ok {
c.logf("Found resolver for %v: %T", typ, vr)
err := vr.addNode(node, i, c)
if err != nil {
return nil, err
}
} else {
c.resolvers[typ] = &simpleResolver{
node: node,
typ: typ,
}

typeGraphNode, err := c.typeGraphNode(typ)
if err != nil {
return reflect.Value{}, err
var typeGraphNode *cgraph.Node
var err error

if isAutoGroupType(typ) {
c.logf("Registering resolver for auto-group type %v", typ)
sliceType := reflect.SliceOf(typ)

typeGraphNode, err = c.typeGraphNode(sliceType)
if err != nil {
return reflect.Value{}, err
}
typeGraphNode.SetComment("auto-group")

r := &groupResolver{
typ: typ,
sliceType: sliceType,
}

err = r.addNode(node, i, c)
if err != nil {
return nil, err
}

c.resolvers[typ] = r
c.resolvers[sliceType] = &sliceGroupResolver{r}

} else if isOnePerScopeType(typ) {
c.logf("Registering resolver for one-per-scope type %v", typ)
mapType := reflect.MapOf(stringType, typ)

typeGraphNode, err = c.typeGraphNode(mapType)
if err != nil {
return reflect.Value{}, err
}
typeGraphNode.SetComment("one-per-scope")

r := &onePerScopeResolver{
typ: typ,
mapType: mapType,
providers: map[Scope]*simpleProvider{},
idxMap: map[Scope]int{},
}

err = r.addNode(node, i, c)
if err != nil {
return nil, err
}

c.resolvers[typ] = r
c.resolvers[mapType] = &mapOfOnePerScopeResolver{r}
} else {
c.logf("Registering resolver for simple type %v", typ)

typeGraphNode, err = c.typeGraphNode(typ)
if err != nil {
return reflect.Value{}, err
}

c.resolvers[typ] = &simpleResolver{
node: node,
typ: typ,
}
}

c.addGraphEdge(constructorGraphNode, typeGraphNode)
Expand All @@ -165,9 +204,10 @@ func (c *container) addNode(constructor *ProviderDescriptor, scope Scope, noLog

return node, nil
} else {
if !noLog {
c.logf("Registering scope provider: %s", constructor.Location.String())
}
c.logf("Registering scope provider: %s", constructor.Location.String())
c.indentLogger()
defer c.dedentLogger()

node := &scopeDepProvider{
provider: constructor,
calledForScope: map[Scope]bool{},
Expand All @@ -176,6 +216,9 @@ func (c *container) addNode(constructor *ProviderDescriptor, scope Scope, noLog

for i, out := range constructor.Outputs {
typ := out.Type

c.logf("Registering resolver for scoped type %v", typ)

existing, ok := c.resolvers[typ]
if ok {
return nil, errors.Errorf("duplicate provision of type %v by scoped provider %s\n\talready provided by %s",
Expand Down Expand Up @@ -280,13 +323,16 @@ func (c *container) run(invoker interface{}) error {
return errors.Errorf("invoker function cannot have return values other than error: %s", rctr.Location)
}

c.logf("Registering invoker %s", rctr.Location)
c.logf("Registering invoker")
c.indentLogger()

node, err := c.addNode(&rctr, nil, true)
node, err := c.addNode(&rctr, nil)
if err != nil {
return err
}

c.dedentLogger()

sn, ok := node.(*simpleProvider)
if !ok {
return errors.Errorf("cannot run scoped provider as an invoker")
Expand Down
Loading

0 comments on commit 8748aeb

Please sign in to comment.