blob: bb68d7bdca67fc291508628a25fa1b0b6eaf9daa [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001//+build !go1.12
2
3package dynamic
4
5import (
6 "github.com/jhump/protoreflect/desc"
7 "reflect"
8)
9
10// Pre-Go-1.12, we must use reflect.Value.MapKeys to reflectively
11// iterate a map. (We can be more efficient in Go 1.12 and up...)
12
13func mapsEqual(a, b reflect.Value) bool {
14 if a.Len() != b.Len() {
15 return false
16 }
17 if a.Len() == 0 && b.Len() == 0 {
18 // Optimize the case where maps are frequently empty because MapKeys()
19 // function allocates heavily.
20 return true
21 }
22
23 for _, k := range a.MapKeys() {
24 av := a.MapIndex(k)
25 bv := b.MapIndex(k)
26 if !bv.IsValid() {
27 return false
28 }
29 if !fieldsEqual(av.Interface(), bv.Interface()) {
30 return false
31 }
32 }
33 return true
34}
35
36func validFieldValueForMapField(fd *desc.FieldDescriptor, val reflect.Value) (interface{}, error) {
37 // make a defensive copy while we check the contents
38 // (also converts to map[interface{}]interface{} if it's some other type)
39 keyField := fd.GetMessageType().GetFields()[0]
40 valField := fd.GetMessageType().GetFields()[1]
41 m := map[interface{}]interface{}{}
42 for _, k := range val.MapKeys() {
43 if k.Kind() == reflect.Interface {
44 // unwrap it
45 k = reflect.ValueOf(k.Interface())
46 }
47 kk, err := validFieldValueForRv(keyField, k)
48 if err != nil {
49 return nil, err
50 }
51 v := val.MapIndex(k)
52 if v.Kind() == reflect.Interface {
53 // unwrap it
54 v = reflect.ValueOf(v.Interface())
55 }
56 vv, err := validFieldValueForRv(valField, v)
57 if err != nil {
58 return nil, err
59 }
60 m[kk] = vv
61 }
62 return m, nil
63}
64
65func canConvertMap(src reflect.Value, target reflect.Type) bool {
66 kt := target.Key()
67 vt := target.Elem()
68 for _, k := range src.MapKeys() {
69 if !canConvert(k, kt) {
70 return false
71 }
72 if !canConvert(src.MapIndex(k), vt) {
73 return false
74 }
75 }
76 return true
77}
78
79func mergeMapVal(src, target reflect.Value, targetType reflect.Type) error {
80 tkt := targetType.Key()
81 tvt := targetType.Elem()
82 for _, k := range src.MapKeys() {
83 v := src.MapIndex(k)
84 skt := k.Type()
85 svt := v.Type()
86 var nk, nv reflect.Value
87 if tkt == skt {
88 nk = k
89 } else if tkt.Kind() == reflect.Ptr && tkt.Elem() == skt {
90 nk = k.Addr()
91 } else {
92 nk = reflect.New(tkt).Elem()
93 if err := mergeVal(k, nk); err != nil {
94 return err
95 }
96 }
97 if tvt == svt {
98 nv = v
99 } else if tvt.Kind() == reflect.Ptr && tvt.Elem() == svt {
100 nv = v.Addr()
101 } else {
102 nv = reflect.New(tvt).Elem()
103 if err := mergeVal(v, nv); err != nil {
104 return err
105 }
106 }
107 if target.IsNil() {
108 target.Set(reflect.MakeMap(targetType))
109 }
110 target.SetMapIndex(nk, nv)
111 }
112 return nil
113}
114
115func mergeMapField(m *Message, fd *desc.FieldDescriptor, rv reflect.Value) error {
116 for _, k := range rv.MapKeys() {
117 if k.Kind() == reflect.Interface && !k.IsNil() {
118 k = k.Elem()
119 }
120 v := rv.MapIndex(k)
121 if v.Kind() == reflect.Interface && !v.IsNil() {
122 v = v.Elem()
123 }
124 if err := m.putMapField(fd, k.Interface(), v.Interface()); err != nil {
125 return err
126 }
127 }
128 return nil
129}