desc_init.go raw

   1  // Copyright 2019 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 protodesc
   6  
   7  import (
   8  	"google.golang.org/protobuf/internal/errors"
   9  	"google.golang.org/protobuf/internal/filedesc"
  10  	"google.golang.org/protobuf/internal/strs"
  11  	"google.golang.org/protobuf/proto"
  12  	"google.golang.org/protobuf/reflect/protoreflect"
  13  
  14  	"google.golang.org/protobuf/types/descriptorpb"
  15  )
  16  
  17  type descsByName map[protoreflect.FullName]protoreflect.Descriptor
  18  
  19  func (r descsByName) initEnumDeclarations(eds []*descriptorpb.EnumDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (es []filedesc.Enum, err error) {
  20  	es = make([]filedesc.Enum, len(eds)) // allocate up-front to ensure stable pointers
  21  	for i, ed := range eds {
  22  		e := &es[i]
  23  		e.L2 = new(filedesc.EnumL2)
  24  		if e.L0, err = r.makeBase(e, parent, ed.GetName(), i, sb); err != nil {
  25  			return nil, err
  26  		}
  27  		if opts := ed.GetOptions(); opts != nil {
  28  			opts = proto.Clone(opts).(*descriptorpb.EnumOptions)
  29  			e.L2.Options = func() protoreflect.ProtoMessage { return opts }
  30  		}
  31  		e.L1.EditionFeatures = mergeEditionFeatures(parent, ed.GetOptions().GetFeatures())
  32  		e.L1.Visibility = int32(ed.GetVisibility())
  33  		for _, s := range ed.GetReservedName() {
  34  			e.L2.ReservedNames.List = append(e.L2.ReservedNames.List, protoreflect.Name(s))
  35  		}
  36  		for _, rr := range ed.GetReservedRange() {
  37  			e.L2.ReservedRanges.List = append(e.L2.ReservedRanges.List, [2]protoreflect.EnumNumber{
  38  				protoreflect.EnumNumber(rr.GetStart()),
  39  				protoreflect.EnumNumber(rr.GetEnd()),
  40  			})
  41  		}
  42  		if e.L2.Values.List, err = r.initEnumValuesFromDescriptorProto(ed.GetValue(), e, sb); err != nil {
  43  			return nil, err
  44  		}
  45  	}
  46  	return es, nil
  47  }
  48  
  49  func (r descsByName) initEnumValuesFromDescriptorProto(vds []*descriptorpb.EnumValueDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (vs []filedesc.EnumValue, err error) {
  50  	vs = make([]filedesc.EnumValue, len(vds)) // allocate up-front to ensure stable pointers
  51  	for i, vd := range vds {
  52  		v := &vs[i]
  53  		if v.L0, err = r.makeBase(v, parent, vd.GetName(), i, sb); err != nil {
  54  			return nil, err
  55  		}
  56  		if opts := vd.GetOptions(); opts != nil {
  57  			opts = proto.Clone(opts).(*descriptorpb.EnumValueOptions)
  58  			v.L1.Options = func() protoreflect.ProtoMessage { return opts }
  59  		}
  60  		v.L1.Number = protoreflect.EnumNumber(vd.GetNumber())
  61  	}
  62  	return vs, nil
  63  }
  64  
  65  func (r descsByName) initMessagesDeclarations(mds []*descriptorpb.DescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (ms []filedesc.Message, err error) {
  66  	ms = make([]filedesc.Message, len(mds)) // allocate up-front to ensure stable pointers
  67  	for i, md := range mds {
  68  		m := &ms[i]
  69  		m.L2 = new(filedesc.MessageL2)
  70  		if m.L0, err = r.makeBase(m, parent, md.GetName(), i, sb); err != nil {
  71  			return nil, err
  72  		}
  73  		m.L1.EditionFeatures = mergeEditionFeatures(parent, md.GetOptions().GetFeatures())
  74  		m.L1.Visibility = int32(md.GetVisibility())
  75  		if opts := md.GetOptions(); opts != nil {
  76  			opts = proto.Clone(opts).(*descriptorpb.MessageOptions)
  77  			m.L2.Options = func() protoreflect.ProtoMessage { return opts }
  78  			m.L1.IsMapEntry = opts.GetMapEntry()
  79  			m.L1.IsMessageSet = opts.GetMessageSetWireFormat()
  80  		}
  81  		for _, s := range md.GetReservedName() {
  82  			m.L2.ReservedNames.List = append(m.L2.ReservedNames.List, protoreflect.Name(s))
  83  		}
  84  		for _, rr := range md.GetReservedRange() {
  85  			m.L2.ReservedRanges.List = append(m.L2.ReservedRanges.List, [2]protoreflect.FieldNumber{
  86  				protoreflect.FieldNumber(rr.GetStart()),
  87  				protoreflect.FieldNumber(rr.GetEnd()),
  88  			})
  89  		}
  90  		for _, xr := range md.GetExtensionRange() {
  91  			m.L2.ExtensionRanges.List = append(m.L2.ExtensionRanges.List, [2]protoreflect.FieldNumber{
  92  				protoreflect.FieldNumber(xr.GetStart()),
  93  				protoreflect.FieldNumber(xr.GetEnd()),
  94  			})
  95  			var optsFunc func() protoreflect.ProtoMessage
  96  			if opts := xr.GetOptions(); opts != nil {
  97  				opts = proto.Clone(opts).(*descriptorpb.ExtensionRangeOptions)
  98  				optsFunc = func() protoreflect.ProtoMessage { return opts }
  99  			}
 100  			m.L2.ExtensionRangeOptions = append(m.L2.ExtensionRangeOptions, optsFunc)
 101  		}
 102  		if m.L2.Fields.List, err = r.initFieldsFromDescriptorProto(md.GetField(), m, sb); err != nil {
 103  			return nil, err
 104  		}
 105  		if m.L2.Oneofs.List, err = r.initOneofsFromDescriptorProto(md.GetOneofDecl(), m, sb); err != nil {
 106  			return nil, err
 107  		}
 108  		if m.L1.Enums.List, err = r.initEnumDeclarations(md.GetEnumType(), m, sb); err != nil {
 109  			return nil, err
 110  		}
 111  		if m.L1.Messages.List, err = r.initMessagesDeclarations(md.GetNestedType(), m, sb); err != nil {
 112  			return nil, err
 113  		}
 114  		if m.L1.Extensions.List, err = r.initExtensionDeclarations(md.GetExtension(), m, sb); err != nil {
 115  			return nil, err
 116  		}
 117  	}
 118  	return ms, nil
 119  }
 120  
 121  // canBePacked returns whether the field can use packed encoding:
 122  // https://protobuf.dev/programming-guides/encoding/#packed
 123  func canBePacked(fd *descriptorpb.FieldDescriptorProto) bool {
 124  	if fd.GetLabel() != descriptorpb.FieldDescriptorProto_LABEL_REPEATED {
 125  		return false // not a repeated field
 126  	}
 127  
 128  	switch protoreflect.Kind(fd.GetType()) {
 129  	case protoreflect.MessageKind, protoreflect.GroupKind:
 130  		return false // not a scalar type field
 131  
 132  	case protoreflect.StringKind, protoreflect.BytesKind:
 133  		// string and bytes can explicitly not be declared as packed,
 134  		// see https://protobuf.dev/programming-guides/encoding/#packed
 135  		return false
 136  
 137  	default:
 138  		return true
 139  	}
 140  }
 141  
 142  func (r descsByName) initFieldsFromDescriptorProto(fds []*descriptorpb.FieldDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (fs []filedesc.Field, err error) {
 143  	fs = make([]filedesc.Field, len(fds)) // allocate up-front to ensure stable pointers
 144  	for i, fd := range fds {
 145  		f := &fs[i]
 146  		if f.L0, err = r.makeBase(f, parent, fd.GetName(), i, sb); err != nil {
 147  			return nil, err
 148  		}
 149  		f.L1.EditionFeatures = mergeEditionFeatures(parent, fd.GetOptions().GetFeatures())
 150  		f.L1.IsProto3Optional = fd.GetProto3Optional()
 151  		if opts := fd.GetOptions(); opts != nil {
 152  			opts = proto.Clone(opts).(*descriptorpb.FieldOptions)
 153  			f.L1.Options = func() protoreflect.ProtoMessage { return opts }
 154  			f.L1.IsLazy = opts.GetLazy()
 155  			if opts.Packed != nil {
 156  				f.L1.EditionFeatures.IsPacked = opts.GetPacked()
 157  			}
 158  		}
 159  		f.L1.Number = protoreflect.FieldNumber(fd.GetNumber())
 160  		f.L1.Cardinality = protoreflect.Cardinality(fd.GetLabel())
 161  		if fd.Type != nil {
 162  			f.L1.Kind = protoreflect.Kind(fd.GetType())
 163  		}
 164  		if fd.JsonName != nil {
 165  			f.L1.StringName.InitJSON(fd.GetJsonName())
 166  		}
 167  
 168  		if f.L1.EditionFeatures.IsLegacyRequired {
 169  			f.L1.Cardinality = protoreflect.Required
 170  		}
 171  
 172  		if f.L1.Kind == protoreflect.MessageKind && f.L1.EditionFeatures.IsDelimitedEncoded {
 173  			f.L1.Kind = protoreflect.GroupKind
 174  		}
 175  	}
 176  	return fs, nil
 177  }
 178  
 179  func (r descsByName) initOneofsFromDescriptorProto(ods []*descriptorpb.OneofDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (os []filedesc.Oneof, err error) {
 180  	os = make([]filedesc.Oneof, len(ods)) // allocate up-front to ensure stable pointers
 181  	for i, od := range ods {
 182  		o := &os[i]
 183  		if o.L0, err = r.makeBase(o, parent, od.GetName(), i, sb); err != nil {
 184  			return nil, err
 185  		}
 186  		o.L1.EditionFeatures = mergeEditionFeatures(parent, od.GetOptions().GetFeatures())
 187  		if opts := od.GetOptions(); opts != nil {
 188  			opts = proto.Clone(opts).(*descriptorpb.OneofOptions)
 189  			o.L1.Options = func() protoreflect.ProtoMessage { return opts }
 190  		}
 191  	}
 192  	return os, nil
 193  }
 194  
 195  func (r descsByName) initExtensionDeclarations(xds []*descriptorpb.FieldDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (xs []filedesc.Extension, err error) {
 196  	xs = make([]filedesc.Extension, len(xds)) // allocate up-front to ensure stable pointers
 197  	for i, xd := range xds {
 198  		x := &xs[i]
 199  		x.L2 = new(filedesc.ExtensionL2)
 200  		if x.L0, err = r.makeBase(x, parent, xd.GetName(), i, sb); err != nil {
 201  			return nil, err
 202  		}
 203  		x.L1.EditionFeatures = mergeEditionFeatures(parent, xd.GetOptions().GetFeatures())
 204  		if opts := xd.GetOptions(); opts != nil {
 205  			opts = proto.Clone(opts).(*descriptorpb.FieldOptions)
 206  			x.L2.Options = func() protoreflect.ProtoMessage { return opts }
 207  			if opts.Packed != nil {
 208  				x.L1.EditionFeatures.IsPacked = opts.GetPacked()
 209  			}
 210  		}
 211  		x.L1.Number = protoreflect.FieldNumber(xd.GetNumber())
 212  		x.L1.Cardinality = protoreflect.Cardinality(xd.GetLabel())
 213  		if xd.Type != nil {
 214  			x.L1.Kind = protoreflect.Kind(xd.GetType())
 215  		}
 216  		if xd.JsonName != nil {
 217  			x.L2.StringName.InitJSON(xd.GetJsonName())
 218  		}
 219  		if x.L1.Kind == protoreflect.MessageKind && x.L1.EditionFeatures.IsDelimitedEncoded {
 220  			x.L1.Kind = protoreflect.GroupKind
 221  		}
 222  	}
 223  	return xs, nil
 224  }
 225  
 226  func (r descsByName) initServiceDeclarations(sds []*descriptorpb.ServiceDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (ss []filedesc.Service, err error) {
 227  	ss = make([]filedesc.Service, len(sds)) // allocate up-front to ensure stable pointers
 228  	for i, sd := range sds {
 229  		s := &ss[i]
 230  		s.L2 = new(filedesc.ServiceL2)
 231  		if s.L0, err = r.makeBase(s, parent, sd.GetName(), i, sb); err != nil {
 232  			return nil, err
 233  		}
 234  		if opts := sd.GetOptions(); opts != nil {
 235  			opts = proto.Clone(opts).(*descriptorpb.ServiceOptions)
 236  			s.L2.Options = func() protoreflect.ProtoMessage { return opts }
 237  		}
 238  		if s.L2.Methods.List, err = r.initMethodsFromDescriptorProto(sd.GetMethod(), s, sb); err != nil {
 239  			return nil, err
 240  		}
 241  	}
 242  	return ss, nil
 243  }
 244  
 245  func (r descsByName) initMethodsFromDescriptorProto(mds []*descriptorpb.MethodDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (ms []filedesc.Method, err error) {
 246  	ms = make([]filedesc.Method, len(mds)) // allocate up-front to ensure stable pointers
 247  	for i, md := range mds {
 248  		m := &ms[i]
 249  		if m.L0, err = r.makeBase(m, parent, md.GetName(), i, sb); err != nil {
 250  			return nil, err
 251  		}
 252  		if opts := md.GetOptions(); opts != nil {
 253  			opts = proto.Clone(opts).(*descriptorpb.MethodOptions)
 254  			m.L1.Options = func() protoreflect.ProtoMessage { return opts }
 255  		}
 256  		m.L1.IsStreamingClient = md.GetClientStreaming()
 257  		m.L1.IsStreamingServer = md.GetServerStreaming()
 258  	}
 259  	return ms, nil
 260  }
 261  
 262  func (r descsByName) makeBase(child, parent protoreflect.Descriptor, name string, idx int, sb *strs.Builder) (filedesc.BaseL0, error) {
 263  	if !protoreflect.Name(name).IsValid() {
 264  		return filedesc.BaseL0{}, errors.New("descriptor %q has an invalid nested name: %q", parent.FullName(), name)
 265  	}
 266  
 267  	// Derive the full name of the child.
 268  	// Note that enum values are a sibling to the enum parent in the namespace.
 269  	var fullName protoreflect.FullName
 270  	if _, ok := parent.(protoreflect.EnumDescriptor); ok {
 271  		fullName = sb.AppendFullName(parent.FullName().Parent(), protoreflect.Name(name))
 272  	} else {
 273  		fullName = sb.AppendFullName(parent.FullName(), protoreflect.Name(name))
 274  	}
 275  	if _, ok := r[fullName]; ok {
 276  		return filedesc.BaseL0{}, errors.New("descriptor %q already declared", fullName)
 277  	}
 278  	r[fullName] = child
 279  
 280  	// TODO: Verify that the full name does not already exist in the resolver?
 281  	// This is not as critical since most usages of NewFile will register
 282  	// the created file back into the registry, which will perform this check.
 283  
 284  	return filedesc.BaseL0{
 285  		FullName:   fullName,
 286  		ParentFile: parent.ParentFile().(*filedesc.File),
 287  		Parent:     parent,
 288  		Index:      idx,
 289  	}, nil
 290  }
 291