github.com/cosmos/cosmos-proto@v1.0.0-beta.3/features/protoc/main.go (about) 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 protoc is used to generate protoc-gen-go files 6 package protoc 7 8 import ( 9 "fmt" 10 "github.com/cosmos/cosmos-proto/features/protoc/genid" 11 "github.com/cosmos/cosmos-proto/generator" 12 "go/ast" 13 "go/parser" 14 "go/token" 15 "google.golang.org/protobuf/encoding/protowire" 16 "google.golang.org/protobuf/proto" 17 "math" 18 "strconv" 19 "strings" 20 "unicode" 21 "unicode/utf8" 22 23 pref "google.golang.org/protobuf/reflect/protoreflect" 24 25 "github.com/cosmos/cosmos-proto/features/protoc/version" 26 "google.golang.org/protobuf/compiler/protogen" 27 "google.golang.org/protobuf/reflect/protoreflect" 28 "google.golang.org/protobuf/runtime/protoimpl" 29 30 "google.golang.org/protobuf/types/descriptorpb" 31 "google.golang.org/protobuf/types/pluginpb" 32 ) 33 34 // SupportedFeatures reports the set of supported protobuf language features. 35 var SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL) 36 37 // GenerateVersionMarkers specifies whether to generate version markers. 38 var GenerateVersionMarkers = true 39 40 // Standard library dependencies. 41 const ( 42 base64Package = protogen.GoImportPath("encoding/base64") 43 mathPackage = protogen.GoImportPath("math") 44 reflectPackage = protogen.GoImportPath("reflect") 45 sortPackage = protogen.GoImportPath("sort") 46 stringsPackage = protogen.GoImportPath("strings") 47 syncPackage = protogen.GoImportPath("sync") 48 timePackage = protogen.GoImportPath("time") 49 utf8Package = protogen.GoImportPath("unicode/utf8") 50 ) 51 52 // Protobuf library dependencies. 53 // 54 // These are declared as an interface type so that they can be more easily 55 // patched to support unique build environments that impose restrictions 56 // on the dependencies of generated source code. 57 var ( 58 protoPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/proto") 59 protoimplPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/runtime/protoimpl") 60 protojsonPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/encoding/protojson") 61 protoreflectPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/reflect/protoreflect") 62 protoregistryPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/reflect/protoregistry") 63 ) 64 65 // GenerateFile generates the contents of a .pb.go file. 66 func GenerateFile(gen *protogen.Plugin, file *protogen.File, g *generator.GeneratedFile) *generator.GeneratedFile { 67 // filename := file.GeneratedFilenamePrefix + ".pb.go" 68 // g := gen.NewGeneratedFile(filename, file.GoImportPath) 69 f := newFileInfo(file) 70 71 genStandaloneComments(g, f, int32(genid.FileDescriptorProto_Syntax_field_number)) 72 genGeneratedHeader(gen, g, f) 73 genStandaloneComments(g, f, int32(genid.FileDescriptorProto_Package_field_number)) 74 75 // Emit a static check that enforces a minimum version of the proto package. 76 if GenerateVersionMarkers { 77 g.P("const (") 78 g.P("// Verify that this generated code is sufficiently up-to-date.") 79 g.P("_ = ", protoimplPackage.Ident("EnforceVersion"), "(", protoimpl.GenVersion, " - ", protoimplPackage.Ident("MinVersion"), ")") 80 g.P("// Verify that runtime/protoimpl is sufficiently up-to-date.") 81 g.P("_ = ", protoimplPackage.Ident("EnforceVersion"), "(", protoimplPackage.Ident("MaxVersion"), " - ", protoimpl.GenVersion, ")") 82 g.P(")") 83 g.P() 84 } 85 86 for i, imps := 0, f.Desc.Imports(); i < imps.Len(); i++ { 87 genImport(gen, g, f, imps.Get(i)) 88 } 89 for _, enum := range f.allEnums { 90 genEnum(g, f, enum) 91 } 92 for _, message := range f.allMessages { 93 genMessage(g, f, message) 94 } 95 genExtensions(g, f) 96 97 genReflectFileDescriptor(gen, g, f) 98 99 return g 100 } 101 102 func fileVarName(f *protogen.File, suffix string) string { 103 prefix := f.GoDescriptorIdent.GoName 104 _, n := utf8.DecodeRuneInString(prefix) 105 prefix = strings.ToLower(prefix[:n]) + prefix[n:] 106 return prefix + "_" + suffix 107 } 108 109 func rawDescVarName(f *fileInfo) string { 110 return fileVarName(f.File, "rawDesc") 111 } 112 func goTypesVarName(f *fileInfo) string { 113 return fileVarName(f.File, "goTypes") 114 } 115 func depIdxsVarName(f *fileInfo) string { 116 return fileVarName(f.File, "depIdxs") 117 } 118 func enumTypesVarName(f *fileInfo) string { 119 return fileVarName(f.File, "enumTypes") 120 } 121 func messageTypesVarName(f *fileInfo) string { 122 return fileVarName(f.File, "msgTypes") 123 } 124 func extensionTypesVarName(f *fileInfo) string { 125 return fileVarName(f.File, "extTypes") 126 } 127 func initFuncName(f *protogen.File) string { 128 return fileVarName(f, "init") 129 } 130 131 func genFileDescriptor(gen *protogen.Plugin, g *generator.GeneratedFile, f *fileInfo) { 132 descProto := proto.Clone(f.Proto).(*descriptorpb.FileDescriptorProto) 133 descProto.SourceCodeInfo = nil // drop source code information 134 135 b, err := proto.MarshalOptions{AllowPartial: true, Deterministic: true}.Marshal(descProto) 136 if err != nil { 137 gen.Error(err) 138 return 139 } 140 141 g.P("var ", rawDescVarName(f), " = []byte{") 142 for len(b) > 0 { 143 n := 16 144 if n > len(b) { 145 n = len(b) 146 } 147 148 s := "" 149 for _, c := range b[:n] { 150 s += fmt.Sprintf("0x%02x,", c) 151 } 152 g.P(s) 153 154 b = b[n:] 155 } 156 g.P("}") 157 g.P() 158 159 if f.needRawDesc { 160 onceVar := rawDescVarName(f) + "Once" 161 dataVar := rawDescVarName(f) + "Data" 162 g.P("var (") 163 g.P(onceVar, " ", syncPackage.Ident("Once")) 164 g.P(dataVar, " = ", rawDescVarName(f)) 165 g.P(")") 166 g.P() 167 168 g.P("func ", rawDescVarName(f), "GZIP() []byte {") 169 g.P(onceVar, ".Do(func() {") 170 g.P(dataVar, " = ", protoimplPackage.Ident("X"), ".CompressGZIP(", dataVar, ")") 171 g.P("})") 172 g.P("return ", dataVar) 173 g.P("}") 174 g.P() 175 } 176 } 177 178 func genReflectFileDescriptor(gen *protogen.Plugin, g *generator.GeneratedFile, f *fileInfo) { 179 g.P("var ", f.GoDescriptorIdent, " ", protoreflectPackage.Ident("FileDescriptor")) 180 g.P() 181 182 genFileDescriptor(gen, g, f) 183 if len(f.allEnums) > 0 { 184 g.P("var ", enumTypesVarName(f), " = make([]", protoimplPackage.Ident("EnumInfo"), ",", len(f.allEnums), ")") 185 } 186 if len(f.allMessages) > 0 { 187 g.P("var ", messageTypesVarName(f), " = make([]", protoimplPackage.Ident("MessageInfo"), ",", len(f.allMessages), ")") 188 } 189 190 // Generate a unique list of Go types for all declarations and dependencies, 191 // and the associated index into the type list for all dependencies. 192 var goTypes []string 193 var depIdxs []string 194 seen := map[protoreflect.FullName]int{} 195 genDep := func(name protoreflect.FullName, depSource string) { 196 if depSource != "" { 197 line := fmt.Sprintf("%d, // %d: %s -> %s", seen[name], len(depIdxs), depSource, name) 198 depIdxs = append(depIdxs, line) 199 } 200 } 201 genEnum := func(e *protogen.Enum, depSource string) { 202 if e != nil { 203 name := e.Desc.FullName() 204 if _, ok := seen[name]; !ok { 205 line := fmt.Sprintf("(%s)(0), // %d: %s", g.QualifiedGoIdent(e.GoIdent), len(goTypes), name) 206 goTypes = append(goTypes, line) 207 seen[name] = len(seen) 208 } 209 if depSource != "" { 210 genDep(name, depSource) 211 } 212 } 213 } 214 genMessage := func(m *protogen.Message, depSource string) { 215 if m != nil { 216 name := m.Desc.FullName() 217 if _, ok := seen[name]; !ok { 218 line := fmt.Sprintf("(*%s)(nil), // %d: %s", g.QualifiedGoIdent(m.GoIdent), len(goTypes), name) 219 if m.Desc.IsMapEntry() { 220 // Map entry messages have no associated Go type. 221 line = fmt.Sprintf("nil, // %d: %s", len(goTypes), name) 222 } 223 goTypes = append(goTypes, line) 224 seen[name] = len(seen) 225 } 226 if depSource != "" { 227 genDep(name, depSource) 228 } 229 } 230 } 231 232 // This ordering is significant. 233 // See filetype.TypeBuilder.DependencyIndexes. 234 type offsetEntry struct { 235 start int 236 name string 237 } 238 var depOffsets []offsetEntry 239 for _, enum := range f.allEnums { 240 genEnum(enum.Enum, "") 241 } 242 for _, message := range f.allMessages { 243 genMessage(message.Message, "") 244 } 245 depOffsets = append(depOffsets, offsetEntry{len(depIdxs), "field type_name"}) 246 for _, message := range f.allMessages { 247 for _, field := range message.Fields { 248 if field.Desc.IsWeak() { 249 continue 250 } 251 source := string(field.Desc.FullName()) 252 genEnum(field.Enum, source+":type_name") 253 genMessage(field.Message, source+":type_name") 254 } 255 } 256 depOffsets = append(depOffsets, offsetEntry{len(depIdxs), "extension extendee"}) 257 for _, extension := range f.allExtensions { 258 source := string(extension.Desc.FullName()) 259 genMessage(extension.Extendee, source+":extendee") 260 } 261 depOffsets = append(depOffsets, offsetEntry{len(depIdxs), "extension type_name"}) 262 for _, extension := range f.allExtensions { 263 source := string(extension.Desc.FullName()) 264 genEnum(extension.Enum, source+":type_name") 265 genMessage(extension.Message, source+":type_name") 266 } 267 depOffsets = append(depOffsets, offsetEntry{len(depIdxs), "method input_type"}) 268 for _, service := range f.Services { 269 for _, method := range service.Methods { 270 source := string(method.Desc.FullName()) 271 genMessage(method.Input, source+":input_type") 272 } 273 } 274 depOffsets = append(depOffsets, offsetEntry{len(depIdxs), "method output_type"}) 275 for _, service := range f.Services { 276 for _, method := range service.Methods { 277 source := string(method.Desc.FullName()) 278 genMessage(method.Output, source+":output_type") 279 } 280 } 281 depOffsets = append(depOffsets, offsetEntry{len(depIdxs), ""}) 282 for i := len(depOffsets) - 2; i >= 0; i-- { 283 curr, next := depOffsets[i], depOffsets[i+1] 284 depIdxs = append(depIdxs, fmt.Sprintf("%d, // [%d:%d] is the sub-list for %s", 285 curr.start, curr.start, next.start, curr.name)) 286 } 287 if len(depIdxs) > math.MaxInt32 { 288 panic("too many dependencies") // sanity check 289 } 290 291 g.P("var ", goTypesVarName(f), " = []interface{}{") 292 for _, s := range goTypes { 293 g.P(s) 294 } 295 g.P("}") 296 297 g.P("var ", depIdxsVarName(f), " = []int32{") 298 for _, s := range depIdxs { 299 g.P(s) 300 } 301 g.P("}") 302 303 g.P("func init() { ", initFuncName(f.File), "() }") 304 305 g.P("func ", initFuncName(f.File), "() {") 306 g.P("if ", f.GoDescriptorIdent, " != nil {") 307 g.P("return") 308 g.P("}") 309 310 // Ensure that initialization functions for different files in the same Go 311 // package run in the correct order: Call the init funcs for every .proto file 312 // imported by this one that is in the same Go package. 313 for i, imps := 0, f.Desc.Imports(); i < imps.Len(); i++ { 314 impFile := gen.FilesByPath[imps.Get(i).Path()] 315 if impFile.GoImportPath != f.GoImportPath { 316 continue 317 } 318 g.P(initFuncName(impFile), "()") 319 } 320 321 if len(f.allMessages) > 0 { 322 // Populate MessageInfo.Exporters. 323 g.P("if !", protoimplPackage.Ident("UnsafeEnabled"), " {") 324 for _, message := range f.allMessages { 325 if sf := f.allMessageFieldsByPtr[message]; len(sf.unexported) > 0 { 326 idx := f.allMessagesByPtr[message] 327 typesVar := messageTypesVarName(f) 328 329 g.P(typesVar, "[", idx, "].Exporter = func(v interface{}, i int) interface{} {") 330 g.P("switch v := v.(*", message.GoIdent, "); i {") 331 for i := 0; i < sf.count; i++ { 332 if name := sf.unexported[i]; name != "" { 333 g.P("case ", i, ": return &v.", name) 334 } 335 } 336 g.P("default: return nil") 337 g.P("}") 338 g.P("}") 339 } 340 } 341 g.P("}") 342 343 // Populate MessageInfo.OneofWrappers. 344 for _, message := range f.allMessages { 345 if len(message.Oneofs) > 0 { 346 idx := f.allMessagesByPtr[message] 347 typesVar := messageTypesVarName(f) 348 349 // Associate the wrapper types by directly passing them to the MessageInfo. 350 g.P(typesVar, "[", idx, "].OneofWrappers = []interface{} {") 351 for _, oneof := range message.Oneofs { 352 if !oneof.Desc.IsSynthetic() { 353 for _, field := range oneof.Fields { 354 g.P("(*", field.GoIdent, ")(nil),") 355 } 356 } 357 } 358 g.P("}") 359 } 360 } 361 } 362 363 g.P("type x struct{}") 364 g.P("out := ", protoimplPackage.Ident("TypeBuilder"), "{") 365 g.P("File: ", protoimplPackage.Ident("DescBuilder"), "{") 366 g.P("GoPackagePath: ", reflectPackage.Ident("TypeOf"), "(x{}).PkgPath(),") 367 g.P("RawDescriptor: ", rawDescVarName(f), ",") 368 g.P("NumEnums: ", len(f.allEnums), ",") 369 g.P("NumMessages: ", len(f.allMessages), ",") 370 g.P("NumExtensions: ", len(f.allExtensions), ",") 371 g.P("NumServices: ", len(f.Services), ",") 372 g.P("},") 373 g.P("GoTypes: ", goTypesVarName(f), ",") 374 g.P("DependencyIndexes: ", depIdxsVarName(f), ",") 375 if len(f.allEnums) > 0 { 376 g.P("EnumInfos: ", enumTypesVarName(f), ",") 377 } 378 if len(f.allMessages) > 0 { 379 g.P("MessageInfos: ", messageTypesVarName(f), ",") 380 } 381 if len(f.allExtensions) > 0 { 382 g.P("ExtensionInfos: ", extensionTypesVarName(f), ",") 383 } 384 g.P("}.Build()") 385 g.P(f.GoDescriptorIdent, " = out.File") 386 387 // Set inputs to nil to allow GC to reclaim resources. 388 g.P(rawDescVarName(f), " = nil") 389 g.P(goTypesVarName(f), " = nil") 390 g.P(depIdxsVarName(f), " = nil") 391 g.P("}") 392 } 393 394 // genStandaloneComments prints all leading comments for a FileDescriptorProto 395 // location identified by the field number n. 396 func genStandaloneComments(g *generator.GeneratedFile, f *fileInfo, n int32) { 397 loc := f.Desc.SourceLocations().ByPath(protoreflect.SourcePath{n}) 398 for _, s := range loc.LeadingDetachedComments { 399 g.P(protogen.Comments(s)) 400 g.P() 401 } 402 if s := loc.LeadingComments; s != "" { 403 g.P(protogen.Comments(s)) 404 g.P() 405 } 406 } 407 408 func genGeneratedHeader(gen *protogen.Plugin, g *generator.GeneratedFile, f *fileInfo) { 409 g.P("// Code generated by protoc-gen-go. DO NOT EDIT.") 410 411 if GenerateVersionMarkers { 412 g.P("// versions:") 413 protocGenGoVersion := version.String() 414 protocVersion := "(unknown)" 415 if v := gen.Request.GetCompilerVersion(); v != nil { 416 protocVersion = fmt.Sprintf("v%v.%v.%v", v.GetMajor(), v.GetMinor(), v.GetPatch()) 417 if s := v.GetSuffix(); s != "" { 418 protocVersion += "-" + s 419 } 420 } 421 g.P("// \tprotoc-gen-go ", protocGenGoVersion) 422 g.P("// \tprotoc ", protocVersion) 423 } 424 425 if f.Proto.GetOptions().GetDeprecated() { 426 g.P("// ", f.Desc.Path(), " is a deprecated file.") 427 } else { 428 g.P("// source: ", f.Desc.Path()) 429 } 430 g.P() 431 } 432 433 func genImport(gen *protogen.Plugin, g *generator.GeneratedFile, f *fileInfo, imp protoreflect.FileImport) { 434 impFile, ok := gen.FilesByPath[imp.Path()] 435 if !ok { 436 return 437 } 438 if impFile.GoImportPath == f.GoImportPath { 439 // Don't generate imports or aliases for types in the same Go package. 440 return 441 } 442 // Generate imports for all non-weak dependencies, even if they are not 443 // referenced, because other code and tools depend on having the 444 // full transitive closure of protocol buffer types in the binary. 445 if !imp.IsWeak { 446 g.Import(impFile.GoImportPath) 447 } 448 if !imp.IsPublic { 449 return 450 } 451 452 // Generate public imports by generating the imported file, parsing it, 453 // and extracting every symbol that should receive a forwarding declaration. 454 impGen := GenerateFile(gen, impFile, g) 455 impGen.Skip() 456 b, err := impGen.Content() 457 if err != nil { 458 gen.Error(err) 459 return 460 } 461 fset := token.NewFileSet() 462 astFile, err := parser.ParseFile(fset, "", b, parser.ParseComments) 463 if err != nil { 464 gen.Error(err) 465 return 466 } 467 genForward := func(tok token.Token, name string, expr ast.Expr) { 468 // Don't import unexported symbols. 469 r, _ := utf8.DecodeRuneInString(name) 470 if !unicode.IsUpper(r) { 471 return 472 } 473 // Don't import the FileDescriptor. 474 if name == impFile.GoDescriptorIdent.GoName { 475 return 476 } 477 // Don't import decls referencing a symbol defined in another package. 478 // i.e., don't import decls which are themselves public imports: 479 // 480 // type T = somepackage.T 481 if _, ok := expr.(*ast.SelectorExpr); ok { 482 return 483 } 484 g.P(tok, " ", name, " = ", impFile.GoImportPath.Ident(name)) 485 } 486 g.P("// Symbols defined in public import of ", imp.Path(), ".") 487 g.P() 488 for _, decl := range astFile.Decls { 489 switch decl := decl.(type) { 490 case *ast.GenDecl: 491 for _, spec := range decl.Specs { 492 switch spec := spec.(type) { 493 case *ast.TypeSpec: 494 genForward(decl.Tok, spec.Name.Name, spec.Type) 495 case *ast.ValueSpec: 496 for i, name := range spec.Names { 497 var expr ast.Expr 498 if i < len(spec.Values) { 499 expr = spec.Values[i] 500 } 501 genForward(decl.Tok, name.Name, expr) 502 } 503 case *ast.ImportSpec: 504 default: 505 panic(fmt.Sprintf("can't generate forward for spec type %T", spec)) 506 } 507 } 508 } 509 } 510 g.P() 511 } 512 513 func genEnumReflectMethods(g *generator.GeneratedFile, f *fileInfo, e *enumInfo) { 514 idx := f.allEnumsByPtr[e] 515 typesVar := enumTypesVarName(f) 516 517 // Descriptor method. 518 g.P("func (", e.GoIdent, ") Descriptor() ", protoreflectPackage.Ident("EnumDescriptor"), " {") 519 g.P("return ", typesVar, "[", idx, "].Descriptor()") 520 g.P("}") 521 g.P() 522 523 // Type method. 524 g.P("func (", e.GoIdent, ") Type() ", protoreflectPackage.Ident("EnumType"), " {") 525 g.P("return &", typesVar, "[", idx, "]") 526 g.P("}") 527 g.P() 528 529 // Number method. 530 g.P("func (x ", e.GoIdent, ") Number() ", protoreflectPackage.Ident("EnumNumber"), " {") 531 g.P("return ", protoreflectPackage.Ident("EnumNumber"), "(x)") 532 g.P("}") 533 g.P() 534 } 535 536 func genEnum(g *generator.GeneratedFile, f *fileInfo, e *enumInfo) { 537 // Enum type declaration. 538 g.Annotate(e.GoIdent.GoName, e.Location) 539 leadingComments := appendDeprecationSuffix(e.Comments.Leading, 540 e.Desc.Options().(*descriptorpb.EnumOptions).GetDeprecated()) 541 g.P(leadingComments, 542 "type ", e.GoIdent, " int32") 543 544 // Enum value constants. 545 g.P("const (") 546 for _, value := range e.Values { 547 g.Annotate(value.GoIdent.GoName, value.Location) 548 leadingComments := appendDeprecationSuffix(value.Comments.Leading, 549 value.Desc.Options().(*descriptorpb.EnumValueOptions).GetDeprecated()) 550 g.P(leadingComments, 551 value.GoIdent, " ", e.GoIdent, " = ", value.Desc.Number(), 552 trailingComment(value.Comments.Trailing)) 553 } 554 g.P(")") 555 g.P() 556 557 // Enum value maps. 558 g.P("// Enum value maps for ", e.GoIdent, ".") 559 g.P("var (") 560 g.P(e.GoIdent.GoName+"_name", " = map[int32]string{") 561 for _, value := range e.Values { 562 duplicate := "" 563 if value.Desc != e.Desc.Values().ByNumber(value.Desc.Number()) { 564 duplicate = "// Duplicate value: " 565 } 566 g.P(duplicate, value.Desc.Number(), ": ", strconv.Quote(string(value.Desc.Name())), ",") 567 } 568 g.P("}") 569 g.P(e.GoIdent.GoName+"_value", " = map[string]int32{") 570 for _, value := range e.Values { 571 g.P(strconv.Quote(string(value.Desc.Name())), ": ", value.Desc.Number(), ",") 572 } 573 g.P("}") 574 g.P(")") 575 g.P() 576 577 // Enum method. 578 // 579 // NOTE: A pointer value is needed to represent presence in proto2. 580 // Since a proto2 message can reference a proto3 enum, it is useful to 581 // always generate this method (even on proto3 enums) to support that case. 582 g.P("func (x ", e.GoIdent, ") Enum() *", e.GoIdent, " {") 583 g.P("p := new(", e.GoIdent, ")") 584 g.P("*p = x") 585 g.P("return p") 586 g.P("}") 587 g.P() 588 589 // String method. 590 g.P("func (x ", e.GoIdent, ") String() string {") 591 g.P("return ", protoimplPackage.Ident("X"), ".EnumStringOf(x.Descriptor(), ", protoreflectPackage.Ident("EnumNumber"), "(x))") 592 g.P("}") 593 g.P() 594 595 genEnumReflectMethods(g, f, e) 596 597 // UnmarshalJSON method. 598 if e.genJSONMethod && e.Desc.Syntax() == protoreflect.Proto2 { 599 g.P("// Deprecated: Do not use.") 600 g.P("func (x *", e.GoIdent, ") UnmarshalJSON(b []byte) error {") 601 g.P("num, err := ", protoimplPackage.Ident("X"), ".UnmarshalJSONEnum(x.Descriptor(), b)") 602 g.P("if err != nil {") 603 g.P("return err") 604 g.P("}") 605 g.P("*x = ", e.GoIdent, "(num)") 606 g.P("return nil") 607 g.P("}") 608 g.P() 609 } 610 611 // EnumDescriptor method. 612 if e.genRawDescMethod { 613 var indexes []string 614 for i := 1; i < len(e.Location.Path); i += 2 { 615 indexes = append(indexes, strconv.Itoa(int(e.Location.Path[i]))) 616 } 617 g.P("// Deprecated: Use ", e.GoIdent, ".Descriptor instead.") 618 g.P("func (", e.GoIdent, ") EnumDescriptor() ([]byte, []int) {") 619 g.P("return ", rawDescVarName(f), "GZIP(), []int{", strings.Join(indexes, ","), "}") 620 g.P("}") 621 g.P() 622 f.needRawDesc = true 623 } 624 } 625 626 func genMessage(g *generator.GeneratedFile, f *fileInfo, m *messageInfo) { 627 if m.Desc.IsMapEntry() { 628 return 629 } 630 631 // Message type declaration. 632 g.Annotate(m.GoIdent.GoName, m.Location) 633 leadingComments := appendDeprecationSuffix(m.Comments.Leading, 634 m.Desc.Options().(*descriptorpb.MessageOptions).GetDeprecated()) 635 g.P(leadingComments, 636 "type ", m.GoIdent, " struct {") 637 genMessageFields(g, f, m) 638 g.P("}") 639 g.P() 640 641 genMessageKnownFunctions(g, f, m) 642 genMessageDefaultDecls(g, f, m) 643 genMessageMethods(g, f, m) 644 genMessageOneofWrapperTypes(g, f, m) 645 } 646 647 func genMessageKnownFunctions(g *generator.GeneratedFile, f *fileInfo, m *messageInfo) { 648 switch m.Desc.FullName() { 649 case genid.Any_message_fullname: 650 g.P("// New marshals src into a new Any instance.") 651 g.P("func New(src ", protoPackage.Ident("Message"), ") (*Any, error) {") 652 g.P(" dst := new(Any)") 653 g.P(" if err := dst.MarshalFrom(src); err != nil {") 654 g.P(" return nil, err") 655 g.P(" }") 656 g.P(" return dst, nil") 657 g.P("}") 658 g.P() 659 660 g.P("// MarshalFrom marshals src into dst as the underlying message") 661 g.P("// using the provided marshal options.") 662 g.P("//") 663 g.P("// If no options are specified, call dst.MarshalFrom instead.") 664 g.P("func MarshalFrom(dst *Any, src ", protoPackage.Ident("Message"), ", opts ", protoPackage.Ident("MarshalOptions"), ") error {") 665 g.P(" const urlPrefix = \"type.googleapis.com/\"") 666 g.P(" if src == nil {") 667 g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"invalid nil source message\")") 668 g.P(" }") 669 g.P(" b, err := opts.Marshal(src)") 670 g.P(" if err != nil {") 671 g.P(" return err") 672 g.P(" }") 673 g.P(" dst.TypeUrl = urlPrefix + string(src.ProtoReflect().Descriptor().FullName())") 674 g.P(" dst.Value = b") 675 g.P(" return nil") 676 g.P("}") 677 g.P() 678 679 g.P("// UnmarshalTo unmarshals the underlying message from src into dst") 680 g.P("// using the provided unmarshal options.") 681 g.P("// It reports an error if dst is not of the right message type.") 682 g.P("//") 683 g.P("// If no options are specified, call src.UnmarshalTo instead.") 684 g.P("func UnmarshalTo(src *Any, dst ", protoPackage.Ident("Message"), ", opts ", protoPackage.Ident("UnmarshalOptions"), ") error {") 685 g.P(" if src == nil {") 686 g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"invalid nil source message\")") 687 g.P(" }") 688 g.P(" if !src.MessageIs(dst) {") 689 g.P(" got := dst.ProtoReflect().Descriptor().FullName()") 690 g.P(" want := src.MessageName()") 691 g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"mismatched message type: got %q, want %q\", got, want)") 692 g.P(" }") 693 g.P(" return opts.Unmarshal(src.GetValue(), dst)") 694 g.P("}") 695 g.P() 696 697 g.P("// UnmarshalNew unmarshals the underlying message from src into dst,") 698 g.P("// which is newly created message using a type resolved from the type URL.") 699 g.P("// The message type is resolved according to opt.Resolver,") 700 g.P("// which should implement protoregistry.MessageTypeResolver.") 701 g.P("// It reports an error if the underlying message type could not be resolved.") 702 g.P("//") 703 g.P("// If no options are specified, call src.UnmarshalNew instead.") 704 g.P("func UnmarshalNew(src *Any, opts ", protoPackage.Ident("UnmarshalOptions"), ") (dst ", protoPackage.Ident("Message"), ", err error) {") 705 g.P(" if src.GetTypeUrl() == \"\" {") 706 g.P(" return nil, ", protoimplPackage.Ident("X"), ".NewError(\"invalid empty type URL\")") 707 g.P(" }") 708 g.P(" if opts.Resolver == nil {") 709 g.P(" opts.Resolver = ", protoregistryPackage.Ident("GlobalTypes")) 710 g.P(" }") 711 g.P(" r, ok := opts.Resolver.(", protoregistryPackage.Ident("MessageTypeResolver"), ")") 712 g.P(" if !ok {") 713 g.P(" return nil, ", protoregistryPackage.Ident("NotFound")) 714 g.P(" }") 715 g.P(" mt, err := r.FindMessageByURL(src.GetTypeUrl())") 716 g.P(" if err != nil {") 717 g.P(" if err == ", protoregistryPackage.Ident("NotFound"), " {") 718 g.P(" return nil, err") 719 g.P(" }") 720 g.P(" return nil, ", protoimplPackage.Ident("X"), ".NewError(\"could not resolve %q: %v\", src.GetTypeUrl(), err)") 721 g.P(" }") 722 g.P(" dst = mt.New().Interface()") 723 g.P(" return dst, opts.Unmarshal(src.GetValue(), dst)") 724 g.P("}") 725 g.P() 726 727 g.P("// MessageIs reports whether the underlying message is of the same type as m.") 728 g.P("func (x *Any) MessageIs(m ", protoPackage.Ident("Message"), ") bool {") 729 g.P(" if m == nil {") 730 g.P(" return false") 731 g.P(" }") 732 g.P(" url := x.GetTypeUrl()") 733 g.P(" name := string(m.ProtoReflect().Descriptor().FullName())") 734 g.P(" if !", stringsPackage.Ident("HasSuffix"), "(url, name) {") 735 g.P(" return false") 736 g.P(" }") 737 g.P(" return len(url) == len(name) || url[len(url)-len(name)-1] == '/'") 738 g.P("}") 739 g.P() 740 741 g.P("// MessageName reports the full name of the underlying message,") 742 g.P("// returning an empty string if invalid.") 743 g.P("func (x *Any) MessageName() ", protoreflectPackage.Ident("FullName"), " {") 744 g.P(" url := x.GetTypeUrl()") 745 g.P(" name := ", protoreflectPackage.Ident("FullName"), "(url)") 746 g.P(" if i := ", stringsPackage.Ident("LastIndexByte"), "(url, '/'); i >= 0 {") 747 g.P(" name = name[i+len(\"/\"):]") 748 g.P(" }") 749 g.P(" if !name.IsValid() {") 750 g.P(" return \"\"") 751 g.P(" }") 752 g.P(" return name") 753 g.P("}") 754 g.P() 755 756 g.P("// MarshalFrom marshals m into x as the underlying message.") 757 g.P("func (x *Any) MarshalFrom(m ", protoPackage.Ident("Message"), ") error {") 758 g.P(" return MarshalFrom(x, m, ", protoPackage.Ident("MarshalOptions"), "{})") 759 g.P("}") 760 g.P() 761 762 g.P("// UnmarshalTo unmarshals the contents of the underlying message of x into m.") 763 g.P("// It resets m before performing the unmarshal operation.") 764 g.P("// It reports an error if m is not of the right message type.") 765 g.P("func (x *Any) UnmarshalTo(m ", protoPackage.Ident("Message"), ") error {") 766 g.P(" return UnmarshalTo(x, m, ", protoPackage.Ident("UnmarshalOptions"), "{})") 767 g.P("}") 768 g.P() 769 770 g.P("// UnmarshalNew unmarshals the contents of the underlying message of x into") 771 g.P("// a newly allocated message of the specified type.") 772 g.P("// It reports an error if the underlying message type could not be resolved.") 773 g.P("func (x *Any) UnmarshalNew() (", protoPackage.Ident("Message"), ", error) {") 774 g.P(" return UnmarshalNew(x, ", protoPackage.Ident("UnmarshalOptions"), "{})") 775 g.P("}") 776 g.P() 777 778 case genid.Timestamp_message_fullname: 779 g.P("// Now constructs a new Timestamp from the current time.") 780 g.P("func Now() *Timestamp {") 781 g.P(" return New(", timePackage.Ident("Now"), "())") 782 g.P("}") 783 g.P() 784 785 g.P("// New constructs a new Timestamp from the provided time.Time.") 786 g.P("func New(t ", timePackage.Ident("Time"), ") *Timestamp {") 787 g.P(" return &Timestamp{Seconds: int64(t.Unix()), Nanos: int32(t.Nanosecond())}") 788 g.P("}") 789 g.P() 790 791 g.P("// AsTime converts x to a time.Time.") 792 g.P("func (x *Timestamp) AsTime() ", timePackage.Ident("Time"), " {") 793 g.P(" return ", timePackage.Ident("Unix"), "(int64(x.GetSeconds()), int64(x.GetNanos())).UTC()") 794 g.P("}") 795 g.P() 796 797 g.P("// IsValid reports whether the timestamp is valid.") 798 g.P("// It is equivalent to CheckValid == nil.") 799 g.P("func (x *Timestamp) IsValid() bool {") 800 g.P(" return x.check() == 0") 801 g.P("}") 802 g.P() 803 804 g.P("// CheckValid returns an error if the timestamp is invalid.") 805 g.P("// In particular, it checks whether the value represents a date that is") 806 g.P("// in the range of 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.") 807 g.P("// An error is reported for a nil Timestamp.") 808 g.P("func (x *Timestamp) CheckValid() error {") 809 g.P(" switch x.check() {") 810 g.P(" case invalidNil:") 811 g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"invalid nil Timestamp\")") 812 g.P(" case invalidUnderflow:") 813 g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"timestamp (%v) before 0001-01-01\", x)") 814 g.P(" case invalidOverflow:") 815 g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"timestamp (%v) after 9999-12-31\", x)") 816 g.P(" case invalidNanos:") 817 g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"timestamp (%v) has out-of-range nanos\", x)") 818 g.P(" default:") 819 g.P(" return nil") 820 g.P(" }") 821 g.P("}") 822 g.P() 823 824 g.P("const (") 825 g.P(" _ = iota") 826 g.P(" invalidNil") 827 g.P(" invalidUnderflow") 828 g.P(" invalidOverflow") 829 g.P(" invalidNanos") 830 g.P(")") 831 g.P() 832 833 g.P("func (x *Timestamp) check() uint {") 834 g.P(" const minTimestamp = -62135596800 // Seconds between 1970-01-01T00:00:00Z and 0001-01-01T00:00:00Z, inclusive") 835 g.P(" const maxTimestamp = +253402300799 // Seconds between 1970-01-01T00:00:00Z and 9999-12-31T23:59:59Z, inclusive") 836 g.P(" secs := x.GetSeconds()") 837 g.P(" nanos := x.GetNanos()") 838 g.P(" switch {") 839 g.P(" case x == nil:") 840 g.P(" return invalidNil") 841 g.P(" case secs < minTimestamp:") 842 g.P(" return invalidUnderflow") 843 g.P(" case secs > maxTimestamp:") 844 g.P(" return invalidOverflow") 845 g.P(" case nanos < 0 || nanos >= 1e9:") 846 g.P(" return invalidNanos") 847 g.P(" default:") 848 g.P(" return 0") 849 g.P(" }") 850 g.P("}") 851 g.P() 852 853 case genid.Duration_message_fullname: 854 g.P("// New constructs a new Duration from the provided time.Duration.") 855 g.P("func New(d ", timePackage.Ident("Duration"), ") *Duration {") 856 g.P(" nanos := d.Nanoseconds()") 857 g.P(" secs := nanos / 1e9") 858 g.P(" nanos -= secs * 1e9") 859 g.P(" return &Duration{Seconds: int64(secs), Nanos: int32(nanos)}") 860 g.P("}") 861 g.P() 862 863 g.P("// AsDuration converts x to a time.Duration,") 864 g.P("// returning the closest duration value in the event of overflow.") 865 g.P("func (x *Duration) AsDuration() ", timePackage.Ident("Duration"), " {") 866 g.P(" secs := x.GetSeconds()") 867 g.P(" nanos := x.GetNanos()") 868 g.P(" d := ", timePackage.Ident("Duration"), "(secs) * ", timePackage.Ident("Second")) 869 g.P(" overflow := d/", timePackage.Ident("Second"), " != ", timePackage.Ident("Duration"), "(secs)") 870 g.P(" d += ", timePackage.Ident("Duration"), "(nanos) * ", timePackage.Ident("Nanosecond")) 871 g.P(" overflow = overflow || (secs < 0 && nanos < 0 && d > 0)") 872 g.P(" overflow = overflow || (secs > 0 && nanos > 0 && d < 0)") 873 g.P(" if overflow {") 874 g.P(" switch {") 875 g.P(" case secs < 0:") 876 g.P(" return ", timePackage.Ident("Duration"), "(", mathPackage.Ident("MinInt64"), ")") 877 g.P(" case secs > 0:") 878 g.P(" return ", timePackage.Ident("Duration"), "(", mathPackage.Ident("MaxInt64"), ")") 879 g.P(" }") 880 g.P(" }") 881 g.P(" return d") 882 g.P("}") 883 g.P() 884 885 g.P("// IsValid reports whether the duration is valid.") 886 g.P("// It is equivalent to CheckValid == nil.") 887 g.P("func (x *Duration) IsValid() bool {") 888 g.P(" return x.check() == 0") 889 g.P("}") 890 g.P() 891 892 g.P("// CheckValid returns an error if the duration is invalid.") 893 g.P("// In particular, it checks whether the value is within the range of") 894 g.P("// -10000 years to +10000 years inclusive.") 895 g.P("// An error is reported for a nil Duration.") 896 g.P("func (x *Duration) CheckValid() error {") 897 g.P(" switch x.check() {") 898 g.P(" case invalidNil:") 899 g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"invalid nil Duration\")") 900 g.P(" case invalidUnderflow:") 901 g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"duration (%v) exceeds -10000 years\", x)") 902 g.P(" case invalidOverflow:") 903 g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"duration (%v) exceeds +10000 years\", x)") 904 g.P(" case invalidNanosRange:") 905 g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"duration (%v) has out-of-range nanos\", x)") 906 g.P(" case invalidNanosSign:") 907 g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"duration (%v) has seconds and nanos with different signs\", x)") 908 g.P(" default:") 909 g.P(" return nil") 910 g.P(" }") 911 g.P("}") 912 g.P() 913 914 g.P("const (") 915 g.P(" _ = iota") 916 g.P(" invalidNil") 917 g.P(" invalidUnderflow") 918 g.P(" invalidOverflow") 919 g.P(" invalidNanosRange") 920 g.P(" invalidNanosSign") 921 g.P(")") 922 g.P() 923 924 g.P("func (x *Duration) check() uint {") 925 g.P(" const absDuration = 315576000000 // 10000yr * 365.25day/yr * 24hr/day * 60min/hr * 60sec/min") 926 g.P(" secs := x.GetSeconds()") 927 g.P(" nanos := x.GetNanos()") 928 g.P(" switch {") 929 g.P(" case x == nil:") 930 g.P(" return invalidNil") 931 g.P(" case secs < -absDuration:") 932 g.P(" return invalidUnderflow") 933 g.P(" case secs > +absDuration:") 934 g.P(" return invalidOverflow") 935 g.P(" case nanos <= -1e9 || nanos >= +1e9:") 936 g.P(" return invalidNanosRange") 937 g.P(" case (secs > 0 && nanos < 0) || (secs < 0 && nanos > 0):") 938 g.P(" return invalidNanosSign") 939 g.P(" default:") 940 g.P(" return 0") 941 g.P(" }") 942 g.P("}") 943 g.P() 944 945 case genid.Struct_message_fullname: 946 g.P("// NewStruct constructs a Struct from a general-purpose Go map.") 947 g.P("// The map keys must be valid UTF-8.") 948 g.P("// The map values are converted using NewValue.") 949 g.P("func NewStruct(v map[string]interface{}) (*Struct, error) {") 950 g.P(" x := &Struct{Fields: make(map[string]*Value, len(v))}") 951 g.P(" for k, v := range v {") 952 g.P(" if !", utf8Package.Ident("ValidString"), "(k) {") 953 g.P(" return nil, ", protoimplPackage.Ident("X"), ".NewError(\"invalid UTF-8 in string: %q\", k)") 954 g.P(" }") 955 g.P(" var err error") 956 g.P(" x.Fields[k], err = NewValue(v)") 957 g.P(" if err != nil {") 958 g.P(" return nil, err") 959 g.P(" }") 960 g.P(" }") 961 g.P(" return x, nil") 962 g.P("}") 963 g.P() 964 965 g.P("// AsMap converts x to a general-purpose Go map.") 966 g.P("// The map values are converted by calling Value.AsInterface.") 967 g.P("func (x *Struct) AsMap() map[string]interface{} {") 968 g.P(" vs := make(map[string]interface{})") 969 g.P(" for k, v := range x.GetFields() {") 970 g.P(" vs[k] = v.AsInterface()") 971 g.P(" }") 972 g.P(" return vs") 973 g.P("}") 974 g.P() 975 976 g.P("func (x *Struct) MarshalJSON() ([]byte, error) {") 977 g.P(" return ", protojsonPackage.Ident("Marshal"), "(x)") 978 g.P("}") 979 g.P() 980 981 g.P("func (x *Struct) UnmarshalJSON(b []byte) error {") 982 g.P(" return ", protojsonPackage.Ident("Unmarshal"), "(b, x)") 983 g.P("}") 984 g.P() 985 986 case genid.ListValue_message_fullname: 987 g.P("// NewList constructs a ListValue from a general-purpose Go slice.") 988 g.P("// The slice elements are converted using NewValue.") 989 g.P("func NewList(v []interface{}) (*ListValue, error) {") 990 g.P(" x := &ListValue{Values: make([]*Value, len(v))}") 991 g.P(" for i, v := range v {") 992 g.P(" var err error") 993 g.P(" x.Values[i], err = NewValue(v)") 994 g.P(" if err != nil {") 995 g.P(" return nil, err") 996 g.P(" }") 997 g.P(" }") 998 g.P(" return x, nil") 999 g.P("}") 1000 g.P() 1001 1002 g.P("// AsSlice converts x to a general-purpose Go slice.") 1003 g.P("// The slice elements are converted by calling Value.AsInterface.") 1004 g.P("func (x *ListValue) AsSlice() []interface{} {") 1005 g.P(" vs := make([]interface{}, len(x.GetValues()))") 1006 g.P(" for i, v := range x.GetValues() {") 1007 g.P(" vs[i] = v.AsInterface()") 1008 g.P(" }") 1009 g.P(" return vs") 1010 g.P("}") 1011 g.P() 1012 1013 g.P("func (x *ListValue) MarshalJSON() ([]byte, error) {") 1014 g.P(" return ", protojsonPackage.Ident("Marshal"), "(x)") 1015 g.P("}") 1016 g.P() 1017 1018 g.P("func (x *ListValue) UnmarshalJSON(b []byte) error {") 1019 g.P(" return ", protojsonPackage.Ident("Unmarshal"), "(b, x)") 1020 g.P("}") 1021 g.P() 1022 1023 case genid.Value_message_fullname: 1024 g.P("// NewValue constructs a Value from a general-purpose Go interface.") 1025 g.P("//") 1026 g.P("// ╔════════════════════════╤════════════════════════════════════════════╗") 1027 g.P("// ║ Go type │ Conversion ║") 1028 g.P("// ╠════════════════════════╪════════════════════════════════════════════╣") 1029 g.P("// ║ nil │ stored as NullValue ║") 1030 g.P("// ║ bool │ stored as BoolValue ║") 1031 g.P("// ║ int, int32, int64 │ stored as NumberValue ║") 1032 g.P("// ║ uint, uint32, uint64 │ stored as NumberValue ║") 1033 g.P("// ║ float32, float64 │ stored as NumberValue ║") 1034 g.P("// ║ string │ stored as StringValue; must be valid UTF-8 ║") 1035 g.P("// ║ []byte │ stored as StringValue; base64-encoded ║") 1036 g.P("// ║ map[string]interface{} │ stored as StructValue ║") 1037 g.P("// ║ []interface{} │ stored as ListValue ║") 1038 g.P("// ╚════════════════════════╧════════════════════════════════════════════╝") 1039 g.P("//") 1040 g.P("// When converting an int64 or uint64 to a NumberValue, numeric precision loss") 1041 g.P("// is possible since they are stored as a float64.") 1042 g.P("func NewValue(v interface{}) (*Value, error) {") 1043 g.P(" switch v := v.(type) {") 1044 g.P(" case nil:") 1045 g.P(" return NewNullValue(), nil") 1046 g.P(" case bool:") 1047 g.P(" return NewBoolValue(v), nil") 1048 g.P(" case int:") 1049 g.P(" return NewNumberValue(float64(v)), nil") 1050 g.P(" case int32:") 1051 g.P(" return NewNumberValue(float64(v)), nil") 1052 g.P(" case int64:") 1053 g.P(" return NewNumberValue(float64(v)), nil") 1054 g.P(" case uint:") 1055 g.P(" return NewNumberValue(float64(v)), nil") 1056 g.P(" case uint32:") 1057 g.P(" return NewNumberValue(float64(v)), nil") 1058 g.P(" case uint64:") 1059 g.P(" return NewNumberValue(float64(v)), nil") 1060 g.P(" case float32:") 1061 g.P(" return NewNumberValue(float64(v)), nil") 1062 g.P(" case float64:") 1063 g.P(" return NewNumberValue(float64(v)), nil") 1064 g.P(" case string:") 1065 g.P(" if !", utf8Package.Ident("ValidString"), "(v) {") 1066 g.P(" return nil, ", protoimplPackage.Ident("X"), ".NewError(\"invalid UTF-8 in string: %q\", v)") 1067 g.P(" }") 1068 g.P(" return NewStringValue(v), nil") 1069 g.P(" case []byte:") 1070 g.P(" s := ", base64Package.Ident("StdEncoding"), ".EncodeToString(v)") 1071 g.P(" return NewStringValue(s), nil") 1072 g.P(" case map[string]interface{}:") 1073 g.P(" v2, err := NewStruct(v)") 1074 g.P(" if err != nil {") 1075 g.P(" return nil, err") 1076 g.P(" }") 1077 g.P(" return NewStructValue(v2), nil") 1078 g.P(" case []interface{}:") 1079 g.P(" v2, err := NewList(v)") 1080 g.P(" if err != nil {") 1081 g.P(" return nil, err") 1082 g.P(" }") 1083 g.P(" return NewListValue(v2), nil") 1084 g.P(" default:") 1085 g.P(" return nil, ", protoimplPackage.Ident("X"), ".NewError(\"invalid type: %T\", v)") 1086 g.P(" }") 1087 g.P("}") 1088 g.P() 1089 1090 g.P("// NewNullValue constructs a new null Value.") 1091 g.P("func NewNullValue() *Value {") 1092 g.P(" return &Value{Kind: &Value_NullValue{NullValue: NullValue_NULL_VALUE}}") 1093 g.P("}") 1094 g.P() 1095 1096 g.P("// NewBoolValue constructs a new boolean Value.") 1097 g.P("func NewBoolValue(v bool) *Value {") 1098 g.P(" return &Value{Kind: &Value_BoolValue{BoolValue: v}}") 1099 g.P("}") 1100 g.P() 1101 1102 g.P("// NewNumberValue constructs a new number Value.") 1103 g.P("func NewNumberValue(v float64) *Value {") 1104 g.P(" return &Value{Kind: &Value_NumberValue{NumberValue: v}}") 1105 g.P("}") 1106 g.P() 1107 1108 g.P("// NewStringValue constructs a new string Value.") 1109 g.P("func NewStringValue(v string) *Value {") 1110 g.P(" return &Value{Kind: &Value_StringValue{StringValue: v}}") 1111 g.P("}") 1112 g.P() 1113 1114 g.P("// NewStructValue constructs a new struct Value.") 1115 g.P("func NewStructValue(v *Struct) *Value {") 1116 g.P(" return &Value{Kind: &Value_StructValue{StructValue: v}}") 1117 g.P("}") 1118 g.P() 1119 1120 g.P("// NewListValue constructs a new list Value.") 1121 g.P("func NewListValue(v *ListValue) *Value {") 1122 g.P(" return &Value{Kind: &Value_ListValue{ListValue: v}}") 1123 g.P("}") 1124 g.P() 1125 1126 g.P("// AsInterface converts x to a general-purpose Go interface.") 1127 g.P("//") 1128 g.P("// Calling Value.MarshalJSON and \"encoding/json\".Marshal on this output produce") 1129 g.P("// semantically equivalent JSON (assuming no errors occur).") 1130 g.P("//") 1131 g.P("// Floating-point values (i.e., \"NaN\", \"Infinity\", and \"-Infinity\") are") 1132 g.P("// converted as strings to remain compatible with MarshalJSON.") 1133 g.P("func (x *Value) AsInterface() interface{} {") 1134 g.P(" switch v := x.GetKind().(type) {") 1135 g.P(" case *Value_NumberValue:") 1136 g.P(" if v != nil {") 1137 g.P(" switch {") 1138 g.P(" case ", mathPackage.Ident("IsNaN"), "(v.NumberValue):") 1139 g.P(" return \"NaN\"") 1140 g.P(" case ", mathPackage.Ident("IsInf"), "(v.NumberValue, +1):") 1141 g.P(" return \"Infinity\"") 1142 g.P(" case ", mathPackage.Ident("IsInf"), "(v.NumberValue, -1):") 1143 g.P(" return \"-Infinity\"") 1144 g.P(" default:") 1145 g.P(" return v.NumberValue") 1146 g.P(" }") 1147 g.P(" }") 1148 g.P(" case *Value_StringValue:") 1149 g.P(" if v != nil {") 1150 g.P(" return v.StringValue") 1151 g.P(" }") 1152 g.P(" case *Value_BoolValue:") 1153 g.P(" if v != nil {") 1154 g.P(" return v.BoolValue") 1155 g.P(" }") 1156 g.P(" case *Value_StructValue:") 1157 g.P(" if v != nil {") 1158 g.P(" return v.StructValue.AsMap()") 1159 g.P(" }") 1160 g.P(" case *Value_ListValue:") 1161 g.P(" if v != nil {") 1162 g.P(" return v.ListValue.AsSlice()") 1163 g.P(" }") 1164 g.P(" }") 1165 g.P(" return nil") 1166 g.P("}") 1167 g.P() 1168 1169 g.P("func (x *Value) MarshalJSON() ([]byte, error) {") 1170 g.P(" return ", protojsonPackage.Ident("Marshal"), "(x)") 1171 g.P("}") 1172 g.P() 1173 1174 g.P("func (x *Value) UnmarshalJSON(b []byte) error {") 1175 g.P(" return ", protojsonPackage.Ident("Unmarshal"), "(b, x)") 1176 g.P("}") 1177 g.P() 1178 1179 case genid.FieldMask_message_fullname: 1180 g.P("// New constructs a field mask from a list of paths and verifies that") 1181 g.P("// each one is valid according to the specified message type.") 1182 g.P("func New(m ", protoPackage.Ident("Message"), ", paths ...string) (*FieldMask, error) {") 1183 g.P(" x := new(FieldMask)") 1184 g.P(" return x, x.Append(m, paths...)") 1185 g.P("}") 1186 g.P() 1187 1188 g.P("// Union returns the union of all the paths in the input field masks.") 1189 g.P("func Union(mx *FieldMask, my *FieldMask, ms ...*FieldMask) *FieldMask {") 1190 g.P(" var out []string") 1191 g.P(" out = append(out, mx.GetPaths()...)") 1192 g.P(" out = append(out, my.GetPaths()...)") 1193 g.P(" for _, m := range ms {") 1194 g.P(" out = append(out, m.GetPaths()...)") 1195 g.P(" }") 1196 g.P(" return &FieldMask{Paths: normalizePaths(out)}") 1197 g.P("}") 1198 g.P() 1199 1200 g.P("// Intersect returns the intersection of all the paths in the input field masks.") 1201 g.P("func Intersect(mx *FieldMask, my *FieldMask, ms ...*FieldMask) *FieldMask {") 1202 g.P(" var ss1, ss2 []string // reused buffers for performance") 1203 g.P(" intersect := func(out, in []string) []string {") 1204 g.P(" ss1 = normalizePaths(append(ss1[:0], in...))") 1205 g.P(" ss2 = normalizePaths(append(ss2[:0], out...))") 1206 g.P(" out = out[:0]") 1207 g.P(" for i1, i2 := 0, 0; i1 < len(ss1) && i2 < len(ss2); {") 1208 g.P(" switch s1, s2 := ss1[i1], ss2[i2]; {") 1209 g.P(" case hasPathPrefix(s1, s2):") 1210 g.P(" out = append(out, s1)") 1211 g.P(" i1++") 1212 g.P(" case hasPathPrefix(s2, s1):") 1213 g.P(" out = append(out, s2)") 1214 g.P(" i2++") 1215 g.P(" case lessPath(s1, s2):") 1216 g.P(" i1++") 1217 g.P(" case lessPath(s2, s1):") 1218 g.P(" i2++") 1219 g.P(" }") 1220 g.P(" }") 1221 g.P(" return out") 1222 g.P(" }") 1223 g.P() 1224 g.P(" out := Union(mx, my, ms...).GetPaths()") 1225 g.P(" out = intersect(out, mx.GetPaths())") 1226 g.P(" out = intersect(out, my.GetPaths())") 1227 g.P(" for _, m := range ms {") 1228 g.P(" out = intersect(out, m.GetPaths())") 1229 g.P(" }") 1230 g.P(" return &FieldMask{Paths: normalizePaths(out)}") 1231 g.P("}") 1232 g.P() 1233 1234 g.P("// IsValid reports whether all the paths are syntactically valid and") 1235 g.P("// refer to known fields in the specified message type.") 1236 g.P("// It reports false for a nil FieldMask.") 1237 g.P("func (x *FieldMask) IsValid(m ", protoPackage.Ident("Message"), ") bool {") 1238 g.P(" paths := x.GetPaths()") 1239 g.P(" return x != nil && numValidPaths(m, paths) == len(paths)") 1240 g.P("}") 1241 g.P() 1242 1243 g.P("// Append appends a list of paths to the mask and verifies that each one") 1244 g.P("// is valid according to the specified message type.") 1245 g.P("// An invalid path is not appended and breaks insertion of subsequent paths.") 1246 g.P("func (x *FieldMask) Append(m ", protoPackage.Ident("Message"), ", paths ...string) error {") 1247 g.P(" numValid := numValidPaths(m, paths)") 1248 g.P(" x.Paths = append(x.Paths, paths[:numValid]...)") 1249 g.P(" paths = paths[numValid:]") 1250 g.P(" if len(paths) > 0 {") 1251 g.P(" name := m.ProtoReflect().Descriptor().FullName()") 1252 g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"invalid path %q for message %q\", paths[0], name)") 1253 g.P(" }") 1254 g.P(" return nil") 1255 g.P("}") 1256 g.P() 1257 1258 g.P("func numValidPaths(m ", protoPackage.Ident("Message"), ", paths []string) int {") 1259 g.P(" md0 := m.ProtoReflect().Descriptor()") 1260 g.P(" for i, path := range paths {") 1261 g.P(" md := md0") 1262 g.P(" if !rangeFields(path, func(field string) bool {") 1263 g.P(" // Search the field within the message.") 1264 g.P(" if md == nil {") 1265 g.P(" return false // not within a message") 1266 g.P(" }") 1267 g.P(" fd := md.Fields().ByName(", protoreflectPackage.Ident("Name"), "(field))") 1268 g.P(" // The real field name of a group is the message name.") 1269 g.P(" if fd == nil {") 1270 g.P(" gd := md.Fields().ByName(", protoreflectPackage.Ident("Name"), "(", stringsPackage.Ident("ToLower"), "(field)))") 1271 g.P(" if gd != nil && gd.Kind() == ", protoreflectPackage.Ident("GroupKind"), " && string(gd.Message().Name()) == field {") 1272 g.P(" fd = gd") 1273 g.P(" }") 1274 g.P(" } else if fd.Kind() == ", protoreflectPackage.Ident("GroupKind"), " && string(fd.Message().Name()) != field {") 1275 g.P(" fd = nil") 1276 g.P(" }") 1277 g.P(" if fd == nil {") 1278 g.P(" return false // message has does not have this field") 1279 g.P(" }") 1280 g.P() 1281 g.P(" // Identify the next message to search within.") 1282 g.P(" md = fd.Message() // may be nil") 1283 g.P() 1284 g.P(" // Repeated fields are only allowed at the last postion.") 1285 g.P(" if fd.IsList() || fd.IsMap() {") 1286 g.P(" md = nil") 1287 g.P(" }") 1288 g.P() 1289 g.P(" return true") 1290 g.P(" }) {") 1291 g.P(" return i") 1292 g.P(" }") 1293 g.P(" }") 1294 g.P(" return len(paths)") 1295 g.P("}") 1296 g.P() 1297 1298 g.P("// Normalize converts the mask to its canonical form where all paths are sorted") 1299 g.P("// and redundant paths are removed.") 1300 g.P("func (x *FieldMask) Normalize() {") 1301 g.P(" x.Paths = normalizePaths(x.Paths)") 1302 g.P("}") 1303 g.P() 1304 g.P("func normalizePaths(paths []string) []string {") 1305 g.P(" ", sortPackage.Ident("Slice"), "(paths, func(i, j int) bool {") 1306 g.P(" return lessPath(paths[i], paths[j])") 1307 g.P(" })") 1308 g.P() 1309 g.P(" // Elide any path that is a prefix match on the previous.") 1310 g.P(" out := paths[:0]") 1311 g.P(" for _, path := range paths {") 1312 g.P(" if len(out) > 0 && hasPathPrefix(path, out[len(out)-1]) {") 1313 g.P(" continue") 1314 g.P(" }") 1315 g.P(" out = append(out, path)") 1316 g.P(" }") 1317 g.P(" return out") 1318 g.P("}") 1319 g.P() 1320 1321 g.P("// hasPathPrefix is like strings.HasPrefix, but further checks for either") 1322 g.P("// an exact matche or that the prefix is delimited by a dot.") 1323 g.P("func hasPathPrefix(path, prefix string) bool {") 1324 g.P(" return ", stringsPackage.Ident("HasPrefix"), "(path, prefix) && (len(path) == len(prefix) || path[len(prefix)] == '.')") 1325 g.P("}") 1326 g.P() 1327 1328 g.P("// lessPath is a lexicographical comparison where dot is specially treated") 1329 g.P("// as the smallest symbol.") 1330 g.P("func lessPath(x, y string) bool {") 1331 g.P(" for i := 0; i < len(x) && i < len(y); i++ {") 1332 g.P(" if x[i] != y[i] {") 1333 g.P(" return (x[i] - '.') < (y[i] - '.')") 1334 g.P(" }") 1335 g.P(" }") 1336 g.P(" return len(x) < len(y)") 1337 g.P("}") 1338 g.P() 1339 1340 g.P("// rangeFields is like strings.Split(path, \".\"), but avoids allocations by") 1341 g.P("// iterating over each field in place and calling a iterator function.") 1342 g.P("func rangeFields(path string, f func(field string) bool) bool {") 1343 g.P(" for {") 1344 g.P(" var field string") 1345 g.P(" if i := ", stringsPackage.Ident("IndexByte"), "(path, '.'); i >= 0 {") 1346 g.P(" field, path = path[:i], path[i:]") 1347 g.P(" } else {") 1348 g.P(" field, path = path, \"\"") 1349 g.P(" }") 1350 g.P() 1351 g.P(" if !f(field) {") 1352 g.P(" return false") 1353 g.P(" }") 1354 g.P() 1355 g.P(" if len(path) == 0 {") 1356 g.P(" return true") 1357 g.P(" }") 1358 g.P(" path = ", stringsPackage.Ident("TrimPrefix"), "(path, \".\")") 1359 g.P(" }") 1360 g.P("}") 1361 g.P() 1362 1363 case genid.BoolValue_message_fullname, 1364 genid.Int32Value_message_fullname, 1365 genid.Int64Value_message_fullname, 1366 genid.UInt32Value_message_fullname, 1367 genid.UInt64Value_message_fullname, 1368 genid.FloatValue_message_fullname, 1369 genid.DoubleValue_message_fullname, 1370 genid.StringValue_message_fullname, 1371 genid.BytesValue_message_fullname: 1372 funcName := strings.TrimSuffix(m.GoIdent.GoName, "Value") 1373 typeName := strings.ToLower(funcName) 1374 switch typeName { 1375 case "float": 1376 typeName = "float32" 1377 case "double": 1378 typeName = "float64" 1379 case "bytes": 1380 typeName = "[]byte" 1381 } 1382 1383 g.P("// ", funcName, " stores v in a new ", m.GoIdent, " and returns a pointer to it.") 1384 g.P("func ", funcName, "(v ", typeName, ") *", m.GoIdent, " {") 1385 g.P(" return &", m.GoIdent, "{Value: v}") 1386 g.P("}") 1387 g.P() 1388 } 1389 } 1390 1391 func genMessageFields(g *generator.GeneratedFile, f *fileInfo, m *messageInfo) { 1392 sf := f.allMessageFieldsByPtr[m] 1393 genMessageInternalFields(g, f, m, sf) 1394 for _, field := range m.Fields { 1395 genMessageField(g, f, m, field, sf) 1396 } 1397 } 1398 1399 func genMessageInternalFields(g *generator.GeneratedFile, f *fileInfo, m *messageInfo, sf *structFields) { 1400 g.P(genid.State_goname, " ", protoimplPackage.Ident("MessageState")) 1401 sf.append(genid.State_goname) 1402 g.P(genid.SizeCache_goname, " ", protoimplPackage.Ident("SizeCache")) 1403 sf.append(genid.SizeCache_goname) 1404 if m.hasWeak { 1405 g.P(genid.WeakFields_goname, " ", protoimplPackage.Ident("WeakFields")) 1406 sf.append(genid.WeakFields_goname) 1407 } 1408 g.P(genid.UnknownFields_goname, " ", protoimplPackage.Ident("UnknownFields")) 1409 sf.append(genid.UnknownFields_goname) 1410 if m.Desc.ExtensionRanges().Len() > 0 { 1411 g.P(genid.ExtensionFields_goname, " ", protoimplPackage.Ident("ExtensionFields")) 1412 sf.append(genid.ExtensionFields_goname) 1413 } 1414 if sf.count > 0 { 1415 g.P() 1416 } 1417 } 1418 1419 func genMessageField(g *generator.GeneratedFile, f *fileInfo, m *messageInfo, field *protogen.Field, sf *structFields) { 1420 if oneof := field.Oneof; oneof != nil && !oneof.Desc.IsSynthetic() { 1421 // It would be a bit simpler to iterate over the oneofs below, 1422 // but generating the field here keeps the contents of the Go 1423 // struct in the same order as the contents of the source 1424 // .proto file. 1425 if oneof.Fields[0] != field { 1426 return // only generate for first appearance 1427 } 1428 1429 tags := structTags{ 1430 {"protobuf_oneof", string(oneof.Desc.Name())}, 1431 } 1432 if m.isTracked { 1433 tags = append(tags, gotrackTags...) 1434 } 1435 1436 g.Annotate(m.GoIdent.GoName+"."+oneof.GoName, oneof.Location) 1437 leadingComments := oneof.Comments.Leading 1438 if leadingComments != "" { 1439 leadingComments += "\n" 1440 } 1441 ss := []string{fmt.Sprintf(" Types that are assignable to %s:\n", oneof.GoName)} 1442 for _, field := range oneof.Fields { 1443 ss = append(ss, "\t*"+field.GoIdent.GoName+"\n") 1444 } 1445 leadingComments += protogen.Comments(strings.Join(ss, "")) 1446 g.P(leadingComments, 1447 oneof.GoName, " ", oneofInterfaceName(oneof), tags) 1448 sf.append(oneof.GoName) 1449 return 1450 } 1451 goType, pointer := fieldGoType(g, f, field) 1452 if pointer { 1453 goType = "*" + goType 1454 } 1455 tags := structTags{ 1456 {"protobuf", fieldProtobufTagValue(field)}, 1457 {"json", fieldJSONTagValue(field)}, 1458 } 1459 if field.Desc.IsMap() { 1460 key := field.Message.Fields[0] 1461 val := field.Message.Fields[1] 1462 tags = append(tags, structTags{ 1463 {"protobuf_key", fieldProtobufTagValue(key)}, 1464 {"protobuf_val", fieldProtobufTagValue(val)}, 1465 }...) 1466 } 1467 if m.isTracked { 1468 tags = append(tags, gotrackTags...) 1469 } 1470 1471 name := field.GoName 1472 if field.Desc.IsWeak() { 1473 name = genid.WeakFieldPrefix_goname + name 1474 } 1475 g.Annotate(m.GoIdent.GoName+"."+name, field.Location) 1476 leadingComments := appendDeprecationSuffix(field.Comments.Leading, 1477 field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated()) 1478 g.P(leadingComments, 1479 name, " ", goType, tags, 1480 trailingComment(field.Comments.Trailing)) 1481 sf.append(field.GoName) 1482 } 1483 1484 // genMessageDefaultDecls generates consts and vars holding the default 1485 // values of fields. 1486 func genMessageDefaultDecls(g *generator.GeneratedFile, f *fileInfo, m *messageInfo) { 1487 var consts, vars []string 1488 for _, field := range m.Fields { 1489 if !field.Desc.HasDefault() { 1490 continue 1491 } 1492 name := "Default_" + m.GoIdent.GoName + "_" + field.GoName 1493 goType, _ := fieldGoType(g, f, field) 1494 defVal := field.Desc.Default() 1495 switch field.Desc.Kind() { 1496 case protoreflect.StringKind: 1497 consts = append(consts, fmt.Sprintf("%s = %s(%q)", name, goType, defVal.String())) 1498 case protoreflect.BytesKind: 1499 vars = append(vars, fmt.Sprintf("%s = %s(%q)", name, goType, defVal.Bytes())) 1500 case protoreflect.EnumKind: 1501 idx := field.Desc.DefaultEnumValue().Index() 1502 val := field.Enum.Values[idx] 1503 if val.GoIdent.GoImportPath == f.GoImportPath { 1504 consts = append(consts, fmt.Sprintf("%s = %s", name, g.QualifiedGoIdent(val.GoIdent))) 1505 } else { 1506 // If the enum value is declared in a different Go package, 1507 // reference it by number since the name may not be correct. 1508 // See https://github.com/golang/protobuf/issues/513. 1509 consts = append(consts, fmt.Sprintf("%s = %s(%d) // %s", 1510 name, g.QualifiedGoIdent(field.Enum.GoIdent), val.Desc.Number(), g.QualifiedGoIdent(val.GoIdent))) 1511 } 1512 case protoreflect.FloatKind, protoreflect.DoubleKind: 1513 if f := defVal.Float(); math.IsNaN(f) || math.IsInf(f, 0) { 1514 var fn, arg string 1515 switch f := defVal.Float(); { 1516 case math.IsInf(f, -1): 1517 fn, arg = g.QualifiedGoIdent(mathPackage.Ident("Inf")), "-1" 1518 case math.IsInf(f, +1): 1519 fn, arg = g.QualifiedGoIdent(mathPackage.Ident("Inf")), "+1" 1520 case math.IsNaN(f): 1521 fn, arg = g.QualifiedGoIdent(mathPackage.Ident("NaN")), "" 1522 } 1523 vars = append(vars, fmt.Sprintf("%s = %s(%s(%s))", name, goType, fn, arg)) 1524 } else { 1525 consts = append(consts, fmt.Sprintf("%s = %s(%v)", name, goType, f)) 1526 } 1527 default: 1528 consts = append(consts, fmt.Sprintf("%s = %s(%v)", name, goType, defVal.Interface())) 1529 } 1530 } 1531 if len(consts) > 0 { 1532 g.P("// Default values for ", m.GoIdent, " fields.") 1533 g.P("const (") 1534 for _, s := range consts { 1535 g.P(s) 1536 } 1537 g.P(")") 1538 } 1539 if len(vars) > 0 { 1540 g.P("// Default values for ", m.GoIdent, " fields.") 1541 g.P("var (") 1542 for _, s := range vars { 1543 g.P(s) 1544 } 1545 g.P(")") 1546 } 1547 g.P() 1548 } 1549 1550 func genMessageMethods(g *generator.GeneratedFile, f *fileInfo, m *messageInfo) { 1551 genMessageBaseMethods(g, f, m) 1552 genMessageGetterMethods(g, f, m) 1553 genMessageSetterMethods(g, f, m) 1554 } 1555 1556 func genMessageBaseMethods(g *generator.GeneratedFile, f *fileInfo, m *messageInfo) { 1557 // Reset method. 1558 g.P("func (x *", m.GoIdent, ") Reset() {") 1559 g.P("*x = ", m.GoIdent, "{}") 1560 g.P("if ", protoimplPackage.Ident("UnsafeEnabled"), " {") 1561 g.P("mi := &", messageTypesVarName(f), "[", f.allMessagesByPtr[m], "]") 1562 g.P("ms := ", protoimplPackage.Ident("X"), ".MessageStateOf(", protoimplPackage.Ident("Pointer"), "(x))") 1563 g.P("ms.StoreMessageInfo(mi)") 1564 g.P("}") 1565 g.P("}") 1566 g.P() 1567 1568 // String method. 1569 g.P("func (x *", m.GoIdent, ") String() string {") 1570 g.P("return ", protoimplPackage.Ident("X"), ".MessageStringOf(x)") 1571 g.P("}") 1572 g.P() 1573 1574 // ProtoMessage method. 1575 g.P("func (*", m.GoIdent, ") ProtoMessage() {}") 1576 g.P() 1577 1578 // ProtoReflect method. 1579 genMessageReflectMethods(g, f, m) 1580 1581 // Descriptor method. 1582 if m.genRawDescMethod { 1583 var indexes []string 1584 for i := 1; i < len(m.Location.Path); i += 2 { 1585 indexes = append(indexes, strconv.Itoa(int(m.Location.Path[i]))) 1586 } 1587 g.P("// Deprecated: Use ", m.GoIdent, ".ProtoReflect.Descriptor instead.") 1588 g.P("func (*", m.GoIdent, ") Descriptor() ([]byte, []int) {") 1589 g.P("return ", rawDescVarName(f), "GZIP(), []int{", strings.Join(indexes, ","), "}") 1590 g.P("}") 1591 g.P() 1592 f.needRawDesc = true 1593 } 1594 } 1595 1596 func genMessageGetterMethods(g *generator.GeneratedFile, f *fileInfo, m *messageInfo) { 1597 for _, field := range m.Fields { 1598 genNoInterfacePragma(g, m.isTracked) 1599 1600 // Getter for parent oneof. 1601 if oneof := field.Oneof; oneof != nil && oneof.Fields[0] == field && !oneof.Desc.IsSynthetic() { 1602 g.Annotate(m.GoIdent.GoName+".Get"+oneof.GoName, oneof.Location) 1603 g.P("func (x *", m.GoIdent.GoName, ") Get", oneof.GoName, "() ", oneofInterfaceName(oneof), " {") 1604 g.P("if x != nil {") 1605 g.P("return x.", oneof.GoName) 1606 g.P("}") 1607 g.P("return nil") 1608 g.P("}") 1609 g.P() 1610 } 1611 1612 // Getter for message field. 1613 goType, pointer := fieldGoType(g, f, field) 1614 defaultValue := fieldDefaultValue(g, f, m, field) 1615 g.Annotate(m.GoIdent.GoName+".Get"+field.GoName, field.Location) 1616 leadingComments := appendDeprecationSuffix("", 1617 field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated()) 1618 switch { 1619 case field.Desc.IsWeak(): 1620 g.P(leadingComments, "func (x *", m.GoIdent, ") Get", field.GoName, "() ", protoPackage.Ident("Message"), "{") 1621 g.P("var w ", protoimplPackage.Ident("WeakFields")) 1622 g.P("if x != nil {") 1623 g.P("w = x.", genid.WeakFields_goname) 1624 if m.isTracked { 1625 g.P("_ = x.", genid.WeakFieldPrefix_goname+field.GoName) 1626 } 1627 g.P("}") 1628 g.P("return ", protoimplPackage.Ident("X"), ".GetWeak(w, ", field.Desc.Number(), ", ", strconv.Quote(string(field.Message.Desc.FullName())), ")") 1629 g.P("}") 1630 case field.Oneof != nil && !field.Oneof.Desc.IsSynthetic(): 1631 g.P(leadingComments, "func (x *", m.GoIdent, ") Get", field.GoName, "() ", goType, " {") 1632 g.P("if x, ok := x.Get", field.Oneof.GoName, "().(*", field.GoIdent, "); ok {") 1633 g.P("return x.", field.GoName) 1634 g.P("}") 1635 g.P("return ", defaultValue) 1636 g.P("}") 1637 default: 1638 g.P(leadingComments, "func (x *", m.GoIdent, ") Get", field.GoName, "() ", goType, " {") 1639 if !field.Desc.HasPresence() || defaultValue == "nil" { 1640 g.P("if x != nil {") 1641 } else { 1642 g.P("if x != nil && x.", field.GoName, " != nil {") 1643 } 1644 star := "" 1645 if pointer { 1646 star = "*" 1647 } 1648 g.P("return ", star, " x.", field.GoName) 1649 g.P("}") 1650 g.P("return ", defaultValue) 1651 g.P("}") 1652 } 1653 g.P() 1654 } 1655 } 1656 1657 func genMessageSetterMethods(g *generator.GeneratedFile, f *fileInfo, m *messageInfo) { 1658 for _, field := range m.Fields { 1659 if !field.Desc.IsWeak() { 1660 continue 1661 } 1662 1663 genNoInterfacePragma(g, m.isTracked) 1664 1665 g.Annotate(m.GoIdent.GoName+".Set"+field.GoName, field.Location) 1666 leadingComments := appendDeprecationSuffix("", 1667 field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated()) 1668 g.P(leadingComments, "func (x *", m.GoIdent, ") Set", field.GoName, "(v ", protoPackage.Ident("Message"), ") {") 1669 g.P("var w *", protoimplPackage.Ident("WeakFields")) 1670 g.P("if x != nil {") 1671 g.P("w = &x.", genid.WeakFields_goname) 1672 if m.isTracked { 1673 g.P("_ = x.", genid.WeakFieldPrefix_goname+field.GoName) 1674 } 1675 g.P("}") 1676 g.P(protoimplPackage.Ident("X"), ".SetWeak(w, ", field.Desc.Number(), ", ", strconv.Quote(string(field.Message.Desc.FullName())), ", v)") 1677 g.P("}") 1678 g.P() 1679 } 1680 } 1681 1682 // fieldGoType returns the Go type used for a field. 1683 // 1684 // If it returns pointer=true, the struct field is a pointer to the type. 1685 func fieldGoType(g *generator.GeneratedFile, f *fileInfo, field *protogen.Field) (goType string, pointer bool) { 1686 if field.Desc.IsWeak() { 1687 return "struct{}", false 1688 } 1689 1690 pointer = field.Desc.HasPresence() 1691 switch field.Desc.Kind() { 1692 case protoreflect.BoolKind: 1693 goType = "bool" 1694 case protoreflect.EnumKind: 1695 goType = g.QualifiedGoIdent(field.Enum.GoIdent) 1696 case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: 1697 goType = "int32" 1698 case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: 1699 goType = "uint32" 1700 case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: 1701 goType = "int64" 1702 case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: 1703 goType = "uint64" 1704 case protoreflect.FloatKind: 1705 goType = "float32" 1706 case protoreflect.DoubleKind: 1707 goType = "float64" 1708 case protoreflect.StringKind: 1709 goType = "string" 1710 case protoreflect.BytesKind: 1711 goType = "[]byte" 1712 pointer = false // rely on nullability of slices for presence 1713 case protoreflect.MessageKind, protoreflect.GroupKind: 1714 goType = "*" + g.QualifiedGoIdent(field.Message.GoIdent) 1715 pointer = false // pointer captured as part of the type 1716 } 1717 switch { 1718 case field.Desc.IsList(): 1719 return "[]" + goType, false 1720 case field.Desc.IsMap(): 1721 keyType, _ := fieldGoType(g, f, field.Message.Fields[0]) 1722 valType, _ := fieldGoType(g, f, field.Message.Fields[1]) 1723 return fmt.Sprintf("map[%v]%v", keyType, valType), false 1724 } 1725 return goType, pointer 1726 } 1727 1728 func fieldProtobufTagValue(field *protogen.Field) string { 1729 var enumName string 1730 if field.Desc.Kind() == protoreflect.EnumKind { 1731 enumName = protoimpl.X.LegacyEnumName(field.Enum.Desc) 1732 } 1733 return TagMarshal(field.Desc, enumName) 1734 } 1735 1736 func fieldDefaultValue(g *generator.GeneratedFile, f *fileInfo, m *messageInfo, field *protogen.Field) string { 1737 if field.Desc.IsList() { 1738 return "nil" 1739 } 1740 if field.Desc.HasDefault() { 1741 defVarName := "Default_" + m.GoIdent.GoName + "_" + field.GoName 1742 if field.Desc.Kind() == protoreflect.BytesKind { 1743 return "append([]byte(nil), " + defVarName + "...)" 1744 } 1745 return defVarName 1746 } 1747 switch field.Desc.Kind() { 1748 case protoreflect.BoolKind: 1749 return "false" 1750 case protoreflect.StringKind: 1751 return `""` 1752 case protoreflect.MessageKind, protoreflect.GroupKind, protoreflect.BytesKind: 1753 return "nil" 1754 case protoreflect.EnumKind: 1755 val := field.Enum.Values[0] 1756 if val.GoIdent.GoImportPath == f.GoImportPath { 1757 return g.QualifiedGoIdent(val.GoIdent) 1758 } else { 1759 // If the enum value is declared in a different Go package, 1760 // reference it by number since the name may not be correct. 1761 // See https://github.com/golang/protobuf/issues/513. 1762 return g.QualifiedGoIdent(field.Enum.GoIdent) + "(" + strconv.FormatInt(int64(val.Desc.Number()), 10) + ")" 1763 } 1764 default: 1765 return "0" 1766 } 1767 } 1768 1769 func fieldJSONTagValue(field *protogen.Field) string { 1770 return string(field.Desc.Name()) + ",omitempty" 1771 } 1772 1773 func genExtensions(g *generator.GeneratedFile, f *fileInfo) { 1774 if len(f.allExtensions) == 0 { 1775 return 1776 } 1777 1778 g.P("var ", extensionTypesVarName(f), " = []", protoimplPackage.Ident("ExtensionInfo"), "{") 1779 for _, x := range f.allExtensions { 1780 g.P("{") 1781 g.P("ExtendedType: (*", x.Extendee.GoIdent, ")(nil),") 1782 goType, pointer := fieldGoType(g, f, x.Extension) 1783 if pointer { 1784 goType = "*" + goType 1785 } 1786 g.P("ExtensionType: (", goType, ")(nil),") 1787 g.P("Field: ", x.Desc.Number(), ",") 1788 g.P("Name: ", strconv.Quote(string(x.Desc.FullName())), ",") 1789 g.P("Tag: ", strconv.Quote(fieldProtobufTagValue(x.Extension)), ",") 1790 g.P("Filename: ", strconv.Quote(f.Desc.Path()), ",") 1791 g.P("},") 1792 } 1793 g.P("}") 1794 g.P() 1795 1796 // Group extensions by the target message. 1797 var orderedTargets []protogen.GoIdent 1798 allExtensionsByTarget := make(map[protogen.GoIdent][]*extensionInfo) 1799 allExtensionsByPtr := make(map[*extensionInfo]int) 1800 for i, x := range f.allExtensions { 1801 target := x.Extendee.GoIdent 1802 if len(allExtensionsByTarget[target]) == 0 { 1803 orderedTargets = append(orderedTargets, target) 1804 } 1805 allExtensionsByTarget[target] = append(allExtensionsByTarget[target], x) 1806 allExtensionsByPtr[x] = i 1807 } 1808 for _, target := range orderedTargets { 1809 g.P("// Extension fields to ", target, ".") 1810 g.P("var (") 1811 for _, x := range allExtensionsByTarget[target] { 1812 xd := x.Desc 1813 typeName := xd.Kind().String() 1814 switch xd.Kind() { 1815 case protoreflect.EnumKind: 1816 typeName = string(xd.Enum().FullName()) 1817 case protoreflect.MessageKind, protoreflect.GroupKind: 1818 typeName = string(xd.Message().FullName()) 1819 } 1820 fieldName := string(xd.Name()) 1821 1822 leadingComments := x.Comments.Leading 1823 if leadingComments != "" { 1824 leadingComments += "\n" 1825 } 1826 leadingComments += protogen.Comments(fmt.Sprintf(" %v %v %v = %v;\n", 1827 xd.Cardinality(), typeName, fieldName, xd.Number())) 1828 leadingComments = appendDeprecationSuffix(leadingComments, 1829 x.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated()) 1830 g.P(leadingComments, 1831 "E_", x.GoIdent, " = &", extensionTypesVarName(f), "[", allExtensionsByPtr[x], "]", 1832 trailingComment(x.Comments.Trailing)) 1833 } 1834 g.P(")") 1835 g.P() 1836 } 1837 } 1838 1839 // genMessageOneofWrapperTypes generates the oneof wrapper types and 1840 // associates the types with the parent message type. 1841 func genMessageOneofWrapperTypes(g *generator.GeneratedFile, f *fileInfo, m *messageInfo) { 1842 for _, oneof := range m.Oneofs { 1843 if oneof.Desc.IsSynthetic() { 1844 continue 1845 } 1846 ifName := oneofInterfaceName(oneof) 1847 g.P("type ", ifName, " interface {") 1848 g.P(ifName, "()") 1849 g.P("}") 1850 g.P() 1851 for _, field := range oneof.Fields { 1852 g.Annotate(field.GoIdent.GoName, field.Location) 1853 g.Annotate(field.GoIdent.GoName+"."+field.GoName, field.Location) 1854 g.P("type ", field.GoIdent, " struct {") 1855 goType, _ := fieldGoType(g, f, field) 1856 tags := structTags{ 1857 {"protobuf", fieldProtobufTagValue(field)}, 1858 } 1859 if m.isTracked { 1860 tags = append(tags, gotrackTags...) 1861 } 1862 leadingComments := appendDeprecationSuffix(field.Comments.Leading, 1863 field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated()) 1864 g.P(leadingComments, 1865 field.GoName, " ", goType, tags, 1866 trailingComment(field.Comments.Trailing)) 1867 g.P("}") 1868 g.P() 1869 } 1870 for _, field := range oneof.Fields { 1871 g.P("func (*", field.GoIdent, ") ", ifName, "() {}") 1872 g.P() 1873 } 1874 } 1875 } 1876 1877 // oneofInterfaceName returns the name of the interface type implemented by 1878 // the oneof field value types. 1879 func oneofInterfaceName(oneof *protogen.Oneof) string { 1880 return "is" + oneof.GoIdent.GoName 1881 } 1882 1883 // genNoInterfacePragma generates a standalone "nointerface" pragma to 1884 // decorate methods with field-tracking support. 1885 func genNoInterfacePragma(g *generator.GeneratedFile, tracked bool) { 1886 if tracked { 1887 g.P("//go:nointerface") 1888 g.P() 1889 } 1890 } 1891 1892 var gotrackTags = structTags{{"go", "track"}} 1893 1894 // structTags is a data structure for build idiomatic Go struct tags. 1895 // Each [2]string is a key-value pair, where value is the unescaped string. 1896 // 1897 // Example: structTags{{"key", "value"}}.String() -> `key:"value"` 1898 type structTags [][2]string 1899 1900 func (tags structTags) String() string { 1901 if len(tags) == 0 { 1902 return "" 1903 } 1904 var ss []string 1905 for _, tag := range tags { 1906 // NOTE: When quoting the value, we need to make sure the backtick 1907 // character does not appear. Convert all cases to the escaped hex form. 1908 key := tag[0] 1909 val := strings.Replace(strconv.Quote(tag[1]), "`", `\x60`, -1) 1910 ss = append(ss, fmt.Sprintf("%s:%s", key, val)) 1911 } 1912 return "`" + strings.Join(ss, " ") + "`" 1913 } 1914 1915 // appendDeprecationSuffix optionally appends a deprecation notice as a suffix. 1916 func appendDeprecationSuffix(prefix protogen.Comments, deprecated bool) protogen.Comments { 1917 if !deprecated { 1918 return prefix 1919 } 1920 if prefix != "" { 1921 prefix += "\n" 1922 } 1923 return prefix + " Deprecated: Do not use.\n" 1924 } 1925 1926 // trailingComment is like protogen.Comments, but lacks a trailing newline. 1927 type trailingComment protogen.Comments 1928 1929 func (c trailingComment) String() string { 1930 s := strings.TrimSuffix(protogen.Comments(c).String(), "\n") 1931 if strings.Contains(s, "\n") { 1932 // We don't support multi-lined trailing comments as it is unclear 1933 // how to best render them in the generated code. 1934 return "" 1935 } 1936 return s 1937 } 1938 1939 // TagMarshal encodes the protoreflect.FieldDescriptor as a tag. 1940 // 1941 // The enumName must be provided if the kind is an enum. 1942 // Historically, the formulation of the enum "name" was the proto package 1943 // dot-concatenated with the generated Go identifier for the enum type. 1944 // Depending on the context on how Marshal is called, there are different ways 1945 // through which that information is determined. As such it is the caller's 1946 // responsibility to provide a function to obtain that information. 1947 func TagMarshal(fd pref.FieldDescriptor, enumName string) string { 1948 var tag []string 1949 switch fd.Kind() { 1950 case pref.BoolKind, pref.EnumKind, pref.Int32Kind, pref.Uint32Kind, pref.Int64Kind, pref.Uint64Kind: 1951 tag = append(tag, "varint") 1952 case pref.Sint32Kind: 1953 tag = append(tag, "zigzag32") 1954 case pref.Sint64Kind: 1955 tag = append(tag, "zigzag64") 1956 case pref.Sfixed32Kind, pref.Fixed32Kind, pref.FloatKind: 1957 tag = append(tag, "fixed32") 1958 case pref.Sfixed64Kind, pref.Fixed64Kind, pref.DoubleKind: 1959 tag = append(tag, "fixed64") 1960 case pref.StringKind, pref.BytesKind, pref.MessageKind: 1961 tag = append(tag, "bytes") 1962 case pref.GroupKind: 1963 tag = append(tag, "group") 1964 } 1965 tag = append(tag, strconv.Itoa(int(fd.Number()))) 1966 switch fd.Cardinality() { 1967 case pref.Optional: 1968 tag = append(tag, "opt") 1969 case pref.Required: 1970 tag = append(tag, "req") 1971 case pref.Repeated: 1972 tag = append(tag, "rep") 1973 } 1974 if fd.IsPacked() { 1975 tag = append(tag, "packed") 1976 } 1977 name := string(fd.Name()) 1978 if fd.Kind() == pref.GroupKind { 1979 // The name of the FieldDescriptor for a group field is 1980 // lowercased. To find the original capitalization, we 1981 // look in the field's MessageType. 1982 name = string(fd.Message().Name()) 1983 } 1984 tag = append(tag, "name="+name) 1985 if jsonName := fd.JSONName(); jsonName != "" && jsonName != name && !fd.IsExtension() { 1986 // NOTE: The jsonName != name condition is suspect, but it preserve 1987 // the exact same semantics from the previous generator. 1988 tag = append(tag, "json="+jsonName) 1989 } 1990 if fd.IsWeak() { 1991 tag = append(tag, "weak="+string(fd.Message().FullName())) 1992 } 1993 // The previous implementation does not tag extension fields as proto3, 1994 // even when the field is defined in a proto3 file. Match that behavior 1995 // for consistency. 1996 if fd.Syntax() == pref.Proto3 && !fd.IsExtension() { 1997 tag = append(tag, "proto3") 1998 } 1999 if fd.Kind() == pref.EnumKind && enumName != "" { 2000 tag = append(tag, "enum="+enumName) 2001 } 2002 if fd.ContainingOneof() != nil { 2003 tag = append(tag, "oneof") 2004 } 2005 // This must appear last in the tag, since commas in strings aren't escaped. 2006 if fd.HasDefault() { 2007 def, _ := DefValMarshal(fd.Default(), fd.DefaultEnumValue(), fd.Kind(), 2) // 2 = defval.GoTag 2008 tag = append(tag, "def="+def) 2009 } 2010 return strings.Join(tag, ",") 2011 } 2012 2013 func genMessageReflectMethods(g *generator.GeneratedFile, f *fileInfo, m *messageInfo) { 2014 // This is being handled by the fast reflection feature. 2015 2016 //idx := f.allMessagesByPtr[m] 2017 //typesVar := messageTypesVarName(f) 2018 2019 // ProtoReflect method. 2020 //g.P("func (x *", m.GoIdent, ") ProtoReflect() ", protoreflectPackage.Ident("Message"), " {") 2021 //g.P("mi := &", typesVar, "[", idx, "]") 2022 //g.P("if ", protoimplPackage.Ident("UnsafeEnabled"), " && x != nil {") 2023 //g.P("ms := ", protoimplPackage.Ident("X"), ".MessageStateOf(", protoimplPackage.Ident("Pointer"), "(x))") 2024 //g.P("if ms.LoadMessageInfo() == nil {") 2025 //g.P("ms.StoreMessageInfo(mi)") 2026 //g.P("}") 2027 //g.P("return ms") 2028 //g.P("}") 2029 //g.P("return mi.MessageOf(x)") 2030 //g.P("}") 2031 //g.P() 2032 } 2033 2034 // DefValMarshal serializes v as the default string according to the given kind k. 2035 // When specifying the Descriptor format for an enum kind, the associated 2036 // enum value descriptor must be provided. 2037 func DefValMarshal(v pref.Value, ev pref.EnumValueDescriptor, k pref.Kind, f Format) (string, error) { 2038 switch k { 2039 case pref.BoolKind: 2040 if f == GoTag { 2041 if v.Bool() { 2042 return "1", nil 2043 } else { 2044 return "0", nil 2045 } 2046 } else { 2047 if v.Bool() { 2048 return "true", nil 2049 } else { 2050 return "false", nil 2051 } 2052 } 2053 case pref.EnumKind: 2054 if f == GoTag { 2055 return strconv.FormatInt(int64(v.Enum()), 10), nil 2056 } else { 2057 return string(ev.Name()), nil 2058 } 2059 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind, pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind: 2060 return strconv.FormatInt(v.Int(), 10), nil 2061 case pref.Uint32Kind, pref.Fixed32Kind, pref.Uint64Kind, pref.Fixed64Kind: 2062 return strconv.FormatUint(v.Uint(), 10), nil 2063 case pref.FloatKind, pref.DoubleKind: 2064 f := v.Float() 2065 switch { 2066 case math.IsInf(f, -1): 2067 return "-inf", nil 2068 case math.IsInf(f, +1): 2069 return "inf", nil 2070 case math.IsNaN(f): 2071 return "nan", nil 2072 default: 2073 if k == pref.FloatKind { 2074 return strconv.FormatFloat(f, 'g', -1, 32), nil 2075 } else { 2076 return strconv.FormatFloat(f, 'g', -1, 64), nil 2077 } 2078 } 2079 case pref.StringKind: 2080 // String values are serialized as is without any escaping. 2081 return v.String(), nil 2082 case pref.BytesKind: 2083 if s, ok := marshalBytes(v.Bytes()); ok { 2084 return s, nil 2085 } 2086 } 2087 return "", fmt.Errorf("could not format value for %v: %v", k, v) 2088 } 2089 2090 type Format int 2091 2092 const ( 2093 _ Format = iota 2094 2095 // Descriptor uses the serialization format that protoc uses with the 2096 // google.protobuf.FieldDescriptorProto.default_value field. 2097 Descriptor 2098 2099 // GoTag uses the historical serialization format in Go struct field tags. 2100 GoTag 2101 ) 2102 2103 // marshalBytes serializes bytes by using C escaping. 2104 // To match the exact output of protoc, this is identical to the 2105 // CEscape function in strutil.cc of the protoc source code. 2106 func marshalBytes(b []byte) (string, bool) { 2107 var s []byte 2108 for _, c := range b { 2109 switch c { 2110 case '\n': 2111 s = append(s, `\n`...) 2112 case '\r': 2113 s = append(s, `\r`...) 2114 case '\t': 2115 s = append(s, `\t`...) 2116 case '"': 2117 s = append(s, `\"`...) 2118 case '\'': 2119 s = append(s, `\'`...) 2120 case '\\': 2121 s = append(s, `\\`...) 2122 default: 2123 if printableASCII := c >= 0x20 && c <= 0x7e; printableASCII { 2124 s = append(s, c) 2125 } else { 2126 s = append(s, fmt.Sprintf(`\%03o`, c)...) 2127 } 2128 } 2129 } 2130 return string(s), true 2131 } 2132 2133 type goImportPath interface { 2134 String() string 2135 Ident(string) protogen.GoIdent 2136 } 2137 2138 type enumInfo struct { 2139 *protogen.Enum 2140 2141 genJSONMethod bool 2142 genRawDescMethod bool 2143 } 2144 2145 func newEnumInfo(f *fileInfo, enum *protogen.Enum) *enumInfo { 2146 e := &enumInfo{Enum: enum} 2147 e.genJSONMethod = true 2148 e.genRawDescMethod = true 2149 return e 2150 } 2151 2152 type messageInfo struct { 2153 *protogen.Message 2154 2155 genRawDescMethod bool 2156 genExtRangeMethod bool 2157 2158 isTracked bool 2159 hasWeak bool 2160 } 2161 2162 // isTrackedMessage reports whether field tracking is enabled on the message. 2163 func isTrackedMessage(m *messageInfo) (tracked bool) { 2164 const trackFieldUse_fieldNumber = 37383685 2165 2166 // Decode the option from unknown fields to avoid a dependency on the 2167 // annotation proto from protoc-gen-go. 2168 b := m.Desc.Options().(*descriptorpb.MessageOptions).ProtoReflect().GetUnknown() 2169 for len(b) > 0 { 2170 num, typ, n := protowire.ConsumeTag(b) 2171 b = b[n:] 2172 if num == trackFieldUse_fieldNumber && typ == protowire.VarintType { 2173 v, _ := protowire.ConsumeVarint(b) 2174 tracked = protowire.DecodeBool(v) 2175 } 2176 m := protowire.ConsumeFieldValue(num, typ, b) 2177 b = b[m:] 2178 } 2179 return tracked 2180 } 2181 2182 func newMessageInfo(f *fileInfo, message *protogen.Message) *messageInfo { 2183 m := &messageInfo{Message: message} 2184 m.genRawDescMethod = true 2185 m.genExtRangeMethod = true 2186 m.isTracked = isTrackedMessage(m) 2187 for _, field := range m.Fields { 2188 m.hasWeak = m.hasWeak || field.Desc.IsWeak() 2189 } 2190 return m 2191 } 2192 2193 type extensionInfo struct { 2194 *protogen.Extension 2195 } 2196 2197 func newExtensionInfo(f *fileInfo, extension *protogen.Extension) *extensionInfo { 2198 x := &extensionInfo{Extension: extension} 2199 return x 2200 } 2201 2202 type structFields struct { 2203 count int 2204 unexported map[int]string 2205 } 2206 2207 func (sf *structFields) append(name string) { 2208 if r, _ := utf8.DecodeRuneInString(name); !unicode.IsUpper(r) { 2209 if sf.unexported == nil { 2210 sf.unexported = make(map[int]string) 2211 } 2212 sf.unexported[sf.count] = name 2213 } 2214 sf.count++ 2215 } 2216 2217 type fileInfo struct { 2218 *protogen.File 2219 2220 allEnums []*enumInfo 2221 allMessages []*messageInfo 2222 allExtensions []*extensionInfo 2223 2224 allEnumsByPtr map[*enumInfo]int // value is index into allEnums 2225 allMessagesByPtr map[*messageInfo]int // value is index into allMessages 2226 allMessageFieldsByPtr map[*messageInfo]*structFields 2227 2228 // needRawDesc specifies whether the generator should emit logic to provide 2229 // the legacy raw descriptor in GZIP'd form. 2230 // This is updated by enum and message generation logic as necessary, 2231 // and checked at the end of file generation. 2232 needRawDesc bool 2233 } 2234 2235 func newFileInfo(file *protogen.File) *fileInfo { 2236 f := &fileInfo{File: file} 2237 2238 // Collect all enums, messages, and extensions in "flattened ordering". 2239 // See filetype.TypeBuilder. 2240 var walkMessages func([]*protogen.Message, func(*protogen.Message)) 2241 walkMessages = func(messages []*protogen.Message, f func(*protogen.Message)) { 2242 for _, m := range messages { 2243 f(m) 2244 walkMessages(m.Messages, f) 2245 } 2246 } 2247 initEnumInfos := func(enums []*protogen.Enum) { 2248 for _, enum := range enums { 2249 f.allEnums = append(f.allEnums, newEnumInfo(f, enum)) 2250 } 2251 } 2252 initMessageInfos := func(messages []*protogen.Message) { 2253 for _, message := range messages { 2254 f.allMessages = append(f.allMessages, newMessageInfo(f, message)) 2255 } 2256 } 2257 initExtensionInfos := func(extensions []*protogen.Extension) { 2258 for _, extension := range extensions { 2259 f.allExtensions = append(f.allExtensions, newExtensionInfo(f, extension)) 2260 } 2261 } 2262 initEnumInfos(f.Enums) 2263 initMessageInfos(f.Messages) 2264 initExtensionInfos(f.Extensions) 2265 walkMessages(f.Messages, func(m *protogen.Message) { 2266 initEnumInfos(m.Enums) 2267 initMessageInfos(m.Messages) 2268 initExtensionInfos(m.Extensions) 2269 }) 2270 2271 // Derive a reverse mapping of enum and message pointers to their index 2272 // in allEnums and allMessages. 2273 if len(f.allEnums) > 0 { 2274 f.allEnumsByPtr = make(map[*enumInfo]int) 2275 for i, e := range f.allEnums { 2276 f.allEnumsByPtr[e] = i 2277 } 2278 } 2279 if len(f.allMessages) > 0 { 2280 f.allMessagesByPtr = make(map[*messageInfo]int) 2281 f.allMessageFieldsByPtr = make(map[*messageInfo]*structFields) 2282 for i, m := range f.allMessages { 2283 f.allMessagesByPtr[m] = i 2284 f.allMessageFieldsByPtr[m] = new(structFields) 2285 } 2286 } 2287 2288 return f 2289 }