/
encode.go
59 lines (56 loc) · 1.21 KB
/
encode.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
package runtimescan
import (
"reflect"
)
// Encode convert from some source into struct by using tag information.
func Encode(src any, tags []string, encoder Encoder) error {
v, err := getParser(src, tags, encoder)
if err != nil {
return err
}
return encode(encoder, v, src)
}
func encode(encoder Encoder, v *parser, src any) error {
current := reflect.ValueOf(src).Elem()
stack := []reflect.Value{current}
var errors []error
for i, op := range v.fieldOps {
index := v.fieldIndexes[i]
field := v.fields[i]
switch op {
case visitFieldOp:
fv := current.Field(index)
var value any
if field.isPtr {
if fv.IsNil() {
value = nil
} else {
value = fv.Elem().Interface()
}
} else {
value = fv.Interface()
}
err := encoder.VisitField(field.tag, value)
if err == Skip {
continue
} else if err != nil {
errors = append(errors, err)
continue
}
case visitChildOp:
// todo: call EnterChild
current = current.Field(index)
stack = append(stack, current)
case leaveChildOp:
// todo: call LeaveChild
stack = stack[:len(stack)-1]
current = stack[len(stack)-1]
}
}
if len(errors) > 0 {
return &Errors{
Errors: errors,
}
}
return nil
}