package dig
import (
"fmt"
"reflect"
"go.uber.org/dig/internal/digerror"
"go.uber.org/dig/internal/digreflect"
"go.uber.org/dig/internal/dot"
)
type constructorNode struct {
ctor interface {}
ctype reflect .Type
location *digreflect .Func
id dot .CtorID
called bool
paramList paramList
resultList resultList
orders map [*Scope ]int
s *Scope
origS *Scope
callback Callback
beforeCallback BeforeCallback
}
type constructorOptions struct {
ResultName string
ResultGroup string
ResultAs []interface {}
Location *digreflect .Func
Callback Callback
BeforeCallback BeforeCallback
}
func newConstructorNode(ctor interface {}, s *Scope , origS *Scope , opts constructorOptions ) (*constructorNode , error ) {
cval := reflect .ValueOf (ctor )
ctype := cval .Type ()
cptr := cval .Pointer ()
params , err := newParamList (ctype , s )
if err != nil {
return nil , err
}
results , err := newResultList (
ctype ,
resultOptions {
Name : opts .ResultName ,
Group : opts .ResultGroup ,
As : opts .ResultAs ,
},
)
if err != nil {
return nil , err
}
location := opts .Location
if location == nil {
location = digreflect .InspectFunc (ctor )
}
n := &constructorNode {
ctor : ctor ,
ctype : ctype ,
location : location ,
id : dot .CtorID (cptr ),
paramList : params ,
resultList : results ,
orders : make (map [*Scope ]int ),
s : s ,
origS : origS ,
callback : opts .Callback ,
beforeCallback : opts .BeforeCallback ,
}
s .newGraphNode (n , n .orders )
return n , nil
}
func (n *constructorNode ) Location () *digreflect .Func { return n .location }
func (n *constructorNode ) ParamList () paramList { return n .paramList }
func (n *constructorNode ) ResultList () resultList { return n .resultList }
func (n *constructorNode ) ID () dot .CtorID { return n .id }
func (n *constructorNode ) CType () reflect .Type { return n .ctype }
func (n *constructorNode ) Order (s *Scope ) int { return n .orders [s ] }
func (n *constructorNode ) OrigScope () *Scope { return n .origS }
func (n *constructorNode ) CopyOrder (parent , child *Scope ) {
n .orders [child ] = n .orders [parent ]
}
func (n *constructorNode ) String () string {
return fmt .Sprintf ("deps: %v, ctor: %v" , n .paramList , n .ctype )
}
func (n *constructorNode ) Call (c containerStore ) (err error ) {
if n .called {
return nil
}
if err := shallowCheckDependencies (c , n .paramList ); err != nil {
return errMissingDependencies {
Func : n .location ,
Reason : err ,
}
}
args , err := n .paramList .BuildList (c )
if err != nil {
return errArgumentsFailed {
Func : n .location ,
Reason : err ,
}
}
if n .beforeCallback != nil {
n .beforeCallback (BeforeCallbackInfo {
Name : fmt .Sprintf ("%v.%v" , n .location .Package , n .location .Name ),
})
}
if n .callback != nil {
start := c .clock ().Now ()
defer func () {
n .callback (CallbackInfo {
Name : fmt .Sprintf ("%v.%v" , n .location .Package , n .location .Name ),
Error : err ,
Runtime : c .clock ().Since (start ),
})
}()
}
if n .s .recoverFromPanics {
defer func () {
if p := recover (); p != nil {
err = PanicError {
fn : n .location ,
Panic : p ,
}
}
}()
}
receiver := newStagingContainerWriter ()
results := c .invoker ()(reflect .ValueOf (n .ctor ), args )
if err = n .resultList .ExtractList (receiver , false , results ); err != nil {
return errConstructorFailed {Func : n .location , Reason : err }
}
receiver .Commit (n .s )
n .called = true
return nil
}
type stagingContainerWriter struct {
values map [key ]reflect .Value
groups map [key ][]reflect .Value
}
var _ containerWriter = (*stagingContainerWriter )(nil )
func newStagingContainerWriter() *stagingContainerWriter {
return &stagingContainerWriter {
values : make (map [key ]reflect .Value ),
groups : make (map [key ][]reflect .Value ),
}
}
func (sr *stagingContainerWriter ) setValue (name string , t reflect .Type , v reflect .Value ) {
sr .values [key {t : t , name : name }] = v
}
func (sr *stagingContainerWriter ) setDecoratedValue (_ string , _ reflect .Type , _ reflect .Value ) {
digerror .BugPanicf ("stagingContainerWriter.setDecoratedValue must never be called" )
}
func (sr *stagingContainerWriter ) submitGroupedValue (group string , t reflect .Type , v reflect .Value ) {
k := key {t : t , group : group }
sr .groups [k ] = append (sr .groups [k ], v )
}
func (sr *stagingContainerWriter ) submitDecoratedGroupedValue (_ string , _ reflect .Type , _ reflect .Value ) {
digerror .BugPanicf ("stagingContainerWriter.submitDecoratedGroupedValue must never be called" )
}
func (sr *stagingContainerWriter ) Commit (cw containerWriter ) {
for k , v := range sr .values {
cw .setValue (k .name , k .t , v )
}
for k , vs := range sr .groups {
for _ , v := range vs {
cw .submitGroupedValue (k .group , k .t , v )
}
}
}
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 .