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