//+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 }