/
schema_decode.go
169 lines (142 loc) · 4.63 KB
/
schema_decode.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package jsonpack
import (
"reflect"
"github.com/pkg/errors"
ibuf "github.com/arloliu/jsonpack/buffer"
"github.com/modern-go/reflect2"
)
/*
Decode reads encoded data with compiled schema definition and stores the result
in the value pointed to v.
If type of v is not a pointer type that pointed to a map or struct, Decode
function will return DecodeError.
The valid type of v is either a *map[string]interface{} or a pointer to the struct
which added by AddSchema function.
Example of decoding data into map with "Info" schema
decodeInfoMap = make(map[string]interface{})
err := jsonPack.Decode("Info", encodedData, &decodeInfoMap)
Example of decoding data into Info struct instance with "Info" schema
decodeInfoStruct = Info{}
err := jsonPack.Decode("Info", encodedData, &decodeInfoStruct)
*/
func (s *Schema) Decode(data []byte, v interface{}) (err error) {
return s.decode(data, v, true)
}
// Unmarshal is an alias to Decode function, provides familiar interface of json package
func (s *Schema) Unmarshal(data []byte, v interface{}) (err error) {
return s.Decode(data, v)
}
func (s *Schema) decode(data []byte, v interface{}, checkPtrType bool) (err error) {
defer func() {
if r := recover(); r != nil {
switch r := r.(type) {
case string:
err = errors.WithStack(&DecodeError{s.Name, errors.New(r)})
case error:
err = errors.WithStack(&DecodeError{s.Name, r})
}
}
}()
if v == nil {
return errors.WithStack(&DecodeError{s.Name, errors.New("target of decoding is nil")})
}
vType := reflect2.TypeOf(v)
if vType == nil {
return errors.WithStack(&DecodeError{s.Name, errors.New("invalid type of target")})
}
vKind := vType.Kind()
if reflect2.IsNil(v) {
err = errors.WithStack(&DecodeError{s.Name, &WrongTypeError{vType.String()}})
return
}
if checkPtrType && vKind != reflect.Ptr && vKind != reflect.Map {
err = errors.WithStack(&DecodeError{s.Name, &WrongTypeError{vType.String()}})
return
}
buf := ibuf.From(data)
switch d := v.(type) {
case *map[string]interface{}:
_, err = s.decodeDynamic(buf, s.rootOp, *d)
if err != nil {
return err
}
case *[]map[string]interface{}:
_, err = _sliceOp.decodeDynamic(buf, s.rootOp, d)
if err != nil {
return err
}
case *[]interface{}:
// pass pointer of slice instead of dereferenced value due to slice is not reference type
_, err = _sliceOp.decodeDynamic(buf, s.rootOp, d)
if err != nil {
return err
}
case *interface{}:
return s.decode(data, *d, false)
default:
switch vKind {
case reflect.Struct:
var sop *structOperation
sop, err = s.getStructOperation(vType, v)
if err != nil {
return errors.WithStack(&DecodeError{s.Name, err})
}
return s.decodeStruct(buf, sop, v)
case reflect.Slice:
sliceType := vType.(*reflect2.UnsafeSliceType)
vType = sliceType.Elem()
if vType.Kind() == reflect.Struct {
var sop *structOperation
sop, err = s.getStructOperation(vType, v)
if err != nil {
return errors.WithStack(&DecodeError{s.Name, err})
}
return s.decodeStruct(buf, sop, v)
} else if vType.Kind() == reflect.Map || vType.Kind() == reflect.Interface {
_, err = s.decodeDynamic(buf, s.rootOp, v)
} else {
return errors.WithStack(&DecodeError{s.Name, &WrongTypeError{vType.String()}})
}
case reflect.Array:
sliceType := vType.(*reflect2.UnsafeArrayType)
vType = sliceType.Elem()
if vType.Kind() == reflect.Struct {
var sop *structOperation
sop, err = s.getStructOperation(vType, v)
if err != nil {
return errors.WithStack(&DecodeError{s.Name, err})
}
return s.decodeStruct(buf, sop, v)
} else if vType.Kind() == reflect.Map || vType.Kind() == reflect.Interface {
_, err = s.decodeDynamic(buf, s.rootOp, v)
if err != nil {
return err
}
} else {
return errors.WithStack(&DecodeError{s.Name, &WrongTypeError{vType.String()}})
}
case reflect.Ptr:
elemType := toPtrElemType(vType)
if elemType.Kind() == reflect.Array {
_, err = _arrayOp.decodeDynamic(buf, s.rootOp, v)
} else {
return s.decode(data, elemType.Indirect(v), false)
}
default:
return errors.WithStack(&DecodeError{s.Name, &WrongTypeError{vType.String()}})
}
}
if err != nil {
err = errors.WithStack(&DecodeError{s.Name, err})
}
return
}
func (s *Schema) decodeDynamic(buf *ibuf.Buffer, opNode *operation, d interface{}) (interface{}, error) {
return opNode.handler.decodeDynamic(buf, opNode, d)
}
func (s *Schema) decodeStruct(buf *ibuf.Buffer, opNode *structOperation, v interface{}) error {
if opNode.handler == nil {
return errors.Errorf("opearation handler is nil")
}
return opNode.handler.decodeStruct(buf, opNode, reflect2.PtrOf(v))
}