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 filedesc
   6  
   7  import (
   8  	"fmt"
   9  	"sync"
  10  
  11  	"google.golang.org/protobuf/encoding/protowire"
  12  	"google.golang.org/protobuf/internal/genid"
  13  	"google.golang.org/protobuf/internal/strs"
  14  	"google.golang.org/protobuf/reflect/protoreflect"
  15  )
  16  
  17  // fileRaw is a data struct used when initializing a file descriptor from
  18  // a raw FileDescriptorProto.
  19  type fileRaw struct {
  20  	builder       Builder
  21  	allEnums      []Enum
  22  	allMessages   []Message
  23  	allExtensions []Extension
  24  	allServices   []Service
  25  }
  26  
  27  func newRawFile(db Builder) *File {
  28  	fd := &File{fileRaw: fileRaw{builder: db}}
  29  	fd.initDecls(db.NumEnums, db.NumMessages, db.NumExtensions, db.NumServices)
  30  	fd.unmarshalSeed(db.RawDescriptor)
  31  
  32  	// Extended message targets are eagerly resolved since registration
  33  	// needs this information at program init time.
  34  	for i := range fd.allExtensions {
  35  		xd := &fd.allExtensions[i]
  36  		xd.L1.Extendee = fd.resolveMessageDependency(xd.L1.Extendee, listExtTargets, int32(i))
  37  	}
  38  
  39  	fd.checkDecls()
  40  	return fd
  41  }
  42  
  43  // initDecls pre-allocates slices for the exact number of enums, messages
  44  // (including map entries), extensions, and services declared in the proto file.
  45  // This is done to avoid regrowing the slice, which would change the address
  46  // for any previously seen declaration.
  47  //
  48  // The alloc methods "allocates" slices by pulling from the capacity.
  49  func (fd *File) initDecls(numEnums, numMessages, numExtensions, numServices int32) {
  50  	fd.allEnums = make([]Enum, 0, numEnums)
  51  	fd.allMessages = make([]Message, 0, numMessages)
  52  	fd.allExtensions = make([]Extension, 0, numExtensions)
  53  	fd.allServices = make([]Service, 0, numServices)
  54  }
  55  
  56  func (fd *File) allocEnums(n int) []Enum {
  57  	total := len(fd.allEnums)
  58  	es := fd.allEnums[total : total+n]
  59  	fd.allEnums = fd.allEnums[:total+n]
  60  	return es
  61  }
  62  func (fd *File) allocMessages(n int) []Message {
  63  	total := len(fd.allMessages)
  64  	ms := fd.allMessages[total : total+n]
  65  	fd.allMessages = fd.allMessages[:total+n]
  66  	return ms
  67  }
  68  func (fd *File) allocExtensions(n int) []Extension {
  69  	total := len(fd.allExtensions)
  70  	xs := fd.allExtensions[total : total+n]
  71  	fd.allExtensions = fd.allExtensions[:total+n]
  72  	return xs
  73  }
  74  func (fd *File) allocServices(n int) []Service {
  75  	total := len(fd.allServices)
  76  	xs := fd.allServices[total : total+n]
  77  	fd.allServices = fd.allServices[:total+n]
  78  	return xs
  79  }
  80  
  81  // checkDecls performs a sanity check that the expected number of expected
  82  // declarations matches the number that were found in the descriptor proto.
  83  func (fd *File) checkDecls() {
  84  	switch {
  85  	case len(fd.allEnums) != cap(fd.allEnums):
  86  	case len(fd.allMessages) != cap(fd.allMessages):
  87  	case len(fd.allExtensions) != cap(fd.allExtensions):
  88  	case len(fd.allServices) != cap(fd.allServices):
  89  	default:
  90  		return
  91  	}
  92  	panic("mismatching cardinality")
  93  }
  94  
  95  func (fd *File) unmarshalSeed(b []byte) {
  96  	sb := getBuilder()
  97  	defer putBuilder(sb)
  98  
  99  	var prevField protoreflect.FieldNumber
 100  	var numEnums, numMessages, numExtensions, numServices int
 101  	var posEnums, posMessages, posExtensions, posServices int
 102  	var options []byte
 103  	b0 := b
 104  	for len(b) > 0 {
 105  		num, typ, n := protowire.ConsumeTag(b)
 106  		b = b[n:]
 107  		switch typ {
 108  		case protowire.BytesType:
 109  			v, m := protowire.ConsumeBytes(b)
 110  			b = b[m:]
 111  			switch num {
 112  			case genid.FileDescriptorProto_Syntax_field_number:
 113  				switch string(v) {
 114  				case "proto2":
 115  					fd.L1.Syntax = protoreflect.Proto2
 116  					fd.L1.Edition = EditionProto2
 117  				case "proto3":
 118  					fd.L1.Syntax = protoreflect.Proto3
 119  					fd.L1.Edition = EditionProto3
 120  				case "editions":
 121  					fd.L1.Syntax = protoreflect.Editions
 122  				default:
 123  					panic("invalid syntax")
 124  				}
 125  			case genid.FileDescriptorProto_Name_field_number:
 126  				fd.L1.Path = sb.MakeString(v)
 127  			case genid.FileDescriptorProto_Package_field_number:
 128  				fd.L1.Package = protoreflect.FullName(sb.MakeString(v))
 129  			case genid.FileDescriptorProto_Options_field_number:
 130  				options = v
 131  			case genid.FileDescriptorProto_EnumType_field_number:
 132  				if prevField != genid.FileDescriptorProto_EnumType_field_number {
 133  					if numEnums > 0 {
 134  						panic("non-contiguous repeated field")
 135  					}
 136  					posEnums = len(b0) - len(b) - n - m
 137  				}
 138  				numEnums++
 139  			case genid.FileDescriptorProto_MessageType_field_number:
 140  				if prevField != genid.FileDescriptorProto_MessageType_field_number {
 141  					if numMessages > 0 {
 142  						panic("non-contiguous repeated field")
 143  					}
 144  					posMessages = len(b0) - len(b) - n - m
 145  				}
 146  				numMessages++
 147  			case genid.FileDescriptorProto_Extension_field_number:
 148  				if prevField != genid.FileDescriptorProto_Extension_field_number {
 149  					if numExtensions > 0 {
 150  						panic("non-contiguous repeated field")
 151  					}
 152  					posExtensions = len(b0) - len(b) - n - m
 153  				}
 154  				numExtensions++
 155  			case genid.FileDescriptorProto_Service_field_number:
 156  				if prevField != genid.FileDescriptorProto_Service_field_number {
 157  					if numServices > 0 {
 158  						panic("non-contiguous repeated field")
 159  					}
 160  					posServices = len(b0) - len(b) - n - m
 161  				}
 162  				numServices++
 163  			}
 164  			prevField = num
 165  		case protowire.VarintType:
 166  			v, m := protowire.ConsumeVarint(b)
 167  			b = b[m:]
 168  			switch num {
 169  			case genid.FileDescriptorProto_Edition_field_number:
 170  				fd.L1.Edition = Edition(v)
 171  			}
 172  		default:
 173  			m := protowire.ConsumeFieldValue(num, typ, b)
 174  			b = b[m:]
 175  			prevField = -1 // ignore known field numbers of unknown wire type
 176  		}
 177  	}
 178  
 179  	// If syntax is missing, it is assumed to be proto2.
 180  	if fd.L1.Syntax == 0 {
 181  		fd.L1.Syntax = protoreflect.Proto2
 182  		fd.L1.Edition = EditionProto2
 183  	}
 184  
 185  	fd.L1.EditionFeatures = getFeaturesFor(fd.L1.Edition)
 186  
 187  	// Parse editions features from options if any
 188  	if options != nil {
 189  		fd.unmarshalSeedOptions(options)
 190  	}
 191  
 192  	// Must allocate all declarations before parsing each descriptor type
 193  	// to ensure we handled all descriptors in "flattened ordering".
 194  	if numEnums > 0 {
 195  		fd.L1.Enums.List = fd.allocEnums(numEnums)
 196  	}
 197  	if numMessages > 0 {
 198  		fd.L1.Messages.List = fd.allocMessages(numMessages)
 199  	}
 200  	if numExtensions > 0 {
 201  		fd.L1.Extensions.List = fd.allocExtensions(numExtensions)
 202  	}
 203  	if numServices > 0 {
 204  		fd.L1.Services.List = fd.allocServices(numServices)
 205  	}
 206  
 207  	if numEnums > 0 {
 208  		b := b0[posEnums:]
 209  		for i := range fd.L1.Enums.List {
 210  			_, n := protowire.ConsumeVarint(b)
 211  			v, m := protowire.ConsumeBytes(b[n:])
 212  			fd.L1.Enums.List[i].unmarshalSeed(v, sb, fd, fd, i)
 213  			b = b[n+m:]
 214  		}
 215  	}
 216  	if numMessages > 0 {
 217  		b := b0[posMessages:]
 218  		for i := range fd.L1.Messages.List {
 219  			_, n := protowire.ConsumeVarint(b)
 220  			v, m := protowire.ConsumeBytes(b[n:])
 221  			fd.L1.Messages.List[i].unmarshalSeed(v, sb, fd, fd, i)
 222  			b = b[n+m:]
 223  		}
 224  	}
 225  	if numExtensions > 0 {
 226  		b := b0[posExtensions:]
 227  		for i := range fd.L1.Extensions.List {
 228  			_, n := protowire.ConsumeVarint(b)
 229  			v, m := protowire.ConsumeBytes(b[n:])
 230  			fd.L1.Extensions.List[i].unmarshalSeed(v, sb, fd, fd, i)
 231  			b = b[n+m:]
 232  		}
 233  	}
 234  	if numServices > 0 {
 235  		b := b0[posServices:]
 236  		for i := range fd.L1.Services.List {
 237  			_, n := protowire.ConsumeVarint(b)
 238  			v, m := protowire.ConsumeBytes(b[n:])
 239  			fd.L1.Services.List[i].unmarshalSeed(v, sb, fd, fd, i)
 240  			b = b[n+m:]
 241  		}
 242  	}
 243  }
 244  
 245  func (fd *File) unmarshalSeedOptions(b []byte) {
 246  	for b := b; len(b) > 0; {
 247  		num, typ, n := protowire.ConsumeTag(b)
 248  		b = b[n:]
 249  		switch typ {
 250  		case protowire.BytesType:
 251  			v, m := protowire.ConsumeBytes(b)
 252  			b = b[m:]
 253  			switch num {
 254  			case genid.FileOptions_Features_field_number:
 255  				if fd.Syntax() != protoreflect.Editions {
 256  					panic(fmt.Sprintf("invalid descriptor: using edition features in a proto with syntax %s", fd.Syntax()))
 257  				}
 258  				fd.L1.EditionFeatures = unmarshalFeatureSet(v, fd.L1.EditionFeatures)
 259  			}
 260  		default:
 261  			m := protowire.ConsumeFieldValue(num, typ, b)
 262  			b = b[m:]
 263  		}
 264  	}
 265  }
 266  
 267  func (ed *Enum) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd protoreflect.Descriptor, i int) {
 268  	ed.L0.ParentFile = pf
 269  	ed.L0.Parent = pd
 270  	ed.L0.Index = i
 271  	ed.L1.EditionFeatures = featuresFromParentDesc(ed.Parent())
 272  
 273  	var numValues int
 274  	for b := b; len(b) > 0; {
 275  		num, typ, n := protowire.ConsumeTag(b)
 276  		b = b[n:]
 277  		switch typ {
 278  		case protowire.BytesType:
 279  			v, m := protowire.ConsumeBytes(b)
 280  			b = b[m:]
 281  			switch num {
 282  			case genid.EnumDescriptorProto_Name_field_number:
 283  				ed.L0.FullName = appendFullName(sb, pd.FullName(), v)
 284  			case genid.EnumDescriptorProto_Value_field_number:
 285  				numValues++
 286  			}
 287  		case protowire.VarintType:
 288  			v, m := protowire.ConsumeVarint(b)
 289  			b = b[m:]
 290  			switch num {
 291  			case genid.EnumDescriptorProto_Visibility_field_number:
 292  				ed.L1.Visibility = int32(v)
 293  			}
 294  		default:
 295  			m := protowire.ConsumeFieldValue(num, typ, b)
 296  			b = b[m:]
 297  		}
 298  	}
 299  
 300  	// Only construct enum value descriptors for top-level enums since
 301  	// they are needed for registration.
 302  	if pd != pf {
 303  		return
 304  	}
 305  	ed.L1.eagerValues = true
 306  	ed.L2 = new(EnumL2)
 307  	ed.L2.Values.List = make([]EnumValue, numValues)
 308  	for i := 0; len(b) > 0; {
 309  		num, typ, n := protowire.ConsumeTag(b)
 310  		b = b[n:]
 311  		switch typ {
 312  		case protowire.BytesType:
 313  			v, m := protowire.ConsumeBytes(b)
 314  			b = b[m:]
 315  			switch num {
 316  			case genid.EnumDescriptorProto_Value_field_number:
 317  				ed.L2.Values.List[i].unmarshalFull(v, sb, pf, ed, i)
 318  				i++
 319  			}
 320  		default:
 321  			m := protowire.ConsumeFieldValue(num, typ, b)
 322  			b = b[m:]
 323  		}
 324  	}
 325  }
 326  
 327  func (md *Message) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd protoreflect.Descriptor, i int) {
 328  	md.L0.ParentFile = pf
 329  	md.L0.Parent = pd
 330  	md.L0.Index = i
 331  	md.L1.EditionFeatures = featuresFromParentDesc(md.Parent())
 332  
 333  	var prevField protoreflect.FieldNumber
 334  	var numEnums, numMessages, numExtensions int
 335  	var posEnums, posMessages, posExtensions int
 336  	b0 := b
 337  	for len(b) > 0 {
 338  		num, typ, n := protowire.ConsumeTag(b)
 339  		b = b[n:]
 340  		switch typ {
 341  		case protowire.BytesType:
 342  			v, m := protowire.ConsumeBytes(b)
 343  			b = b[m:]
 344  			switch num {
 345  			case genid.DescriptorProto_Name_field_number:
 346  				md.L0.FullName = appendFullName(sb, pd.FullName(), v)
 347  			case genid.DescriptorProto_EnumType_field_number:
 348  				if prevField != genid.DescriptorProto_EnumType_field_number {
 349  					if numEnums > 0 {
 350  						panic("non-contiguous repeated field")
 351  					}
 352  					posEnums = len(b0) - len(b) - n - m
 353  				}
 354  				numEnums++
 355  			case genid.DescriptorProto_NestedType_field_number:
 356  				if prevField != genid.DescriptorProto_NestedType_field_number {
 357  					if numMessages > 0 {
 358  						panic("non-contiguous repeated field")
 359  					}
 360  					posMessages = len(b0) - len(b) - n - m
 361  				}
 362  				numMessages++
 363  			case genid.DescriptorProto_Extension_field_number:
 364  				if prevField != genid.DescriptorProto_Extension_field_number {
 365  					if numExtensions > 0 {
 366  						panic("non-contiguous repeated field")
 367  					}
 368  					posExtensions = len(b0) - len(b) - n - m
 369  				}
 370  				numExtensions++
 371  			case genid.DescriptorProto_Options_field_number:
 372  				md.unmarshalSeedOptions(v)
 373  			}
 374  			prevField = num
 375  		case protowire.VarintType:
 376  			v, m := protowire.ConsumeVarint(b)
 377  			b = b[m:]
 378  			switch num {
 379  			case genid.DescriptorProto_Visibility_field_number:
 380  				md.L1.Visibility = int32(v)
 381  			}
 382  		default:
 383  			m := protowire.ConsumeFieldValue(num, typ, b)
 384  			b = b[m:]
 385  			prevField = -1 // ignore known field numbers of unknown wire type
 386  		}
 387  	}
 388  
 389  	// Must allocate all declarations before parsing each descriptor type
 390  	// to ensure we handled all descriptors in "flattened ordering".
 391  	if numEnums > 0 {
 392  		md.L1.Enums.List = pf.allocEnums(numEnums)
 393  	}
 394  	if numMessages > 0 {
 395  		md.L1.Messages.List = pf.allocMessages(numMessages)
 396  	}
 397  	if numExtensions > 0 {
 398  		md.L1.Extensions.List = pf.allocExtensions(numExtensions)
 399  	}
 400  
 401  	if numEnums > 0 {
 402  		b := b0[posEnums:]
 403  		for i := range md.L1.Enums.List {
 404  			_, n := protowire.ConsumeVarint(b)
 405  			v, m := protowire.ConsumeBytes(b[n:])
 406  			md.L1.Enums.List[i].unmarshalSeed(v, sb, pf, md, i)
 407  			b = b[n+m:]
 408  		}
 409  	}
 410  	if numMessages > 0 {
 411  		b := b0[posMessages:]
 412  		for i := range md.L1.Messages.List {
 413  			_, n := protowire.ConsumeVarint(b)
 414  			v, m := protowire.ConsumeBytes(b[n:])
 415  			md.L1.Messages.List[i].unmarshalSeed(v, sb, pf, md, i)
 416  			b = b[n+m:]
 417  		}
 418  	}
 419  	if numExtensions > 0 {
 420  		b := b0[posExtensions:]
 421  		for i := range md.L1.Extensions.List {
 422  			_, n := protowire.ConsumeVarint(b)
 423  			v, m := protowire.ConsumeBytes(b[n:])
 424  			md.L1.Extensions.List[i].unmarshalSeed(v, sb, pf, md, i)
 425  			b = b[n+m:]
 426  		}
 427  	}
 428  }
 429  
 430  func (md *Message) unmarshalSeedOptions(b []byte) {
 431  	for len(b) > 0 {
 432  		num, typ, n := protowire.ConsumeTag(b)
 433  		b = b[n:]
 434  		switch typ {
 435  		case protowire.VarintType:
 436  			v, m := protowire.ConsumeVarint(b)
 437  			b = b[m:]
 438  			switch num {
 439  			case genid.MessageOptions_MapEntry_field_number:
 440  				md.L1.IsMapEntry = protowire.DecodeBool(v)
 441  			case genid.MessageOptions_MessageSetWireFormat_field_number:
 442  				md.L1.IsMessageSet = protowire.DecodeBool(v)
 443  			}
 444  		case protowire.BytesType:
 445  			v, m := protowire.ConsumeBytes(b)
 446  			b = b[m:]
 447  			switch num {
 448  			case genid.MessageOptions_Features_field_number:
 449  				md.L1.EditionFeatures = unmarshalFeatureSet(v, md.L1.EditionFeatures)
 450  			}
 451  		default:
 452  			m := protowire.ConsumeFieldValue(num, typ, b)
 453  			b = b[m:]
 454  		}
 455  	}
 456  }
 457  
 458  func (xd *Extension) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd protoreflect.Descriptor, i int) {
 459  	xd.L0.ParentFile = pf
 460  	xd.L0.Parent = pd
 461  	xd.L0.Index = i
 462  	xd.L1.EditionFeatures = featuresFromParentDesc(pd)
 463  
 464  	for len(b) > 0 {
 465  		num, typ, n := protowire.ConsumeTag(b)
 466  		b = b[n:]
 467  		switch typ {
 468  		case protowire.VarintType:
 469  			v, m := protowire.ConsumeVarint(b)
 470  			b = b[m:]
 471  			switch num {
 472  			case genid.FieldDescriptorProto_Number_field_number:
 473  				xd.L1.Number = protoreflect.FieldNumber(v)
 474  			case genid.FieldDescriptorProto_Label_field_number:
 475  				xd.L1.Cardinality = protoreflect.Cardinality(v)
 476  			case genid.FieldDescriptorProto_Type_field_number:
 477  				xd.L1.Kind = protoreflect.Kind(v)
 478  			}
 479  		case protowire.BytesType:
 480  			v, m := protowire.ConsumeBytes(b)
 481  			b = b[m:]
 482  			switch num {
 483  			case genid.FieldDescriptorProto_Name_field_number:
 484  				xd.L0.FullName = appendFullName(sb, pd.FullName(), v)
 485  			case genid.FieldDescriptorProto_Extendee_field_number:
 486  				xd.L1.Extendee = PlaceholderMessage(makeFullName(sb, v))
 487  			case genid.FieldDescriptorProto_Options_field_number:
 488  				xd.unmarshalOptions(v)
 489  			}
 490  		default:
 491  			m := protowire.ConsumeFieldValue(num, typ, b)
 492  			b = b[m:]
 493  		}
 494  	}
 495  
 496  	if xd.L1.Kind == protoreflect.MessageKind && xd.L1.EditionFeatures.IsDelimitedEncoded {
 497  		xd.L1.Kind = protoreflect.GroupKind
 498  	}
 499  }
 500  
 501  func (xd *Extension) unmarshalOptions(b []byte) {
 502  	for len(b) > 0 {
 503  		num, typ, n := protowire.ConsumeTag(b)
 504  		b = b[n:]
 505  		switch typ {
 506  		case protowire.VarintType:
 507  			v, m := protowire.ConsumeVarint(b)
 508  			b = b[m:]
 509  			switch num {
 510  			case genid.FieldOptions_Packed_field_number:
 511  				xd.L1.EditionFeatures.IsPacked = protowire.DecodeBool(v)
 512  			case genid.FieldOptions_Lazy_field_number:
 513  				xd.L1.IsLazy = protowire.DecodeBool(v)
 514  			}
 515  		case protowire.BytesType:
 516  			v, m := protowire.ConsumeBytes(b)
 517  			b = b[m:]
 518  			switch num {
 519  			case genid.FieldOptions_Features_field_number:
 520  				xd.L1.EditionFeatures = unmarshalFeatureSet(v, xd.L1.EditionFeatures)
 521  			}
 522  		default:
 523  			m := protowire.ConsumeFieldValue(num, typ, b)
 524  			b = b[m:]
 525  		}
 526  	}
 527  }
 528  
 529  func (sd *Service) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd protoreflect.Descriptor, i int) {
 530  	sd.L0.ParentFile = pf
 531  	sd.L0.Parent = pd
 532  	sd.L0.Index = i
 533  
 534  	for len(b) > 0 {
 535  		num, typ, n := protowire.ConsumeTag(b)
 536  		b = b[n:]
 537  		switch typ {
 538  		case protowire.BytesType:
 539  			v, m := protowire.ConsumeBytes(b)
 540  			b = b[m:]
 541  			switch num {
 542  			case genid.ServiceDescriptorProto_Name_field_number:
 543  				sd.L0.FullName = appendFullName(sb, pd.FullName(), v)
 544  			}
 545  		default:
 546  			m := protowire.ConsumeFieldValue(num, typ, b)
 547  			b = b[m:]
 548  		}
 549  	}
 550  }
 551  
 552  var nameBuilderPool = sync.Pool{
 553  	New: func() any { return new(strs.Builder) },
 554  }
 555  
 556  func getBuilder() *strs.Builder {
 557  	return nameBuilderPool.Get().(*strs.Builder)
 558  }
 559  func putBuilder(b *strs.Builder) {
 560  	nameBuilderPool.Put(b)
 561  }
 562  
 563  // makeFullName converts b to a protoreflect.FullName,
 564  // where b must start with a leading dot.
 565  func makeFullName(sb *strs.Builder, b []byte) protoreflect.FullName {
 566  	if len(b) == 0 || b[0] != '.' {
 567  		panic("name reference must be fully qualified")
 568  	}
 569  	return protoreflect.FullName(sb.MakeString(b[1:]))
 570  }
 571  
 572  func appendFullName(sb *strs.Builder, prefix protoreflect.FullName, suffix []byte) protoreflect.FullName {
 573  	return sb.AppendFullName(prefix, protoreflect.Name(strs.UnsafeString(suffix)))
 574  }
 575