legacy_message.go (18928B)
1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package impl 6 7 import ( 8 "fmt" 9 "reflect" 10 "strings" 11 "sync" 12 13 "google.golang.org/protobuf/internal/descopts" 14 ptag "google.golang.org/protobuf/internal/encoding/tag" 15 "google.golang.org/protobuf/internal/errors" 16 "google.golang.org/protobuf/internal/filedesc" 17 "google.golang.org/protobuf/internal/strs" 18 "google.golang.org/protobuf/reflect/protoreflect" 19 "google.golang.org/protobuf/runtime/protoiface" 20 ) 21 22 // legacyWrapMessage wraps v as a protoreflect.Message, 23 // where v must be a *struct kind and not implement the v2 API already. 24 func legacyWrapMessage(v reflect.Value) protoreflect.Message { 25 t := v.Type() 26 if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct { 27 return aberrantMessage{v: v} 28 } 29 mt := legacyLoadMessageInfo(t, "") 30 return mt.MessageOf(v.Interface()) 31 } 32 33 // legacyLoadMessageType dynamically loads a protoreflect.Type for t, 34 // where t must be not implement the v2 API already. 35 // The provided name is used if it cannot be determined from the message. 36 func legacyLoadMessageType(t reflect.Type, name protoreflect.FullName) protoreflect.MessageType { 37 if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct { 38 return aberrantMessageType{t} 39 } 40 return legacyLoadMessageInfo(t, name) 41 } 42 43 var legacyMessageTypeCache sync.Map // map[reflect.Type]*MessageInfo 44 45 // legacyLoadMessageInfo dynamically loads a *MessageInfo for t, 46 // where t must be a *struct kind and not implement the v2 API already. 47 // The provided name is used if it cannot be determined from the message. 48 func legacyLoadMessageInfo(t reflect.Type, name protoreflect.FullName) *MessageInfo { 49 // Fast-path: check if a MessageInfo is cached for this concrete type. 50 if mt, ok := legacyMessageTypeCache.Load(t); ok { 51 return mt.(*MessageInfo) 52 } 53 54 // Slow-path: derive message descriptor and initialize MessageInfo. 55 mi := &MessageInfo{ 56 Desc: legacyLoadMessageDesc(t, name), 57 GoReflectType: t, 58 } 59 60 var hasMarshal, hasUnmarshal bool 61 v := reflect.Zero(t).Interface() 62 if _, hasMarshal = v.(legacyMarshaler); hasMarshal { 63 mi.methods.Marshal = legacyMarshal 64 65 // We have no way to tell whether the type's Marshal method 66 // supports deterministic serialization or not, but this 67 // preserves the v1 implementation's behavior of always 68 // calling Marshal methods when present. 69 mi.methods.Flags |= protoiface.SupportMarshalDeterministic 70 } 71 if _, hasUnmarshal = v.(legacyUnmarshaler); hasUnmarshal { 72 mi.methods.Unmarshal = legacyUnmarshal 73 } 74 if _, hasMerge := v.(legacyMerger); hasMerge || (hasMarshal && hasUnmarshal) { 75 mi.methods.Merge = legacyMerge 76 } 77 78 if mi, ok := legacyMessageTypeCache.LoadOrStore(t, mi); ok { 79 return mi.(*MessageInfo) 80 } 81 return mi 82 } 83 84 var legacyMessageDescCache sync.Map // map[reflect.Type]protoreflect.MessageDescriptor 85 86 // LegacyLoadMessageDesc returns an MessageDescriptor derived from the Go type, 87 // which should be a *struct kind and must not implement the v2 API already. 88 // 89 // This is exported for testing purposes. 90 func LegacyLoadMessageDesc(t reflect.Type) protoreflect.MessageDescriptor { 91 return legacyLoadMessageDesc(t, "") 92 } 93 func legacyLoadMessageDesc(t reflect.Type, name protoreflect.FullName) protoreflect.MessageDescriptor { 94 // Fast-path: check if a MessageDescriptor is cached for this concrete type. 95 if mi, ok := legacyMessageDescCache.Load(t); ok { 96 return mi.(protoreflect.MessageDescriptor) 97 } 98 99 // Slow-path: initialize MessageDescriptor from the raw descriptor. 100 mv := reflect.Zero(t).Interface() 101 if _, ok := mv.(protoreflect.ProtoMessage); ok { 102 panic(fmt.Sprintf("%v already implements proto.Message", t)) 103 } 104 mdV1, ok := mv.(messageV1) 105 if !ok { 106 return aberrantLoadMessageDesc(t, name) 107 } 108 109 // If this is a dynamic message type where there isn't a 1-1 mapping between 110 // Go and protobuf types, calling the Descriptor method on the zero value of 111 // the message type isn't likely to work. If it panics, swallow the panic and 112 // continue as if the Descriptor method wasn't present. 113 b, idxs := func() ([]byte, []int) { 114 defer func() { 115 recover() 116 }() 117 return mdV1.Descriptor() 118 }() 119 if b == nil { 120 return aberrantLoadMessageDesc(t, name) 121 } 122 123 // If the Go type has no fields, then this might be a proto3 empty message 124 // from before the size cache was added. If there are any fields, check to 125 // see that at least one of them looks like something we generated. 126 if t.Elem().Kind() == reflect.Struct { 127 if nfield := t.Elem().NumField(); nfield > 0 { 128 hasProtoField := false 129 for i := 0; i < nfield; i++ { 130 f := t.Elem().Field(i) 131 if f.Tag.Get("protobuf") != "" || f.Tag.Get("protobuf_oneof") != "" || strings.HasPrefix(f.Name, "XXX_") { 132 hasProtoField = true 133 break 134 } 135 } 136 if !hasProtoField { 137 return aberrantLoadMessageDesc(t, name) 138 } 139 } 140 } 141 142 md := legacyLoadFileDesc(b).Messages().Get(idxs[0]) 143 for _, i := range idxs[1:] { 144 md = md.Messages().Get(i) 145 } 146 if name != "" && md.FullName() != name { 147 panic(fmt.Sprintf("mismatching message name: got %v, want %v", md.FullName(), name)) 148 } 149 if md, ok := legacyMessageDescCache.LoadOrStore(t, md); ok { 150 return md.(protoreflect.MessageDescriptor) 151 } 152 return md 153 } 154 155 var ( 156 aberrantMessageDescLock sync.Mutex 157 aberrantMessageDescCache map[reflect.Type]protoreflect.MessageDescriptor 158 ) 159 160 // aberrantLoadMessageDesc returns an MessageDescriptor derived from the Go type, 161 // which must not implement protoreflect.ProtoMessage or messageV1. 162 // 163 // This is a best-effort derivation of the message descriptor using the protobuf 164 // tags on the struct fields. 165 func aberrantLoadMessageDesc(t reflect.Type, name protoreflect.FullName) protoreflect.MessageDescriptor { 166 aberrantMessageDescLock.Lock() 167 defer aberrantMessageDescLock.Unlock() 168 if aberrantMessageDescCache == nil { 169 aberrantMessageDescCache = make(map[reflect.Type]protoreflect.MessageDescriptor) 170 } 171 return aberrantLoadMessageDescReentrant(t, name) 172 } 173 func aberrantLoadMessageDescReentrant(t reflect.Type, name protoreflect.FullName) protoreflect.MessageDescriptor { 174 // Fast-path: check if an MessageDescriptor is cached for this concrete type. 175 if md, ok := aberrantMessageDescCache[t]; ok { 176 return md 177 } 178 179 // Slow-path: construct a descriptor from the Go struct type (best-effort). 180 // Cache the MessageDescriptor early on so that we can resolve internal 181 // cyclic references. 182 md := &filedesc.Message{L2: new(filedesc.MessageL2)} 183 md.L0.FullName = aberrantDeriveMessageName(t, name) 184 md.L0.ParentFile = filedesc.SurrogateProto2 185 aberrantMessageDescCache[t] = md 186 187 if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct { 188 return md 189 } 190 191 // Try to determine if the message is using proto3 by checking scalars. 192 for i := 0; i < t.Elem().NumField(); i++ { 193 f := t.Elem().Field(i) 194 if tag := f.Tag.Get("protobuf"); tag != "" { 195 switch f.Type.Kind() { 196 case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String: 197 md.L0.ParentFile = filedesc.SurrogateProto3 198 } 199 for _, s := range strings.Split(tag, ",") { 200 if s == "proto3" { 201 md.L0.ParentFile = filedesc.SurrogateProto3 202 } 203 } 204 } 205 } 206 207 // Obtain a list of oneof wrapper types. 208 var oneofWrappers []reflect.Type 209 for _, method := range []string{"XXX_OneofFuncs", "XXX_OneofWrappers"} { 210 if fn, ok := t.MethodByName(method); ok { 211 for _, v := range fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))}) { 212 if vs, ok := v.Interface().([]interface{}); ok { 213 for _, v := range vs { 214 oneofWrappers = append(oneofWrappers, reflect.TypeOf(v)) 215 } 216 } 217 } 218 } 219 } 220 221 // Obtain a list of the extension ranges. 222 if fn, ok := t.MethodByName("ExtensionRangeArray"); ok { 223 vs := fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0] 224 for i := 0; i < vs.Len(); i++ { 225 v := vs.Index(i) 226 md.L2.ExtensionRanges.List = append(md.L2.ExtensionRanges.List, [2]protoreflect.FieldNumber{ 227 protoreflect.FieldNumber(v.FieldByName("Start").Int()), 228 protoreflect.FieldNumber(v.FieldByName("End").Int() + 1), 229 }) 230 md.L2.ExtensionRangeOptions = append(md.L2.ExtensionRangeOptions, nil) 231 } 232 } 233 234 // Derive the message fields by inspecting the struct fields. 235 for i := 0; i < t.Elem().NumField(); i++ { 236 f := t.Elem().Field(i) 237 if tag := f.Tag.Get("protobuf"); tag != "" { 238 tagKey := f.Tag.Get("protobuf_key") 239 tagVal := f.Tag.Get("protobuf_val") 240 aberrantAppendField(md, f.Type, tag, tagKey, tagVal) 241 } 242 if tag := f.Tag.Get("protobuf_oneof"); tag != "" { 243 n := len(md.L2.Oneofs.List) 244 md.L2.Oneofs.List = append(md.L2.Oneofs.List, filedesc.Oneof{}) 245 od := &md.L2.Oneofs.List[n] 246 od.L0.FullName = md.FullName().Append(protoreflect.Name(tag)) 247 od.L0.ParentFile = md.L0.ParentFile 248 od.L0.Parent = md 249 od.L0.Index = n 250 251 for _, t := range oneofWrappers { 252 if t.Implements(f.Type) { 253 f := t.Elem().Field(0) 254 if tag := f.Tag.Get("protobuf"); tag != "" { 255 aberrantAppendField(md, f.Type, tag, "", "") 256 fd := &md.L2.Fields.List[len(md.L2.Fields.List)-1] 257 fd.L1.ContainingOneof = od 258 od.L1.Fields.List = append(od.L1.Fields.List, fd) 259 } 260 } 261 } 262 } 263 } 264 265 return md 266 } 267 268 func aberrantDeriveMessageName(t reflect.Type, name protoreflect.FullName) protoreflect.FullName { 269 if name.IsValid() { 270 return name 271 } 272 func() { 273 defer func() { recover() }() // swallow possible nil panics 274 if m, ok := reflect.Zero(t).Interface().(interface{ XXX_MessageName() string }); ok { 275 name = protoreflect.FullName(m.XXX_MessageName()) 276 } 277 }() 278 if name.IsValid() { 279 return name 280 } 281 if t.Kind() == reflect.Ptr { 282 t = t.Elem() 283 } 284 return AberrantDeriveFullName(t) 285 } 286 287 func aberrantAppendField(md *filedesc.Message, goType reflect.Type, tag, tagKey, tagVal string) { 288 t := goType 289 isOptional := t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct 290 isRepeated := t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 291 if isOptional || isRepeated { 292 t = t.Elem() 293 } 294 fd := ptag.Unmarshal(tag, t, placeholderEnumValues{}).(*filedesc.Field) 295 296 // Append field descriptor to the message. 297 n := len(md.L2.Fields.List) 298 md.L2.Fields.List = append(md.L2.Fields.List, *fd) 299 fd = &md.L2.Fields.List[n] 300 fd.L0.FullName = md.FullName().Append(fd.Name()) 301 fd.L0.ParentFile = md.L0.ParentFile 302 fd.L0.Parent = md 303 fd.L0.Index = n 304 305 if fd.L1.IsWeak || fd.L1.HasPacked { 306 fd.L1.Options = func() protoreflect.ProtoMessage { 307 opts := descopts.Field.ProtoReflect().New() 308 if fd.L1.IsWeak { 309 opts.Set(opts.Descriptor().Fields().ByName("weak"), protoreflect.ValueOfBool(true)) 310 } 311 if fd.L1.HasPacked { 312 opts.Set(opts.Descriptor().Fields().ByName("packed"), protoreflect.ValueOfBool(fd.L1.IsPacked)) 313 } 314 return opts.Interface() 315 } 316 } 317 318 // Populate Enum and Message. 319 if fd.Enum() == nil && fd.Kind() == protoreflect.EnumKind { 320 switch v := reflect.Zero(t).Interface().(type) { 321 case protoreflect.Enum: 322 fd.L1.Enum = v.Descriptor() 323 default: 324 fd.L1.Enum = LegacyLoadEnumDesc(t) 325 } 326 } 327 if fd.Message() == nil && (fd.Kind() == protoreflect.MessageKind || fd.Kind() == protoreflect.GroupKind) { 328 switch v := reflect.Zero(t).Interface().(type) { 329 case protoreflect.ProtoMessage: 330 fd.L1.Message = v.ProtoReflect().Descriptor() 331 case messageV1: 332 fd.L1.Message = LegacyLoadMessageDesc(t) 333 default: 334 if t.Kind() == reflect.Map { 335 n := len(md.L1.Messages.List) 336 md.L1.Messages.List = append(md.L1.Messages.List, filedesc.Message{L2: new(filedesc.MessageL2)}) 337 md2 := &md.L1.Messages.List[n] 338 md2.L0.FullName = md.FullName().Append(protoreflect.Name(strs.MapEntryName(string(fd.Name())))) 339 md2.L0.ParentFile = md.L0.ParentFile 340 md2.L0.Parent = md 341 md2.L0.Index = n 342 343 md2.L1.IsMapEntry = true 344 md2.L2.Options = func() protoreflect.ProtoMessage { 345 opts := descopts.Message.ProtoReflect().New() 346 opts.Set(opts.Descriptor().Fields().ByName("map_entry"), protoreflect.ValueOfBool(true)) 347 return opts.Interface() 348 } 349 350 aberrantAppendField(md2, t.Key(), tagKey, "", "") 351 aberrantAppendField(md2, t.Elem(), tagVal, "", "") 352 353 fd.L1.Message = md2 354 break 355 } 356 fd.L1.Message = aberrantLoadMessageDescReentrant(t, "") 357 } 358 } 359 } 360 361 type placeholderEnumValues struct { 362 protoreflect.EnumValueDescriptors 363 } 364 365 func (placeholderEnumValues) ByNumber(n protoreflect.EnumNumber) protoreflect.EnumValueDescriptor { 366 return filedesc.PlaceholderEnumValue(protoreflect.FullName(fmt.Sprintf("UNKNOWN_%d", n))) 367 } 368 369 // legacyMarshaler is the proto.Marshaler interface superseded by protoiface.Methoder. 370 type legacyMarshaler interface { 371 Marshal() ([]byte, error) 372 } 373 374 // legacyUnmarshaler is the proto.Unmarshaler interface superseded by protoiface.Methoder. 375 type legacyUnmarshaler interface { 376 Unmarshal([]byte) error 377 } 378 379 // legacyMerger is the proto.Merger interface superseded by protoiface.Methoder. 380 type legacyMerger interface { 381 Merge(protoiface.MessageV1) 382 } 383 384 var aberrantProtoMethods = &protoiface.Methods{ 385 Marshal: legacyMarshal, 386 Unmarshal: legacyUnmarshal, 387 Merge: legacyMerge, 388 389 // We have no way to tell whether the type's Marshal method 390 // supports deterministic serialization or not, but this 391 // preserves the v1 implementation's behavior of always 392 // calling Marshal methods when present. 393 Flags: protoiface.SupportMarshalDeterministic, 394 } 395 396 func legacyMarshal(in protoiface.MarshalInput) (protoiface.MarshalOutput, error) { 397 v := in.Message.(unwrapper).protoUnwrap() 398 marshaler, ok := v.(legacyMarshaler) 399 if !ok { 400 return protoiface.MarshalOutput{}, errors.New("%T does not implement Marshal", v) 401 } 402 out, err := marshaler.Marshal() 403 if in.Buf != nil { 404 out = append(in.Buf, out...) 405 } 406 return protoiface.MarshalOutput{ 407 Buf: out, 408 }, err 409 } 410 411 func legacyUnmarshal(in protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { 412 v := in.Message.(unwrapper).protoUnwrap() 413 unmarshaler, ok := v.(legacyUnmarshaler) 414 if !ok { 415 return protoiface.UnmarshalOutput{}, errors.New("%T does not implement Unmarshal", v) 416 } 417 return protoiface.UnmarshalOutput{}, unmarshaler.Unmarshal(in.Buf) 418 } 419 420 func legacyMerge(in protoiface.MergeInput) protoiface.MergeOutput { 421 // Check whether this supports the legacy merger. 422 dstv := in.Destination.(unwrapper).protoUnwrap() 423 merger, ok := dstv.(legacyMerger) 424 if ok { 425 merger.Merge(Export{}.ProtoMessageV1Of(in.Source)) 426 return protoiface.MergeOutput{Flags: protoiface.MergeComplete} 427 } 428 429 // If legacy merger is unavailable, implement merge in terms of 430 // a marshal and unmarshal operation. 431 srcv := in.Source.(unwrapper).protoUnwrap() 432 marshaler, ok := srcv.(legacyMarshaler) 433 if !ok { 434 return protoiface.MergeOutput{} 435 } 436 dstv = in.Destination.(unwrapper).protoUnwrap() 437 unmarshaler, ok := dstv.(legacyUnmarshaler) 438 if !ok { 439 return protoiface.MergeOutput{} 440 } 441 if !in.Source.IsValid() { 442 // Legacy Marshal methods may not function on nil messages. 443 // Check for a typed nil source only after we confirm that 444 // legacy Marshal/Unmarshal methods are present, for 445 // consistency. 446 return protoiface.MergeOutput{Flags: protoiface.MergeComplete} 447 } 448 b, err := marshaler.Marshal() 449 if err != nil { 450 return protoiface.MergeOutput{} 451 } 452 err = unmarshaler.Unmarshal(b) 453 if err != nil { 454 return protoiface.MergeOutput{} 455 } 456 return protoiface.MergeOutput{Flags: protoiface.MergeComplete} 457 } 458 459 // aberrantMessageType implements MessageType for all types other than pointer-to-struct. 460 type aberrantMessageType struct { 461 t reflect.Type 462 } 463 464 func (mt aberrantMessageType) New() protoreflect.Message { 465 if mt.t.Kind() == reflect.Ptr { 466 return aberrantMessage{reflect.New(mt.t.Elem())} 467 } 468 return aberrantMessage{reflect.Zero(mt.t)} 469 } 470 func (mt aberrantMessageType) Zero() protoreflect.Message { 471 return aberrantMessage{reflect.Zero(mt.t)} 472 } 473 func (mt aberrantMessageType) GoType() reflect.Type { 474 return mt.t 475 } 476 func (mt aberrantMessageType) Descriptor() protoreflect.MessageDescriptor { 477 return LegacyLoadMessageDesc(mt.t) 478 } 479 480 // aberrantMessage implements Message for all types other than pointer-to-struct. 481 // 482 // When the underlying type implements legacyMarshaler or legacyUnmarshaler, 483 // the aberrant Message can be marshaled or unmarshaled. Otherwise, there is 484 // not much that can be done with values of this type. 485 type aberrantMessage struct { 486 v reflect.Value 487 } 488 489 // Reset implements the v1 proto.Message.Reset method. 490 func (m aberrantMessage) Reset() { 491 if mr, ok := m.v.Interface().(interface{ Reset() }); ok { 492 mr.Reset() 493 return 494 } 495 if m.v.Kind() == reflect.Ptr && !m.v.IsNil() { 496 m.v.Elem().Set(reflect.Zero(m.v.Type().Elem())) 497 } 498 } 499 500 func (m aberrantMessage) ProtoReflect() protoreflect.Message { 501 return m 502 } 503 504 func (m aberrantMessage) Descriptor() protoreflect.MessageDescriptor { 505 return LegacyLoadMessageDesc(m.v.Type()) 506 } 507 func (m aberrantMessage) Type() protoreflect.MessageType { 508 return aberrantMessageType{m.v.Type()} 509 } 510 func (m aberrantMessage) New() protoreflect.Message { 511 if m.v.Type().Kind() == reflect.Ptr { 512 return aberrantMessage{reflect.New(m.v.Type().Elem())} 513 } 514 return aberrantMessage{reflect.Zero(m.v.Type())} 515 } 516 func (m aberrantMessage) Interface() protoreflect.ProtoMessage { 517 return m 518 } 519 func (m aberrantMessage) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { 520 return 521 } 522 func (m aberrantMessage) Has(protoreflect.FieldDescriptor) bool { 523 return false 524 } 525 func (m aberrantMessage) Clear(protoreflect.FieldDescriptor) { 526 panic("invalid Message.Clear on " + string(m.Descriptor().FullName())) 527 } 528 func (m aberrantMessage) Get(fd protoreflect.FieldDescriptor) protoreflect.Value { 529 if fd.Default().IsValid() { 530 return fd.Default() 531 } 532 panic("invalid Message.Get on " + string(m.Descriptor().FullName())) 533 } 534 func (m aberrantMessage) Set(protoreflect.FieldDescriptor, protoreflect.Value) { 535 panic("invalid Message.Set on " + string(m.Descriptor().FullName())) 536 } 537 func (m aberrantMessage) Mutable(protoreflect.FieldDescriptor) protoreflect.Value { 538 panic("invalid Message.Mutable on " + string(m.Descriptor().FullName())) 539 } 540 func (m aberrantMessage) NewField(protoreflect.FieldDescriptor) protoreflect.Value { 541 panic("invalid Message.NewField on " + string(m.Descriptor().FullName())) 542 } 543 func (m aberrantMessage) WhichOneof(protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { 544 panic("invalid Message.WhichOneof descriptor on " + string(m.Descriptor().FullName())) 545 } 546 func (m aberrantMessage) GetUnknown() protoreflect.RawFields { 547 return nil 548 } 549 func (m aberrantMessage) SetUnknown(protoreflect.RawFields) { 550 // SetUnknown discards its input on messages which don't support unknown field storage. 551 } 552 func (m aberrantMessage) IsValid() bool { 553 if m.v.Kind() == reflect.Ptr { 554 return !m.v.IsNil() 555 } 556 return false 557 } 558 func (m aberrantMessage) ProtoMethods() *protoiface.Methods { 559 return aberrantProtoMethods 560 } 561 func (m aberrantMessage) protoUnwrap() interface{} { 562 return m.v.Interface() 563 }