| //go:build go1.12 |
| // +build go1.12 |
| |
| package dynamic |
| |
| import ( |
| "github.com/jhump/protoreflect/desc" |
| "reflect" |
| ) |
| |
| // With Go 1.12 and above, we can use reflect.Value.MapRange to iterate |
| // over maps more efficiently than using reflect.Value.MapKeys. |
| |
| func mapsEqual(a, b reflect.Value) bool { |
| if a.Len() != b.Len() { |
| return false |
| } |
| if a.Len() == 0 && b.Len() == 0 { |
| // Optimize the case where maps are frequently empty |
| return true |
| } |
| |
| iter := a.MapRange() |
| for iter.Next() { |
| k := iter.Key() |
| av := iter.Value() |
| bv := b.MapIndex(k) |
| if !bv.IsValid() { |
| return false |
| } |
| if !fieldsEqual(av.Interface(), bv.Interface()) { |
| return false |
| } |
| } |
| return true |
| } |
| |
| func validFieldValueForMapField(fd *desc.FieldDescriptor, val reflect.Value) (interface{}, error) { |
| // make a defensive copy while we check the contents |
| // (also converts to map[interface{}]interface{} if it's some other type) |
| keyField := fd.GetMessageType().GetFields()[0] |
| valField := fd.GetMessageType().GetFields()[1] |
| m := map[interface{}]interface{}{} |
| iter := val.MapRange() |
| for iter.Next() { |
| k := iter.Key() |
| if k.Kind() == reflect.Interface { |
| // unwrap it |
| k = reflect.ValueOf(k.Interface()) |
| } |
| kk, err := validElementFieldValueForRv(keyField, k, false) |
| if err != nil { |
| return nil, err |
| } |
| v := iter.Value() |
| if v.Kind() == reflect.Interface { |
| // unwrap it |
| v = reflect.ValueOf(v.Interface()) |
| } |
| vv, err := validElementFieldValueForRv(valField, v, true) |
| if err != nil { |
| return nil, err |
| } |
| m[kk] = vv |
| } |
| return m, nil |
| } |
| |
| func canConvertMap(src reflect.Value, target reflect.Type) bool { |
| kt := target.Key() |
| vt := target.Elem() |
| iter := src.MapRange() |
| for iter.Next() { |
| if !canConvert(iter.Key(), kt) { |
| return false |
| } |
| if !canConvert(iter.Value(), vt) { |
| return false |
| } |
| } |
| return true |
| } |
| |
| func mergeMapVal(src, target reflect.Value, targetType reflect.Type, deterministic bool) error { |
| tkt := targetType.Key() |
| tvt := targetType.Elem() |
| iter := src.MapRange() |
| for iter.Next() { |
| k := iter.Key() |
| v := iter.Value() |
| skt := k.Type() |
| svt := v.Type() |
| var nk, nv reflect.Value |
| if tkt == skt { |
| nk = k |
| } else if tkt.Kind() == reflect.Ptr && tkt.Elem() == skt { |
| nk = k.Addr() |
| } else { |
| nk = reflect.New(tkt).Elem() |
| if err := mergeVal(k, nk, deterministic); err != nil { |
| return err |
| } |
| } |
| if tvt == svt { |
| nv = v |
| } else if tvt.Kind() == reflect.Ptr && tvt.Elem() == svt { |
| nv = v.Addr() |
| } else { |
| nv = reflect.New(tvt).Elem() |
| if err := mergeVal(v, nv, deterministic); err != nil { |
| return err |
| } |
| } |
| if target.IsNil() { |
| target.Set(reflect.MakeMap(targetType)) |
| } |
| target.SetMapIndex(nk, nv) |
| } |
| return nil |
| } |
| |
| func mergeMapField(m *Message, fd *desc.FieldDescriptor, rv reflect.Value) error { |
| iter := rv.MapRange() |
| for iter.Next() { |
| k := iter.Key() |
| v := iter.Value() |
| if k.Kind() == reflect.Interface && !k.IsNil() { |
| k = k.Elem() |
| } |
| if v.Kind() == reflect.Interface && !v.IsNil() { |
| v = v.Elem() |
| } |
| if err := m.putMapField(fd, k.Interface(), v.Interface()); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |