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
/
initializer.go
111 lines (103 loc) · 2.92 KB
/
initializer.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
package kinitx
import (
"reflect"
"github.com/go-kata/kdone"
"github.com/go-kata/kerror"
)
// Initializer represents a constructor based on a struct.
type Initializer struct {
// t specifies the type of an object that is created by this initializer.
t reflect.Type
// assignableFieldTypes specifies types of assignable struct fields.
assignableFieldTypes []reflect.Type
// assignableFieldIndexes specifies indexes of assignable struct fields.
assignableFieldIndexes []int
}
// NewInitializer returns a new initializer.
//
// The argument x must be a struct or a struct pointer.
func NewInitializer(x interface{}) (*Initializer, error) {
if x == nil {
return nil, kerror.New(kerror.EViolation, "struct or struct pointer expected, nil given")
}
t := reflect.TypeOf(x)
var st reflect.Type
switch t.Kind() {
default:
return nil, kerror.Newf(kerror.EViolation, "struct or struct pointer expected, %s given", t)
case reflect.Struct:
st = t
case reflect.Ptr:
st = t.Elem()
if st.Kind() != reflect.Struct {
return nil, kerror.Newf(kerror.EViolation, "struct or struct pointer expected, %s given", t)
}
}
c := &Initializer{
t: t,
}
for i, n := 0, st.NumField(); i < n; i++ {
sf := st.Field(i)
if sf.PkgPath != "" {
continue
}
c.assignableFieldTypes = append(c.assignableFieldTypes, sf.Type)
c.assignableFieldIndexes = append(c.assignableFieldIndexes, i)
}
return c, nil
}
// MustNewInitializer is a variant of the NewInitializer that panics on error.
func MustNewInitializer(x interface{}) *Initializer {
c, err := NewInitializer(x)
if err != nil {
panic(err)
}
return c
}
// Type implements the kinit.Constructor interface.
func (c *Initializer) Type() reflect.Type {
if c == nil {
return nil
}
return c.t
}
// Parameters implements the kinit.Constructor interface.
func (c *Initializer) Parameters() []reflect.Type {
if c == nil {
return nil
}
types := make([]reflect.Type, len(c.assignableFieldTypes))
copy(types, c.assignableFieldTypes)
return types
}
// Create implements the kinit.Constructor interface.
func (c *Initializer) Create(a ...reflect.Value) (reflect.Value, kdone.Destructor, error) {
if c == nil {
return reflect.Value{}, kdone.Noop, nil
}
if len(a) != len(c.assignableFieldTypes) {
return reflect.Value{}, kdone.Noop, kerror.Newf(kerror.EViolation,
"%s initializer expects %d argument(s), %d given",
c.t, len(c.assignableFieldTypes), len(a))
}
for i, v := range a {
if v.Type() != c.assignableFieldTypes[i] {
return reflect.Value{}, kdone.Noop, kerror.Newf(kerror.EViolation,
"%s initializer expects argument %d to be of %s type, %s given",
c.t, i+1, c.assignableFieldTypes[i], v.Type())
}
}
var sp, obj reflect.Value
if c.t.Kind() == reflect.Ptr {
sp = reflect.New(c.t.Elem())
obj = sp
} else {
sp = reflect.New(c.t)
obj = sp.Elem()
}
sv := sp.Elem()
for i, v := range a {
sv.Field(c.assignableFieldIndexes[i]).Set(v)
}
return obj, kdone.Noop, nil
}