-
Notifications
You must be signed in to change notification settings - Fork 4
/
invoker.go
101 lines (87 loc) · 2.73 KB
/
invoker.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/*
* SPDX-FileCopyrightText: Copyright (c) 2003 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package gontainer
import (
"fmt"
"reflect"
)
// Invoker defines invoker interface.
type Invoker interface {
// Invoke invokes specified function.
Invoke(fn any) (InvokeResult, error)
}
// invoker implements invoker interface.
type invoker struct {
resolver Resolver
}
// Invoke invokes specified function.
func (i *invoker) Invoke(fn any) (InvokeResult, error) {
// Get reflection of the fn.
fnValue := reflect.ValueOf(fn)
if fnValue.Kind() != reflect.Func {
return nil, fmt.Errorf("fn must be a function")
}
// Resolve function arguments.
fnInArgs := make([]reflect.Value, 0, fnValue.Type().NumIn())
for index := 0; index < fnValue.Type().NumIn(); index++ {
fnArgPtrValue := reflect.New(fnValue.Type().In(index))
if err := i.resolver.Resolve(fnArgPtrValue.Interface()); err != nil {
return nil, fmt.Errorf("failed to resolve dependency: %w", err)
}
fnInArgs = append(fnInArgs, fnArgPtrValue.Elem())
}
// Convert function results.
fnOutArgs := fnValue.Call(fnInArgs)
result := &invokeResult{
values: make([]any, 0, len(fnOutArgs)),
err: nil,
}
for index, fnOut := range fnOutArgs {
// If it is the last return value.
if index == len(fnOutArgs)-1 {
// And type of the value is the error.
if fnOut.Type().Implements(errorType) {
// Use the value as an error.
// Ignore failed cast of nil error.
result.err, _ = fnOut.Interface().(error)
}
}
// Add value to the results slice.
result.values = append(result.values, fnOut.Interface())
}
return result, nil
}
// InvokeResult provides access to the invocation result.
type InvokeResult interface {
// Values returns a slice of function result values.
Values() []any
// Error returns function result error, if any.
Error() error
}
// invokeResult implements corresponding interface.
type invokeResult struct {
values []any
err error
}
// Values implements corresponding interface method.
func (r *invokeResult) Values() []any {
return r.values
}
// Error implements corresponding interface method.
func (r *invokeResult) Error() error {
return r.err
}