From e78175786554fa3f6acb93b02b34c6958b49ae83 Mon Sep 17 00:00:00 2001 From: Jeremy Quirke Date: Mon, 6 Mar 2023 18:34:10 -0800 Subject: [PATCH] Track the key of any named group objects. As part of https://github.com/uber-go/dig/issues/380 we allowed names and groups tags/options to co-exist to ultimately support Fx feature request https://github.com/uber-go/fx/issues/998. We now intend to support Map value groups as per https://github.com/uber-go/fx/issues/1036. We will do this in 2 steps. 1. This PR will begin tracking any names passed into value groups with out changing any external facing functionality. 2. a subsequent PR will exploit this structure to support Map value groups. --- constructor.go | 16 ++++++++-------- container.go | 14 +++++++------- param.go | 6 +++++- result.go | 14 ++++++++++---- result_test.go | 2 +- scope.go | 31 ++++++++++++++++++------------- 6 files changed, 49 insertions(+), 34 deletions(-) diff --git a/constructor.go b/constructor.go index 7cf0c8ef..9dd0ff39 100644 --- a/constructor.go +++ b/constructor.go @@ -181,7 +181,7 @@ func (n *constructorNode) Call(c containerStore) (err error) { // would be made to a containerWriter and defers them until Commit is called. type stagingContainerWriter struct { values map[key]reflect.Value - groups map[key][]reflect.Value + groups map[key][]keyedGroupValue } var _ containerWriter = (*stagingContainerWriter)(nil) @@ -189,7 +189,7 @@ var _ containerWriter = (*stagingContainerWriter)(nil) func newStagingContainerWriter() *stagingContainerWriter { return &stagingContainerWriter{ values: make(map[key]reflect.Value), - groups: make(map[key][]reflect.Value), + groups: make(map[key][]keyedGroupValue), } } @@ -201,12 +201,12 @@ func (sr *stagingContainerWriter) setDecoratedValue(_ string, _ reflect.Type, _ digerror.BugPanicf("stagingContainerWriter.setDecoratedValue must never be called") } -func (sr *stagingContainerWriter) submitGroupedValue(group string, t reflect.Type, v reflect.Value) { +func (sr *stagingContainerWriter) submitGroupedValue(group, mapKey string, t reflect.Type, v reflect.Value) { k := key{t: t, group: group} - sr.groups[k] = append(sr.groups[k], v) + sr.groups[k] = append(sr.groups[k], keyedGroupValue{key: mapKey, value: v}) } -func (sr *stagingContainerWriter) submitDecoratedGroupedValue(_ string, _ reflect.Type, _ reflect.Value) { +func (sr *stagingContainerWriter) submitDecoratedGroupedValue(_, _ string, _ reflect.Type, _ reflect.Value) { digerror.BugPanicf("stagingContainerWriter.submitDecoratedGroupedValue must never be called") } @@ -216,9 +216,9 @@ func (sr *stagingContainerWriter) Commit(cw containerWriter) { cw.setValue(k.name, k.t, v) } - for k, vs := range sr.groups { - for _, v := range vs { - cw.submitGroupedValue(k.group, k.t, v) + for k, kgvs := range sr.groups { + for _, kgv := range kgvs { + cw.submitGroupedValue(k.group, kgv.key, k.t, kgv.value) } } } diff --git a/container.go b/container.go index 983fd3f9..4fd6a238 100644 --- a/container.go +++ b/container.go @@ -81,12 +81,12 @@ type containerWriter interface { setDecoratedValue(name string, t reflect.Type, v reflect.Value) // submitGroupedValue submits a value to the value group with the provided - // name. - submitGroupedValue(name string, t reflect.Type, v reflect.Value) + // name and optional map key. + submitGroupedValue(name, mapKey string, t reflect.Type, v reflect.Value) // submitDecoratedGroupedValue submits a decorated value to the value group - // with the provided name. - submitDecoratedGroupedValue(name string, t reflect.Type, v reflect.Value) + // with the provided name and optional map key. + submitDecoratedGroupedValue(name, mapKey string, t reflect.Type, v reflect.Value) } // containerStore provides access to the Container's underlying data store. @@ -108,7 +108,7 @@ type containerStore interface { // Retrieves all values for the provided group and type. // // The order in which the values are returned is undefined. - getValueGroup(name string, t reflect.Type) []reflect.Value + getValueGroup(name string, t reflect.Type) []keyedGroupValue // Retrieves all decorated values for the provided group and type, if any. getDecoratedValueGroup(name string, t reflect.Type) (reflect.Value, bool) @@ -273,8 +273,8 @@ func (bs byTypeName) Swap(i int, j int) { bs[i], bs[j] = bs[j], bs[i] } -func shuffledCopy(rand *rand.Rand, items []reflect.Value) []reflect.Value { - newItems := make([]reflect.Value, len(items)) +func shuffledCopy(rand *rand.Rand, items []keyedGroupValue) []keyedGroupValue { + newItems := make([]keyedGroupValue, len(items)) for i, j := range rand.Perm(len(items)) { newItems[i] = items[j] } diff --git a/param.go b/param.go index d584fc23..e60501e1 100644 --- a/param.go +++ b/param.go @@ -627,6 +627,7 @@ func (pt paramGroupedSlice) Build(c containerStore) (reflect.Value, error) { } // Check if we have decorated values + // qjeremy(how to handle this with maps?) if decoratedItems, ok := pt.getDecoratedValues(c); ok { return decoratedItems, nil } @@ -645,7 +646,10 @@ func (pt paramGroupedSlice) Build(c containerStore) (reflect.Value, error) { stores := c.storesToRoot() result := reflect.MakeSlice(pt.Type, 0, itemCount) for _, c := range stores { - result = reflect.Append(result, c.getValueGroup(pt.Group, pt.Type.Elem())...) + kgvs := c.getValueGroup(pt.Group, pt.Type.Elem()) + for _, kgv := range kgvs { + result = reflect.Append(result, kgv.value) + } } return result, nil } diff --git a/result.go b/result.go index a4e5ba38..22c537dd 100644 --- a/result.go +++ b/result.go @@ -491,6 +491,9 @@ type resultGrouped struct { // Name of the group as specified in the `group:".."` tag. Group string + // Key if a name tag or option was provided, for populating maps + Key string + // Type of value produced. Type reflect.Type @@ -527,8 +530,10 @@ func newResultGrouped(f reflect.StructField) (resultGrouped, error) { if err != nil { return resultGrouped{}, err } + name := f.Tag.Get(_nameTag) rg := resultGrouped{ Group: g.Name, + Key: name, Flatten: g.Flatten, Type: f.Type, } @@ -553,18 +558,19 @@ func newResultGrouped(f reflect.StructField) (resultGrouped, error) { func (rt resultGrouped) Extract(cw containerWriter, decorated bool, v reflect.Value) { // Decorated values are always flattened. if !decorated && !rt.Flatten { - cw.submitGroupedValue(rt.Group, rt.Type, v) + cw.submitGroupedValue(rt.Group, rt.Key, rt.Type, v) for _, asType := range rt.As { - cw.submitGroupedValue(rt.Group, asType, v) + cw.submitGroupedValue(rt.Group, rt.Key, asType, v) } return } if decorated { - cw.submitDecoratedGroupedValue(rt.Group, rt.Type, v) + cw.submitDecoratedGroupedValue(rt.Group, rt.Key, rt.Type, v) return } + // it's not possible to provide a key for the flattening case for i := 0; i < v.Len(); i++ { - cw.submitGroupedValue(rt.Group, rt.Type, v.Index(i)) + cw.submitGroupedValue(rt.Group, "", rt.Type, v.Index(i)) } } diff --git a/result_test.go b/result_test.go index db58ce2b..974e9d8c 100644 --- a/result_test.go +++ b/result_test.go @@ -196,7 +196,7 @@ func TestNewResultObject(t *testing.T) { FieldName: "Writer", FieldIndex: 1, Results: []result{ - resultGrouped{Group: "writers", Type: typeOfWriter}, + resultGrouped{Group: "writers", Key: "writer1", Type: typeOfWriter}, resultSingle{Name: "writer1", Type: typeOfWriter}, }, }, diff --git a/scope.go b/scope.go index 216cf18a..d28806b2 100644 --- a/scope.go +++ b/scope.go @@ -35,6 +35,11 @@ type ScopeOption interface { noScopeOption() //yet } +type keyedGroupValue struct { + key string + value reflect.Value +} + // Scope is a scoped DAG of types and their dependencies. // A Scope may also have one or more child Scopes that inherit // from it. @@ -61,10 +66,10 @@ type Scope struct { values map[key]reflect.Value // Values groups that generated directly in the Scope. - groups map[key][]reflect.Value + groups map[key][]keyedGroupValue // Values groups that generated via decoraters in the Scope. - decoratedGroups map[key]reflect.Value + decoratedGroups map[key]keyedGroupValue // Source of randomness. rand *rand.Rand @@ -98,8 +103,8 @@ func newScope() *Scope { decorators: make(map[key]*decoratorNode), values: make(map[key]reflect.Value), decoratedValues: make(map[key]reflect.Value), - groups: make(map[key][]reflect.Value), - decoratedGroups: make(map[key]reflect.Value), + groups: make(map[key][]keyedGroupValue), + decoratedGroups: make(map[key]keyedGroupValue), invokerFn: defaultInvoker, rand: rand.New(rand.NewSource(time.Now().UnixNano())), } @@ -190,7 +195,7 @@ func (s *Scope) setDecoratedValue(name string, t reflect.Type, v reflect.Value) s.decoratedValues[key{name: name, t: t}] = v } -func (s *Scope) getValueGroup(name string, t reflect.Type) []reflect.Value { +func (s *Scope) getValueGroup(name string, t reflect.Type) []keyedGroupValue { items := s.groups[key{group: name, t: t}] // shuffle the list so users don't rely on the ordering of grouped values return shuffledCopy(s.rand, items) @@ -198,17 +203,17 @@ func (s *Scope) getValueGroup(name string, t reflect.Type) []reflect.Value { func (s *Scope) getDecoratedValueGroup(name string, t reflect.Type) (reflect.Value, bool) { items, ok := s.decoratedGroups[key{group: name, t: t}] - return items, ok + return items.value, ok } -func (s *Scope) submitGroupedValue(name string, t reflect.Type, v reflect.Value) { +func (s *Scope) submitGroupedValue(name, mapKey string, t reflect.Type, v reflect.Value) { k := key{group: name, t: t} - s.groups[k] = append(s.groups[k], v) + s.groups[k] = append(s.groups[k], keyedGroupValue{key: mapKey, value: v}) } -func (s *Scope) submitDecoratedGroupedValue(name string, t reflect.Type, v reflect.Value) { +func (s *Scope) submitDecoratedGroupedValue(name, mapKey string, t reflect.Type, v reflect.Value) { k := key{group: name, t: t} - s.decoratedGroups[k] = v + s.decoratedGroups[k] = keyedGroupValue{key: mapKey, value: v} } func (s *Scope) getValueProviders(name string, t reflect.Type) []provider { @@ -310,9 +315,9 @@ func (s *Scope) String() string { for k, v := range s.values { fmt.Fprintln(b, "\t", k, "=>", v) } - for k, vs := range s.groups { - for _, v := range vs { - fmt.Fprintln(b, "\t", k, "=>", v) + for k, kgvs := range s.groups { + for _, kgv := range kgvs { + fmt.Fprintln(b, "\t", k, "=>", kgv.value) } } fmt.Fprintln(b, "}")