This repository has been archived by the owner on Feb 9, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprocessor.go
130 lines (122 loc) · 3.23 KB
/
processor.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package kinitx
import (
"reflect"
"github.com/go-kata/kerror"
)
// Processor represents a processor based on a function.
type Processor struct {
// t specifies the type of an object that is processed by this processor.
t reflect.Type
// function specifies the reflection to a function value.
function reflect.Value
// inTypes specifies types of function input parameters.
inTypes []reflect.Type
// errorOutIndex specifies the index of a function output parameter that contains an error.
// The value -1 means that a function doesn't return an error.
errorOutIndex int
}
// NewProcessor returns a new processor.
//
// The argument x must be a function that is compatible with one of following signatures
// (T is an arbitrary Go type):
//
// func(T, ...);
//
// func(T, ...) error.
//
func NewProcessor(x interface{}) (*Processor, error) {
if x == nil {
return nil, kerror.New(kerror.EViolation, "function expected, nil given")
}
ft := reflect.TypeOf(x)
fv := reflect.ValueOf(x)
if ft.Kind() != reflect.Func {
return nil, kerror.Newf(kerror.EViolation, "function expected, %s given", ft)
}
if fv.IsNil() {
return nil, kerror.New(kerror.EViolation, "function expected, nil given")
}
p := &Processor{
function: fv,
}
numIn := ft.NumIn()
if ft.IsVariadic() {
numIn--
}
if numIn < 1 {
return nil, kerror.Newf(kerror.EViolation, "function %s is not a processor", ft)
}
p.t = ft.In(0)
p.inTypes = make([]reflect.Type, numIn-1)
for i := 1; i < numIn; i++ {
p.inTypes[i-1] = ft.In(i)
}
switch ft.NumOut() {
default:
return nil, kerror.Newf(kerror.EViolation, "function %s is not a processor", ft)
case 0:
p.errorOutIndex = -1
case 1:
if ft.Out(0) != errorType {
return nil, kerror.Newf(kerror.EViolation, "function %s is not a processor", ft)
}
p.errorOutIndex = 0
}
return p, nil
}
// MustNewProcessor is a variant of the NewProcessor that panics on error.
func MustNewProcessor(x interface{}) *Processor {
p, err := NewProcessor(x)
if err != nil {
panic(err)
}
return p
}
// Type implements the kinit.Processor interface.
func (p *Processor) Type() reflect.Type {
if p == nil {
return nil
}
return p.t
}
// Parameters implements the kinit.Processor interface.
func (p *Processor) Parameters() []reflect.Type {
if p == nil {
return nil
}
types := make([]reflect.Type, len(p.inTypes))
copy(types, p.inTypes)
return types
}
// Process implements the kinit.Processor interface.
func (p *Processor) Process(obj reflect.Value, a ...reflect.Value) error {
if p == nil {
return nil
}
if obj.Type() != p.t {
return kerror.Newf(kerror.EViolation,
"%s processor doesn't accept objects of %s type", p.t, obj.Type())
}
if len(a) != len(p.inTypes) {
return kerror.Newf(kerror.EViolation,
"%s processor expects %d argument(s), %d given", p.t, len(p.inTypes), len(a))
}
in := make([]reflect.Value, len(p.inTypes)+1)
in[0] = obj
for i, v := range a {
if v.Type() != p.inTypes[i] {
return kerror.Newf(kerror.EViolation,
"%s processor expects argument %d to be of %s type, %s given",
p.t, i+1, p.inTypes[i], v.Type())
}
in[i+1] = a[i]
}
out := p.function.Call(in)
var err error
if p.errorOutIndex >= 0 {
if v := out[p.errorOutIndex].Interface(); v != nil {
err = v.(error)
}
}
return err
}