Skip to content

📝 Add docstrings to before-callback #432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions before_callback.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (c) 2023 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package dig

// BeforeCallbackInfo contains information about a provided function or decorator
// called by Dig, and is passed to a [BeforeCallback] registered with
// [WithProviderBeforeCallback] or [WithDecoratorBeforeCallback].
type BeforeCallbackInfo struct {
// Name is the name of the function in the format:
// <package_name>.<function_name>
Name string
}

// BeforeCallback is a function that can be registered with a provided function
// or decorator with [WithCallback] to cause it to be called before the
// provided function or decorator is run.
type BeforeCallback func(bci BeforeCallbackInfo)

// WithProviderBeforeCallback returns a [ProvideOption] which has Dig call
// the passed in [BeforeCallback] before the corresponding constructor begins running.
//
// For example, the following prints a message
// before "myConstructor" is called:
//
// c := dig.New()
// myCallback := func(bci BeforeCallbackInfo) {
// fmt.Printf("%q started", bci.Name)
// }
// c.Provide(myConstructor, WithProviderBeforeCallback(myCallback)),
//
// BeforeCallbacks can also be specified for Decorators with [WithDecoratorBeforeCallback].
//
// WithProviderBeforeCallback returns a ProvideOption that registers the specified BeforeCallback to be invoked before a constructor function is executed. The provided callback receives a BeforeCallbackInfo detailing the target function's fully-qualified name in the format "<package>.<function>".
func WithProviderBeforeCallback(callback BeforeCallback) ProvideOption {
return withBeforeCallbackOption{
callback: callback,
}
}

// WithDecoratorBeforeCallback returns a [DecorateOption] which has Dig call
// the passed in [BeforeCallback] before the corresponding decorator begins running.
//
// For example, the following prints a message
// before "myDecorator" is called:
//
// c := dig.New()
// myCallback := func(bci BeforeCallbackInfo) {
// fmt.Printf("%q started", bci.Name)
// }
// c.Decorate(myDecorator, WithDecoratorBeforeCallback(myCallback)),
//
// BeforeCallbacks can also be specified for Constructors with [WithProviderBeforeCallback].
//
// WithDecoratorBeforeCallback returns a DecorateOption that registers the given BeforeCallback to be executed before a decorator is applied.
// The callback is invoked with a BeforeCallbackInfo that includes the name of the target decorator.
func WithDecoratorBeforeCallback(callback BeforeCallback) DecorateOption {
return withBeforeCallbackOption{
callback: callback,
}
}

type withBeforeCallbackOption struct {
callback BeforeCallback
}

var (
_ ProvideOption = withBeforeCallbackOption{}
_ DecorateOption = withBeforeCallbackOption{}
)

func (o withBeforeCallbackOption) applyProvideOption(po *provideOptions) {
po.BeforeCallback = o.callback

Check failure on line 90 in before_callback.go

View workflow job for this annotation

GitHub Actions / Lint

po.BeforeCallback undefined (type *provideOptions has no field or method BeforeCallback)) (typecheck)

Check failure on line 90 in before_callback.go

View workflow job for this annotation

GitHub Actions / Lint

po.BeforeCallback undefined (type *provideOptions has no field or method BeforeCallback)) (typecheck)

Check failure on line 90 in before_callback.go

View workflow job for this annotation

GitHub Actions / Lint

po.BeforeCallback undefined (type *provideOptions has no field or method BeforeCallback) (typecheck)

Check failure on line 90 in before_callback.go

View workflow job for this annotation

GitHub Actions / Test (Go 1.24.x / ubuntu-latest)

po.BeforeCallback undefined (type *provideOptions has no field or method BeforeCallback)

Check failure on line 90 in before_callback.go

View workflow job for this annotation

GitHub Actions / Test (Go 1.23.x / ubuntu-latest)

po.BeforeCallback undefined (type *provideOptions has no field or method BeforeCallback)
}

func (o withBeforeCallbackOption) apply(do *decorateOptions) {
do.BeforeCallback = o.callback
}
42 changes: 27 additions & 15 deletions constructor.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,23 @@ type constructorNode struct {

// Callback for this provided function, if there is one.
callback Callback

// BeforeCallback for this provided function, if there is one.
beforeCallback BeforeCallback
}

type constructorOptions struct {
// If specified, all values produced by this constructor have the provided name
// belong to the specified value group or implement any of the interfaces.
ResultName string
ResultGroup string
ResultAs []interface{}
Location *digreflect.Func
Callback Callback
ResultName string
ResultGroup string
ResultAs []interface{}
Location *digreflect.Func
Callback Callback
BeforeCallback BeforeCallback
}

// newConstructorNode creates a new constructor node for the dependency injection graph. It uses reflection to inspect the provided constructor function, initializing its parameter and result lists with the given options (such as result naming, grouping, and type assertions). If no location is provided in the options, the constructor’s location is automatically determined. The new node is associated with both the current and original scopes and is configured with callbacks—including an optional pre-callback—to be executed during dependency resolution. An error is returned if the initialization of the parameter or result lists fails.
func newConstructorNode(ctor interface{}, s *Scope, origS *Scope, opts constructorOptions) (*constructorNode, error) {
cval := reflect.ValueOf(ctor)
ctype := cval.Type()
Expand Down Expand Up @@ -106,16 +111,17 @@ func newConstructorNode(ctor interface{}, s *Scope, origS *Scope, opts construct
}

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,
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
Expand Down Expand Up @@ -160,6 +166,12 @@ func (n *constructorNode) Call(c containerStore) (err error) {
}
}

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()
// Wrap in separate func to include PanicErrors
Expand Down
37 changes: 26 additions & 11 deletions decorate.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,16 @@ type decoratorNode struct {

// Callback for this decorator, if there is one.
callback Callback

// BeforeCallback for this decorator, if there is one
beforeCallback BeforeCallback
}

// newDecoratorNode creates a new decorator node for the given decorator function, scope, and decoration options.
//
// It uses reflection to extract type information and a unique identifier from the decorator function, constructs the necessary
// parameter and result lists, and initializes the node with any specified callbacks, including a pre-execution callback if provided.
// An error is returned if initialization of the parameter or result lists fails.
func newDecoratorNode(dcor interface{}, s *Scope, opts decorateOptions) (*decoratorNode, error) {
dval := reflect.ValueOf(dcor)
dtype := dval.Type()
Expand All @@ -86,15 +94,16 @@ func newDecoratorNode(dcor interface{}, s *Scope, opts decorateOptions) (*decora
}

n := &decoratorNode{
dcor: dcor,
dtype: dtype,
id: dot.CtorID(dptr),
location: digreflect.InspectFunc(dcor),
orders: make(map[*Scope]int),
params: pl,
results: rl,
s: s,
callback: opts.Callback,
dcor: dcor,
dtype: dtype,
id: dot.CtorID(dptr),
location: digreflect.InspectFunc(dcor),
orders: make(map[*Scope]int),
params: pl,
results: rl,
s: s,
callback: opts.Callback,
beforeCallback: opts.BeforeCallback,
}
return n, nil
}
Expand All @@ -120,6 +129,11 @@ func (n *decoratorNode) Call(s containerStore) (err error) {
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 := s.clock().Now()
Expand Down Expand Up @@ -162,8 +176,9 @@ type DecorateOption interface {
}

type decorateOptions struct {
Info *DecorateInfo
Callback Callback
Info *DecorateInfo
Callback Callback
BeforeCallback BeforeCallback
}

// FillDecorateInfo is a DecorateOption that writes info on what Dig was
Expand Down
Loading