-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathaccessor.go
128 lines (117 loc) · 2.76 KB
/
accessor.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
package godiff
import (
"fmt"
"github.com/viant/xunsafe"
"reflect"
"unsafe"
)
type nullifierKind int
const (
nullifierKindUnspecified = nullifierKind(iota)
nullifierKindInt
nullifierKindString
nullifierKindFloat64
nullifierKindFloat32
)
type accessor struct {
pos int
deref bool
normType reflect.Type //if from,to data type is different (i.e. int64 vs uint64), norm type is used to reconcile the types
xType *xunsafe.Type
nullifierKind
*xunsafe.Field
}
func (d *accessor) normalize(value interface{}) (interface{}, error) {
if value == nil {
return value, nil
}
if d.deref {
value = d.xType.Deref(value)
}
if d.normType != nil {
ptr := xunsafe.AsPointer(value)
switch d.normType.Kind() {
case reflect.Int:
return *(*int)(ptr), nil
case reflect.Int32:
return *(*int32)(ptr), nil
case reflect.Int64:
return *(*int64)(ptr), nil
case reflect.Int16:
return *(*int16)(ptr), nil
case reflect.Uint8:
return *(*uint8)(ptr), nil
default:
return nil, fmt.Errorf("unsupported norm type: %T", value)
}
}
return value, nil
}
func (d *accessor) Value(ptr unsafe.Pointer) (value interface{}, err error) {
if d.IsNil(ptr) {
return nil, nil
}
value = d.Field.Value(ptr)
if value, err = d.normalize(value); err != nil {
return nil, err
}
return value, nil
}
func (d *accessor) IsNilOrEmpty(value interface{}) bool {
if value == nil {
return true
}
return d.nullifyIfNeeded(value) == nil
}
func (d *accessor) nullifyIfNeeded(value interface{}) interface{} {
if d.nullifierKind == nullifierKindUnspecified {
return value
}
ptr := xunsafe.AsPointer(value)
switch d.nullifierKind {
case nullifierKindInt:
if *(*int)(ptr) == 0 {
return nil
}
case nullifierKindString:
if *(*string)(ptr) == "" {
return nil
}
case nullifierKindFloat32:
if *(*float32)(ptr) == 0 {
return nil
}
case nullifierKindFloat64:
if *(*float64)(ptr) == 0 {
return nil
}
}
return value
}
func newAccessor(pos int, field *xunsafe.Field, tag *Tag) accessor {
result := accessor{
pos: pos,
Field: field,
deref: field.Type.Kind() == reflect.Ptr && (structType(field.Type.Elem()) == nil || isTimeType(field.Type.Elem())),
nullifierKind: getNullifierKind(tag, field),
}
if result.deref {
result.xType = xunsafe.NewType(field.Type.Elem())
}
return result
}
func getNullifierKind(tag *Tag, field *xunsafe.Field) nullifierKind {
if tag.NullifyEmpty != nil && *tag.NullifyEmpty {
switch field.Type.Kind() {
case reflect.Int, reflect.Int64, reflect.Uint, reflect.Uint64:
return nullifierKindInt
case reflect.Float64:
return nullifierKindFloat64
case reflect.Float32:
return nullifierKindFloat32
case reflect.String:
return nullifierKindString
}
}
return nullifierKindUnspecified
}