...
1 package gval
2
3 import (
4 "context"
5 "fmt"
6 "reflect"
7 )
8
9 type function func(ctx context.Context, arguments ...interface{}) (interface{}, error)
10
11 func toFunc(f interface{}) function {
12 if f, ok := f.(func(arguments ...interface{}) (interface{}, error)); ok {
13 return function(func(ctx context.Context, arguments ...interface{}) (interface{}, error) {
14 var v interface{}
15 errCh := make(chan error)
16 go func() {
17 defer func() {
18 if recovered := recover(); recovered != nil {
19 errCh <- fmt.Errorf("%v", recovered)
20 }
21 }()
22 result, err := f(arguments...)
23 v = result
24 errCh <- err
25 }()
26
27 select {
28 case <-ctx.Done():
29 return nil, ctx.Err()
30 case err := <-errCh:
31 return v, err
32 }
33 })
34 }
35 if f, ok := f.(func(ctx context.Context, arguments ...interface{}) (interface{}, error)); ok {
36 return function(f)
37 }
38
39 fun := reflect.ValueOf(f)
40 t := fun.Type()
41 return func(ctx context.Context, args ...interface{}) (interface{}, error) {
42 var v interface{}
43 errCh := make(chan error)
44 go func() {
45 defer func() {
46 if recovered := recover(); recovered != nil {
47 errCh <- fmt.Errorf("%v", recovered)
48 }
49 }()
50 in, err := createCallArguments(ctx, t, args)
51 if err != nil {
52 errCh <- err
53 return
54 }
55 out := fun.Call(in)
56
57 r := make([]interface{}, len(out))
58 for i, e := range out {
59 r[i] = e.Interface()
60 }
61
62 err = nil
63 errorInterface := reflect.TypeOf((*error)(nil)).Elem()
64 if len(r) > 0 && t.Out(len(r)-1).Implements(errorInterface) {
65 if r[len(r)-1] != nil {
66 err = r[len(r)-1].(error)
67 }
68 r = r[0 : len(r)-1]
69 }
70
71 switch len(r) {
72 case 0:
73 v = nil
74 case 1:
75 v = r[0]
76 default:
77 v = r
78 }
79 errCh <- err
80 }()
81
82 select {
83 case <-ctx.Done():
84 return nil, ctx.Err()
85 case err := <-errCh:
86 return v, err
87 }
88 }
89 }
90
91 func createCallArguments(ctx context.Context, t reflect.Type, args []interface{}) ([]reflect.Value, error) {
92 variadic := t.IsVariadic()
93 numIn := t.NumIn()
94
95
96 if numIn > 0 {
97 thisFun := reflect.ValueOf(createCallArguments)
98 thisT := thisFun.Type()
99 if t.In(0) == thisT.In(0) {
100 args = append([]interface{}{ctx}, args...)
101 }
102 }
103
104 if (!variadic && len(args) != numIn) || (variadic && len(args) < numIn-1) {
105 return nil, fmt.Errorf("invalid number of parameters")
106 }
107
108 in := make([]reflect.Value, len(args))
109 var inType reflect.Type
110 for i, arg := range args {
111 if !variadic || i < numIn-1 {
112 inType = t.In(i)
113 } else if i == numIn-1 {
114 inType = t.In(numIn - 1).Elem()
115 }
116 argVal := reflect.ValueOf(arg)
117 if arg == nil {
118 argVal = reflect.ValueOf(reflect.Interface)
119 } else if !argVal.Type().AssignableTo(inType) {
120 return nil, fmt.Errorf("expected type %s for parameter %d but got %T",
121 inType.String(), i, arg)
122 }
123 in[i] = argVal
124 }
125 return in, nil
126 }
127
View as plain text