package dig
import (
"bytes"
"fmt"
"math/rand"
"reflect"
"sort"
"time"
"go.uber.org/dig/internal/digclock"
)
type ScopeOption interface {
noScopeOption()
}
type Scope struct {
name string
providers map [key ][]*constructorNode
decorators map [key ]*decoratorNode
nodes []*constructorNode
decoratedValues map [key ]reflect .Value
values map [key ]reflect .Value
groups map [key ][]reflect .Value
decoratedGroups map [key ]reflect .Value
rand *rand .Rand
isVerifiedAcyclic bool
deferAcyclicVerification bool
recoverFromPanics bool
invokerFn invokerFn
gh *graphHolder
parentScope *Scope
childScopes []*Scope
clockSrc digclock .Clock
}
func newScope() *Scope {
s := &Scope {
providers : make (map [key ][]*constructorNode ),
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 ),
invokerFn : defaultInvoker ,
rand : rand .New (rand .NewSource (time .Now ().UnixNano ())),
clockSrc : digclock .System ,
}
s .gh = newGraphHolder (s )
return s
}
func (s *Scope ) Scope (name string , opts ...ScopeOption ) *Scope {
child := newScope ()
child .name = name
child .parentScope = s
child .invokerFn = s .invokerFn
child .clockSrc = s .clockSrc
child .deferAcyclicVerification = s .deferAcyclicVerification
child .recoverFromPanics = s .recoverFromPanics
for _ , node := range s .gh .nodes {
child .gh .nodes = append (child .gh .nodes , node )
if ctrNode , ok := node .Wrapped .(*constructorNode ); ok {
ctrNode .CopyOrder (s , child )
}
}
for _ , opt := range opts {
opt .noScopeOption ()
}
s .childScopes = append (s .childScopes , child )
return child
}
func (s *Scope ) ancestors () []*Scope {
var scopes []*Scope
for s := s ; s != nil ; s = s .parentScope {
scopes = append (scopes , s )
}
return scopes
}
func (s *Scope ) appendSubscopes (dest []*Scope ) []*Scope {
dest = append (dest , s )
for _ , cs := range s .childScopes {
dest = cs .appendSubscopes (dest )
}
return dest
}
func (s *Scope ) storesToRoot () []containerStore {
scopes := s .ancestors ()
stores := make ([]containerStore , len (scopes ))
for i , s := range scopes {
stores [i ] = s
}
return stores
}
func (s *Scope ) knownTypes () []reflect .Type {
typeSet := make (map [reflect .Type ]struct {}, len (s .providers ))
for k := range s .providers {
typeSet [k .t ] = struct {}{}
}
types := make ([]reflect .Type , 0 , len (typeSet ))
for t := range typeSet {
types = append (types , t )
}
sort .Sort (byTypeName (types ))
return types
}
func (s *Scope ) getValue (name string , t reflect .Type ) (v reflect .Value , ok bool ) {
v , ok = s .values [key {name : name , t : t }]
return
}
func (s *Scope ) getDecoratedValue (name string , t reflect .Type ) (v reflect .Value , ok bool ) {
v , ok = s .decoratedValues [key {name : name , t : t }]
return
}
func (s *Scope ) setValue (name string , t reflect .Type , v reflect .Value ) {
s .values [key {name : name , t : t }] = v
}
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 {
items := s .groups [key {group : name , t : t }]
return shuffledCopy (s .rand , items )
}
func (s *Scope ) getDecoratedValueGroup (name string , t reflect .Type ) (reflect .Value , bool ) {
items , ok := s .decoratedGroups [key {group : name , t : t }]
return items , ok
}
func (s *Scope ) submitGroupedValue (name string , t reflect .Type , v reflect .Value ) {
k := key {group : name , t : t }
s .groups [k ] = append (s .groups [k ], v )
}
func (s *Scope ) submitDecoratedGroupedValue (name string , t reflect .Type , v reflect .Value ) {
k := key {group : name , t : t }
s .decoratedGroups [k ] = v
}
func (s *Scope ) getValueProviders (name string , t reflect .Type ) []provider {
return s .getProviders (key {name : name , t : t })
}
func (s *Scope ) getGroupProviders (name string , t reflect .Type ) []provider {
return s .getProviders (key {group : name , t : t })
}
func (s *Scope ) getValueDecorator (name string , t reflect .Type ) (decorator , bool ) {
return s .getDecorators (key {name : name , t : t })
}
func (s *Scope ) getGroupDecorator (name string , t reflect .Type ) (decorator , bool ) {
return s .getDecorators (key {group : name , t : t })
}
func (s *Scope ) getDecorators (k key ) (decorator , bool ) {
d , found := s .decorators [k ]
return d , found
}
func (s *Scope ) getProviders (k key ) []provider {
nodes := s .providers [k ]
providers := make ([]provider , len (nodes ))
for i , n := range nodes {
providers [i ] = n
}
return providers
}
func (s *Scope ) getAllGroupProviders (name string , t reflect .Type ) []provider {
return s .getAllProviders (key {group : name , t : t })
}
func (s *Scope ) getAllValueProviders (name string , t reflect .Type ) []provider {
return s .getAllProviders (key {name : name , t : t })
}
func (s *Scope ) getAllProviders (k key ) []provider {
allScopes := s .ancestors ()
var providers []provider
for _ , scope := range allScopes {
providers = append (providers , scope .getProviders (k )...)
}
return providers
}
func (s *Scope ) invoker () invokerFn {
return s .invokerFn
}
func (s *Scope ) clock () digclock .Clock {
return s .clockSrc
}
func (s *Scope ) newGraphNode (wrapped interface {}, orders map [*Scope ]int ) {
orders [s ] = s .gh .NewNode (wrapped )
for _ , cs := range s .childScopes {
cs .newGraphNode (wrapped , orders )
}
}
func (s *Scope ) cycleDetectedError (cycle []int ) error {
var path []cycleErrPathEntry
for _ , n := range cycle {
if n , ok := s .gh .Lookup (n ).(*constructorNode ); ok {
path = append (path , cycleErrPathEntry {
Key : key {
t : n .CType (),
},
Func : n .Location (),
})
}
}
return errCycleDetected {Path : path , scope : s }
}
func (s *Scope ) rootScope () *Scope {
curr := s
for curr .parentScope != nil {
curr = curr .parentScope
}
return curr
}
func (s *Scope ) String () string {
b := &bytes .Buffer {}
fmt .Fprintln (b , "nodes: {" )
for k , vs := range s .providers {
for _ , v := range vs {
fmt .Fprintln (b , "\t" , k , "->" , v )
}
}
fmt .Fprintln (b , "}" )
fmt .Fprintln (b , "values: {" )
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 )
}
}
fmt .Fprintln (b , "}" )
return b .String ()
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .