blob: f5ffd674d4f8a670b4f0f49b27c22054ead35eb8 [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// With Go 1.12 and above, we can use reflect.Value.MapRange to iterate
11// over maps more efficiently than using reflect.Value.MapKeys.
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
19 return true
20 }
21
22 iter := a.MapRange()
23 for iter.Next() {
24 k := iter.Key()
25 av := iter.Value()
26 bv := b.MapIndex(k)
27 if !bv.IsValid() {
28 return false
29 }
30 if !fieldsEqual(av.Interface(), bv.Interface()) {
31 return false
32 }
33 }
34 return true
35}
36
37func validFieldValueForMapField(fd *desc.FieldDescriptor, val reflect.Value) (interface{}, error) {
38 // make a defensive copy while we check the contents
39 // (also converts to map[interface{}]interface{} if it's some other type)
40 keyField := fd.GetMessageType().GetFields()[0]
41 valField := fd.GetMessageType().GetFields()[1]
42 m := map[interface{}]interface{}{}
43 iter := val.MapRange()
44 for iter.Next() {
45 k := iter.Key()
46 if k.Kind() == reflect.Interface {
47 // unwrap it
48 k = reflect.ValueOf(k.Interface())
49 }
50 kk, err := validFieldValueForRv(keyField, k)
51 if err != nil {
52 return nil, err
53 }
54 v := iter.Value()
55 if v.Kind() == reflect.Interface {
56 // unwrap it
57 v = reflect.ValueOf(v.Interface())
58 }
59 vv, err := validFieldValueForRv(valField, v)
60 if err != nil {
61 return nil, err
62 }
63 m[kk] = vv
64 }
65 return m, nil
66}
67
68func canConvertMap(src reflect.Value, target reflect.Type) bool {
69 kt := target.Key()
70 vt := target.Elem()
71 iter := src.MapRange()
72 for iter.Next() {
73 if !canConvert(iter.Key(), kt) {
74 return false
75 }
76 if !canConvert(iter.Value(), vt) {
77 return false
78 }
79 }
80 return true
81}
82
83func mergeMapVal(src, target reflect.Value, targetType reflect.Type) error {
84 tkt := targetType.Key()
85 tvt := targetType.Elem()
86 iter := src.MapRange()
87 for iter.Next() {
88 k := iter.Key()
89 v := iter.Value()
90 skt := k.Type()
91 svt := v.Type()
92 var nk, nv reflect.Value
93 if tkt == skt {
94 nk = k
95 } else if tkt.Kind() == reflect.Ptr && tkt.Elem() == skt {
96 nk = k.Addr()
97 } else {
98 nk = reflect.New(tkt).Elem()
99 if err := mergeVal(k, nk); err != nil {
100 return err
101 }
102 }
103 if tvt == svt {
104 nv = v
105 } else if tvt.Kind() == reflect.Ptr && tvt.Elem() == svt {
106 nv = v.Addr()
107 } else {
108 nv = reflect.New(tvt).Elem()
109 if err := mergeVal(v, nv); err != nil {
110 return err
111 }
112 }
113 if target.IsNil() {
114 target.Set(reflect.MakeMap(targetType))
115 }
116 target.SetMapIndex(nk, nv)
117 }
118 return nil
119}
120
121func mergeMapField(m *Message, fd *desc.FieldDescriptor, rv reflect.Value) error {
122 iter := rv.MapRange()
123 for iter.Next() {
124 k := iter.Key()
125 v := iter.Value()
126 if k.Kind() == reflect.Interface && !k.IsNil() {
127 k = k.Elem()
128 }
129 if v.Kind() == reflect.Interface && !v.IsNil() {
130 v = v.Elem()
131 }
132 if err := m.putMapField(fd, k.Interface(), v.Interface()); err != nil {
133 return err
134 }
135 }
136 return nil
137}