forked from Ompluscator/dynamic-struct
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwriter.go
143 lines (137 loc) · 3.55 KB
/
writer.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
package dynamicstruct
import (
"errors"
"fmt"
"log"
"reflect"
"strings"
)
// Writer is helper interface for writing to a struct.
type Writer interface {
// Set sets the value of the field with the given name.
Set(value any) error
Get() (any, bool)
LinkSet(name string, value any) error // slice map 删除则设置为value nil
LinkGet(name string) (any, bool)
linkSet(names []string, value any) error // slice map 删除则设置为value nil
linkGet(names []string) (any, bool)
Type() reflect.Type
linkTyp(names []string) (reflect.Type, bool)
LinkTyp(name string) (reflect.Type, bool)
}
// todo add support slice map
func subWriter(value any) (writer Writer, err error) {
defer func() {
rec := recover()
if rec != nil {
err = errors.New(fmt.Sprint(recover()))
}
}()
fields := make(map[string]Writer)
valueOf, ok := value.(reflect.Value)
if !ok {
valueOf = reflect.ValueOf(value)
}
for {
fmt.Println(valueOf.Kind())
if valueOf.Kind() != reflect.Ptr && valueOf.Kind() != reflect.Interface {
break
}
valueOf = valueOf.Elem()
}
typeOf := valueOf.Type()
if typeOf.Kind() != reflect.Struct {
fmt.Println(typeOf.Kind())
return nil, errors.New("value must be struct ptr")
}
for i := 0; i < valueOf.NumField(); i++ {
field := typeOf.Field(i)
var impl Writer
if field.Type.Kind() == reflect.Struct {
impl, err = subWriter(valueOf.Field(i))
if err != nil {
return nil, err
}
} else if field.Type.Kind() == reflect.Pointer { // todo暂时不要支持指针?
elem := field.Type.Elem()
if elem.Kind() == reflect.Map {
impl = &mapImpl{
field: field,
mapWriters: make(map[any]Writer),
value: valueOf.Field(i),
}
} else {
return nil, errors.New("not suport pointer")
}
} else if field.Type.Kind() == reflect.Map { // todo暂时不要支持指针?
valueOf.Field(i).Set(reflect.MakeMap(valueOf.Field(i).Type()))
impl = &mapImpl{
field: field,
mapWriters: make(map[any]Writer),
value: valueOf.Field(i),
}
} else if field.Type.Kind() == reflect.Slice {
slice := &sliceImpl{
field: field,
value: valueOf.Field(i),
mapWriters: make(map[any]Writer),
}
tagStr := field.Tag.Get("dynamic")
if len(tagStr) > 0 {
tags := strings.Split(tagStr, ",")
for _, tag := range tags {
infos := strings.Split(tag, "=")
if len(infos) == 2 {
k, v := infos[0], infos[1]
if k == "sliceKey" {
slice.sliceToMap = v
}
} else {
log.Printf("got error tag:%s", tagStr)
}
}
}
impl = slice
} else {
impl = &scalarImpl{
field: field,
value: valueOf.Field(i),
}
}
fields[field.Name] = impl
}
return &structImpl{
fields: fields,
value: valueOf,
field: valueOf.Type(),
}, nil
}
func NewWriter(value any) (writer Writer, err error) {
valueOf := reflect.ValueOf(value)
if valueOf.Kind() != reflect.Ptr {
fmt.Println(valueOf.Kind())
return nil, errors.New("value must be ptr")
}
var typeOf reflect.Type
for {
typeOf = valueOf.Type()
if typeOf.Kind() == reflect.Struct {
break
}
valueOf = valueOf.Elem()
}
ret, err := subWriter(value)
return ret, err
}
func UpdateFromJson(writer Writer, linkName string, jsonData []byte, unmarshalFunc func([]byte, any) error) error {
typ, ok := writer.LinkTyp(linkName)
if !ok {
return errors.New("can not got type by " + linkName)
}
instance := reflect.New(typ).Interface()
err := unmarshalFunc(jsonData, &instance)
if err != nil {
return err
}
return writer.LinkSet(linkName, reflect.Indirect(reflect.ValueOf(instance)))
}