| package protoparse |
| |
| import ( |
| "bytes" |
| "fmt" |
| "math" |
| |
| "github.com/golang/protobuf/proto" |
| dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" |
| |
| "github.com/jhump/protoreflect/desc" |
| "github.com/jhump/protoreflect/desc/internal" |
| "github.com/jhump/protoreflect/dynamic" |
| ) |
| |
| // NB: To process options, we need descriptors, but we may not have rich |
| // descriptors when trying to interpret options for unlinked parsed files. |
| // So we define minimal interfaces that can be backed by both rich descriptors |
| // as well as their poorer cousins, plain ol' descriptor protos. |
| |
| type descriptorish interface { |
| GetFile() fileDescriptorish |
| GetFullyQualifiedName() string |
| AsProto() proto.Message |
| } |
| |
| type fileDescriptorish interface { |
| descriptorish |
| GetFileOptions() *dpb.FileOptions |
| GetPackage() string |
| FindSymbol(name string) desc.Descriptor |
| GetPublicDependencies() []fileDescriptorish |
| GetDependencies() []fileDescriptorish |
| GetMessageTypes() []msgDescriptorish |
| GetExtensions() []fldDescriptorish |
| GetEnumTypes() []enumDescriptorish |
| GetServices() []svcDescriptorish |
| } |
| |
| type msgDescriptorish interface { |
| descriptorish |
| GetMessageOptions() *dpb.MessageOptions |
| GetFields() []fldDescriptorish |
| GetOneOfs() []oneofDescriptorish |
| GetExtensionRanges() []extRangeDescriptorish |
| GetNestedMessageTypes() []msgDescriptorish |
| GetNestedExtensions() []fldDescriptorish |
| GetNestedEnumTypes() []enumDescriptorish |
| } |
| |
| type fldDescriptorish interface { |
| descriptorish |
| GetFieldOptions() *dpb.FieldOptions |
| GetMessageType() *desc.MessageDescriptor |
| GetEnumType() *desc.EnumDescriptor |
| AsFieldDescriptorProto() *dpb.FieldDescriptorProto |
| } |
| |
| type oneofDescriptorish interface { |
| descriptorish |
| GetOneOfOptions() *dpb.OneofOptions |
| } |
| |
| type enumDescriptorish interface { |
| descriptorish |
| GetEnumOptions() *dpb.EnumOptions |
| GetValues() []enumValDescriptorish |
| } |
| |
| type enumValDescriptorish interface { |
| descriptorish |
| GetEnumValueOptions() *dpb.EnumValueOptions |
| } |
| |
| type svcDescriptorish interface { |
| descriptorish |
| GetServiceOptions() *dpb.ServiceOptions |
| GetMethods() []methodDescriptorish |
| } |
| |
| type methodDescriptorish interface { |
| descriptorish |
| GetMethodOptions() *dpb.MethodOptions |
| } |
| |
| // The hierarchy of descriptorish implementations backed by |
| // rich descriptors: |
| |
| type richFileDescriptorish struct { |
| *desc.FileDescriptor |
| } |
| |
| func (d richFileDescriptorish) GetFile() fileDescriptorish { |
| return d |
| } |
| |
| func (d richFileDescriptorish) GetPublicDependencies() []fileDescriptorish { |
| deps := d.FileDescriptor.GetPublicDependencies() |
| ret := make([]fileDescriptorish, len(deps)) |
| for i, d := range deps { |
| ret[i] = richFileDescriptorish{FileDescriptor: d} |
| } |
| return ret |
| } |
| |
| func (d richFileDescriptorish) GetDependencies() []fileDescriptorish { |
| deps := d.FileDescriptor.GetDependencies() |
| ret := make([]fileDescriptorish, len(deps)) |
| for i, d := range deps { |
| ret[i] = richFileDescriptorish{FileDescriptor: d} |
| } |
| return ret |
| } |
| |
| func (d richFileDescriptorish) GetMessageTypes() []msgDescriptorish { |
| msgs := d.FileDescriptor.GetMessageTypes() |
| ret := make([]msgDescriptorish, len(msgs)) |
| for i, m := range msgs { |
| ret[i] = richMsgDescriptorish{MessageDescriptor: m} |
| } |
| return ret |
| } |
| |
| func (d richFileDescriptorish) GetExtensions() []fldDescriptorish { |
| flds := d.FileDescriptor.GetExtensions() |
| ret := make([]fldDescriptorish, len(flds)) |
| for i, f := range flds { |
| ret[i] = richFldDescriptorish{FieldDescriptor: f} |
| } |
| return ret |
| } |
| |
| func (d richFileDescriptorish) GetEnumTypes() []enumDescriptorish { |
| ens := d.FileDescriptor.GetEnumTypes() |
| ret := make([]enumDescriptorish, len(ens)) |
| for i, en := range ens { |
| ret[i] = richEnumDescriptorish{EnumDescriptor: en} |
| } |
| return ret |
| } |
| |
| func (d richFileDescriptorish) GetServices() []svcDescriptorish { |
| svcs := d.FileDescriptor.GetServices() |
| ret := make([]svcDescriptorish, len(svcs)) |
| for i, s := range svcs { |
| ret[i] = richSvcDescriptorish{ServiceDescriptor: s} |
| } |
| return ret |
| } |
| |
| type richMsgDescriptorish struct { |
| *desc.MessageDescriptor |
| } |
| |
| func (d richMsgDescriptorish) GetFile() fileDescriptorish { |
| return richFileDescriptorish{FileDescriptor: d.MessageDescriptor.GetFile()} |
| } |
| |
| func (d richMsgDescriptorish) GetFields() []fldDescriptorish { |
| flds := d.MessageDescriptor.GetFields() |
| ret := make([]fldDescriptorish, len(flds)) |
| for i, f := range flds { |
| ret[i] = richFldDescriptorish{FieldDescriptor: f} |
| } |
| return ret |
| } |
| |
| func (d richMsgDescriptorish) GetOneOfs() []oneofDescriptorish { |
| oos := d.MessageDescriptor.GetOneOfs() |
| ret := make([]oneofDescriptorish, len(oos)) |
| for i, oo := range oos { |
| ret[i] = richOneOfDescriptorish{OneOfDescriptor: oo} |
| } |
| return ret |
| } |
| |
| func (d richMsgDescriptorish) GetExtensionRanges() []extRangeDescriptorish { |
| md := d.MessageDescriptor |
| mdFqn := md.GetFullyQualifiedName() |
| extrs := md.AsDescriptorProto().GetExtensionRange() |
| ret := make([]extRangeDescriptorish, len(extrs)) |
| for i, extr := range extrs { |
| ret[i] = extRangeDescriptorish{ |
| er: extr, |
| qual: mdFqn, |
| file: richFileDescriptorish{FileDescriptor: md.GetFile()}, |
| } |
| } |
| return ret |
| } |
| |
| func (d richMsgDescriptorish) GetNestedMessageTypes() []msgDescriptorish { |
| msgs := d.MessageDescriptor.GetNestedMessageTypes() |
| ret := make([]msgDescriptorish, len(msgs)) |
| for i, m := range msgs { |
| ret[i] = richMsgDescriptorish{MessageDescriptor: m} |
| } |
| return ret |
| } |
| |
| func (d richMsgDescriptorish) GetNestedExtensions() []fldDescriptorish { |
| flds := d.MessageDescriptor.GetNestedExtensions() |
| ret := make([]fldDescriptorish, len(flds)) |
| for i, f := range flds { |
| ret[i] = richFldDescriptorish{FieldDescriptor: f} |
| } |
| return ret |
| } |
| |
| func (d richMsgDescriptorish) GetNestedEnumTypes() []enumDescriptorish { |
| ens := d.MessageDescriptor.GetNestedEnumTypes() |
| ret := make([]enumDescriptorish, len(ens)) |
| for i, en := range ens { |
| ret[i] = richEnumDescriptorish{EnumDescriptor: en} |
| } |
| return ret |
| } |
| |
| type richFldDescriptorish struct { |
| *desc.FieldDescriptor |
| } |
| |
| func (d richFldDescriptorish) GetFile() fileDescriptorish { |
| return richFileDescriptorish{FileDescriptor: d.FieldDescriptor.GetFile()} |
| } |
| |
| func (d richFldDescriptorish) AsFieldDescriptorProto() *dpb.FieldDescriptorProto { |
| return d.FieldDescriptor.AsFieldDescriptorProto() |
| } |
| |
| type richOneOfDescriptorish struct { |
| *desc.OneOfDescriptor |
| } |
| |
| func (d richOneOfDescriptorish) GetFile() fileDescriptorish { |
| return richFileDescriptorish{FileDescriptor: d.OneOfDescriptor.GetFile()} |
| } |
| |
| type richEnumDescriptorish struct { |
| *desc.EnumDescriptor |
| } |
| |
| func (d richEnumDescriptorish) GetFile() fileDescriptorish { |
| return richFileDescriptorish{FileDescriptor: d.EnumDescriptor.GetFile()} |
| } |
| |
| func (d richEnumDescriptorish) GetValues() []enumValDescriptorish { |
| vals := d.EnumDescriptor.GetValues() |
| ret := make([]enumValDescriptorish, len(vals)) |
| for i, val := range vals { |
| ret[i] = richEnumValDescriptorish{EnumValueDescriptor: val} |
| } |
| return ret |
| } |
| |
| type richEnumValDescriptorish struct { |
| *desc.EnumValueDescriptor |
| } |
| |
| func (d richEnumValDescriptorish) GetFile() fileDescriptorish { |
| return richFileDescriptorish{FileDescriptor: d.EnumValueDescriptor.GetFile()} |
| } |
| |
| type richSvcDescriptorish struct { |
| *desc.ServiceDescriptor |
| } |
| |
| func (d richSvcDescriptorish) GetFile() fileDescriptorish { |
| return richFileDescriptorish{FileDescriptor: d.ServiceDescriptor.GetFile()} |
| } |
| |
| func (d richSvcDescriptorish) GetMethods() []methodDescriptorish { |
| mtds := d.ServiceDescriptor.GetMethods() |
| ret := make([]methodDescriptorish, len(mtds)) |
| for i, mtd := range mtds { |
| ret[i] = richMethodDescriptorish{MethodDescriptor: mtd} |
| } |
| return ret |
| } |
| |
| type richMethodDescriptorish struct { |
| *desc.MethodDescriptor |
| } |
| |
| func (d richMethodDescriptorish) GetFile() fileDescriptorish { |
| return richFileDescriptorish{FileDescriptor: d.MethodDescriptor.GetFile()} |
| } |
| |
| // The hierarchy of descriptorish implementations backed by |
| // plain descriptor protos: |
| |
| type poorFileDescriptorish struct { |
| *dpb.FileDescriptorProto |
| } |
| |
| func (d poorFileDescriptorish) GetFile() fileDescriptorish { |
| return d |
| } |
| |
| func (d poorFileDescriptorish) GetFullyQualifiedName() string { |
| return d.FileDescriptorProto.GetName() |
| } |
| |
| func (d poorFileDescriptorish) AsProto() proto.Message { |
| return d.FileDescriptorProto |
| } |
| |
| func (d poorFileDescriptorish) GetFileOptions() *dpb.FileOptions { |
| return d.FileDescriptorProto.GetOptions() |
| } |
| |
| func (d poorFileDescriptorish) FindSymbol(name string) desc.Descriptor { |
| return nil |
| } |
| |
| func (d poorFileDescriptorish) GetPublicDependencies() []fileDescriptorish { |
| return nil |
| } |
| |
| func (d poorFileDescriptorish) GetDependencies() []fileDescriptorish { |
| return nil |
| } |
| |
| func (d poorFileDescriptorish) GetMessageTypes() []msgDescriptorish { |
| msgs := d.FileDescriptorProto.GetMessageType() |
| pkg := d.FileDescriptorProto.GetPackage() |
| ret := make([]msgDescriptorish, len(msgs)) |
| for i, m := range msgs { |
| ret[i] = poorMsgDescriptorish{ |
| DescriptorProto: m, |
| qual: pkg, |
| file: d, |
| } |
| } |
| return ret |
| } |
| |
| func (d poorFileDescriptorish) GetExtensions() []fldDescriptorish { |
| exts := d.FileDescriptorProto.GetExtension() |
| pkg := d.FileDescriptorProto.GetPackage() |
| ret := make([]fldDescriptorish, len(exts)) |
| for i, e := range exts { |
| ret[i] = poorFldDescriptorish{ |
| FieldDescriptorProto: e, |
| qual: pkg, |
| file: d, |
| } |
| } |
| return ret |
| } |
| |
| func (d poorFileDescriptorish) GetEnumTypes() []enumDescriptorish { |
| ens := d.FileDescriptorProto.GetEnumType() |
| pkg := d.FileDescriptorProto.GetPackage() |
| ret := make([]enumDescriptorish, len(ens)) |
| for i, e := range ens { |
| ret[i] = poorEnumDescriptorish{ |
| EnumDescriptorProto: e, |
| qual: pkg, |
| file: d, |
| } |
| } |
| return ret |
| } |
| |
| func (d poorFileDescriptorish) GetServices() []svcDescriptorish { |
| svcs := d.FileDescriptorProto.GetService() |
| pkg := d.FileDescriptorProto.GetPackage() |
| ret := make([]svcDescriptorish, len(svcs)) |
| for i, s := range svcs { |
| ret[i] = poorSvcDescriptorish{ |
| ServiceDescriptorProto: s, |
| qual: pkg, |
| file: d, |
| } |
| } |
| return ret |
| } |
| |
| type poorMsgDescriptorish struct { |
| *dpb.DescriptorProto |
| qual string |
| file fileDescriptorish |
| } |
| |
| func (d poorMsgDescriptorish) GetFile() fileDescriptorish { |
| return d.file |
| } |
| |
| func (d poorMsgDescriptorish) GetFullyQualifiedName() string { |
| return qualify(d.qual, d.DescriptorProto.GetName()) |
| } |
| |
| func qualify(qual, name string) string { |
| if qual == "" { |
| return name |
| } else { |
| return fmt.Sprintf("%s.%s", qual, name) |
| } |
| } |
| |
| func (d poorMsgDescriptorish) AsProto() proto.Message { |
| return d.DescriptorProto |
| } |
| |
| func (d poorMsgDescriptorish) GetMessageOptions() *dpb.MessageOptions { |
| return d.DescriptorProto.GetOptions() |
| } |
| |
| func (d poorMsgDescriptorish) GetFields() []fldDescriptorish { |
| flds := d.DescriptorProto.GetField() |
| ret := make([]fldDescriptorish, len(flds)) |
| for i, f := range flds { |
| ret[i] = poorFldDescriptorish{ |
| FieldDescriptorProto: f, |
| qual: d.GetFullyQualifiedName(), |
| file: d.file, |
| } |
| } |
| return ret |
| } |
| |
| func (d poorMsgDescriptorish) GetOneOfs() []oneofDescriptorish { |
| oos := d.DescriptorProto.GetOneofDecl() |
| ret := make([]oneofDescriptorish, len(oos)) |
| for i, oo := range oos { |
| ret[i] = poorOneOfDescriptorish{ |
| OneofDescriptorProto: oo, |
| qual: d.GetFullyQualifiedName(), |
| file: d.file, |
| } |
| } |
| return ret |
| } |
| |
| func (d poorMsgDescriptorish) GetExtensionRanges() []extRangeDescriptorish { |
| mdFqn := d.GetFullyQualifiedName() |
| extrs := d.DescriptorProto.GetExtensionRange() |
| ret := make([]extRangeDescriptorish, len(extrs)) |
| for i, extr := range extrs { |
| ret[i] = extRangeDescriptorish{ |
| er: extr, |
| qual: mdFqn, |
| file: d.file, |
| } |
| } |
| return ret |
| } |
| |
| func (d poorMsgDescriptorish) GetNestedMessageTypes() []msgDescriptorish { |
| msgs := d.DescriptorProto.GetNestedType() |
| ret := make([]msgDescriptorish, len(msgs)) |
| for i, m := range msgs { |
| ret[i] = poorMsgDescriptorish{ |
| DescriptorProto: m, |
| qual: d.GetFullyQualifiedName(), |
| file: d.file, |
| } |
| } |
| return ret |
| } |
| |
| func (d poorMsgDescriptorish) GetNestedExtensions() []fldDescriptorish { |
| flds := d.DescriptorProto.GetExtension() |
| ret := make([]fldDescriptorish, len(flds)) |
| for i, f := range flds { |
| ret[i] = poorFldDescriptorish{ |
| FieldDescriptorProto: f, |
| qual: d.GetFullyQualifiedName(), |
| file: d.file, |
| } |
| } |
| return ret |
| } |
| |
| func (d poorMsgDescriptorish) GetNestedEnumTypes() []enumDescriptorish { |
| ens := d.DescriptorProto.GetEnumType() |
| ret := make([]enumDescriptorish, len(ens)) |
| for i, en := range ens { |
| ret[i] = poorEnumDescriptorish{ |
| EnumDescriptorProto: en, |
| qual: d.GetFullyQualifiedName(), |
| file: d.file, |
| } |
| } |
| return ret |
| } |
| |
| type poorFldDescriptorish struct { |
| *dpb.FieldDescriptorProto |
| qual string |
| file fileDescriptorish |
| } |
| |
| func (d poorFldDescriptorish) GetFile() fileDescriptorish { |
| return d.file |
| } |
| |
| func (d poorFldDescriptorish) GetFullyQualifiedName() string { |
| return qualify(d.qual, d.FieldDescriptorProto.GetName()) |
| } |
| |
| func (d poorFldDescriptorish) AsProto() proto.Message { |
| return d.FieldDescriptorProto |
| } |
| |
| func (d poorFldDescriptorish) GetFieldOptions() *dpb.FieldOptions { |
| return d.FieldDescriptorProto.GetOptions() |
| } |
| |
| func (d poorFldDescriptorish) GetMessageType() *desc.MessageDescriptor { |
| return nil |
| } |
| |
| func (d poorFldDescriptorish) GetEnumType() *desc.EnumDescriptor { |
| return nil |
| } |
| |
| type poorOneOfDescriptorish struct { |
| *dpb.OneofDescriptorProto |
| qual string |
| file fileDescriptorish |
| } |
| |
| func (d poorOneOfDescriptorish) GetFile() fileDescriptorish { |
| return d.file |
| } |
| |
| func (d poorOneOfDescriptorish) GetFullyQualifiedName() string { |
| return qualify(d.qual, d.OneofDescriptorProto.GetName()) |
| } |
| |
| func (d poorOneOfDescriptorish) AsProto() proto.Message { |
| return d.OneofDescriptorProto |
| } |
| |
| func (d poorOneOfDescriptorish) GetOneOfOptions() *dpb.OneofOptions { |
| return d.OneofDescriptorProto.GetOptions() |
| } |
| |
| func (d poorFldDescriptorish) AsFieldDescriptorProto() *dpb.FieldDescriptorProto { |
| return d.FieldDescriptorProto |
| } |
| |
| type poorEnumDescriptorish struct { |
| *dpb.EnumDescriptorProto |
| qual string |
| file fileDescriptorish |
| } |
| |
| func (d poorEnumDescriptorish) GetFile() fileDescriptorish { |
| return d.file |
| } |
| |
| func (d poorEnumDescriptorish) GetFullyQualifiedName() string { |
| return qualify(d.qual, d.EnumDescriptorProto.GetName()) |
| } |
| |
| func (d poorEnumDescriptorish) AsProto() proto.Message { |
| return d.EnumDescriptorProto |
| } |
| |
| func (d poorEnumDescriptorish) GetEnumOptions() *dpb.EnumOptions { |
| return d.EnumDescriptorProto.GetOptions() |
| } |
| |
| func (d poorEnumDescriptorish) GetValues() []enumValDescriptorish { |
| vals := d.EnumDescriptorProto.GetValue() |
| ret := make([]enumValDescriptorish, len(vals)) |
| for i, v := range vals { |
| ret[i] = poorEnumValDescriptorish{ |
| EnumValueDescriptorProto: v, |
| qual: d.GetFullyQualifiedName(), |
| file: d.file, |
| } |
| } |
| return ret |
| } |
| |
| type poorEnumValDescriptorish struct { |
| *dpb.EnumValueDescriptorProto |
| qual string |
| file fileDescriptorish |
| } |
| |
| func (d poorEnumValDescriptorish) GetFile() fileDescriptorish { |
| return d.file |
| } |
| |
| func (d poorEnumValDescriptorish) GetFullyQualifiedName() string { |
| return qualify(d.qual, d.EnumValueDescriptorProto.GetName()) |
| } |
| |
| func (d poorEnumValDescriptorish) AsProto() proto.Message { |
| return d.EnumValueDescriptorProto |
| } |
| |
| func (d poorEnumValDescriptorish) GetEnumValueOptions() *dpb.EnumValueOptions { |
| return d.EnumValueDescriptorProto.GetOptions() |
| } |
| |
| type poorSvcDescriptorish struct { |
| *dpb.ServiceDescriptorProto |
| qual string |
| file fileDescriptorish |
| } |
| |
| func (d poorSvcDescriptorish) GetFile() fileDescriptorish { |
| return d.file |
| } |
| |
| func (d poorSvcDescriptorish) GetFullyQualifiedName() string { |
| return qualify(d.qual, d.ServiceDescriptorProto.GetName()) |
| } |
| |
| func (d poorSvcDescriptorish) AsProto() proto.Message { |
| return d.ServiceDescriptorProto |
| } |
| |
| func (d poorSvcDescriptorish) GetServiceOptions() *dpb.ServiceOptions { |
| return d.ServiceDescriptorProto.GetOptions() |
| } |
| |
| func (d poorSvcDescriptorish) GetMethods() []methodDescriptorish { |
| mtds := d.ServiceDescriptorProto.GetMethod() |
| ret := make([]methodDescriptorish, len(mtds)) |
| for i, m := range mtds { |
| ret[i] = poorMethodDescriptorish{ |
| MethodDescriptorProto: m, |
| qual: d.GetFullyQualifiedName(), |
| file: d.file, |
| } |
| } |
| return ret |
| } |
| |
| type poorMethodDescriptorish struct { |
| *dpb.MethodDescriptorProto |
| qual string |
| file fileDescriptorish |
| } |
| |
| func (d poorMethodDescriptorish) GetFile() fileDescriptorish { |
| return d.file |
| } |
| |
| func (d poorMethodDescriptorish) GetFullyQualifiedName() string { |
| return qualify(d.qual, d.MethodDescriptorProto.GetName()) |
| } |
| |
| func (d poorMethodDescriptorish) AsProto() proto.Message { |
| return d.MethodDescriptorProto |
| } |
| |
| func (d poorMethodDescriptorish) GetMethodOptions() *dpb.MethodOptions { |
| return d.MethodDescriptorProto.GetOptions() |
| } |
| |
| type extRangeDescriptorish struct { |
| er *dpb.DescriptorProto_ExtensionRange |
| qual string |
| file fileDescriptorish |
| } |
| |
| func (er extRangeDescriptorish) GetFile() fileDescriptorish { |
| return er.file |
| } |
| |
| func (er extRangeDescriptorish) GetFullyQualifiedName() string { |
| return qualify(er.qual, fmt.Sprintf("%d-%d", er.er.GetStart(), er.er.GetEnd()-1)) |
| } |
| |
| func (er extRangeDescriptorish) AsProto() proto.Message { |
| return er.er |
| } |
| |
| func (er extRangeDescriptorish) GetExtensionRangeOptions() *dpb.ExtensionRangeOptions { |
| return er.er.GetOptions() |
| } |
| |
| func interpretFileOptions(r *parseResult, fd fileDescriptorish) error { |
| opts := fd.GetFileOptions() |
| if opts != nil { |
| if len(opts.UninterpretedOption) > 0 { |
| if remain, err := interpretOptions(r, fd, opts, opts.UninterpretedOption); err != nil { |
| return err |
| } else { |
| opts.UninterpretedOption = remain |
| } |
| } |
| } |
| for _, md := range fd.GetMessageTypes() { |
| if err := interpretMessageOptions(r, md); err != nil { |
| return err |
| } |
| } |
| for _, fld := range fd.GetExtensions() { |
| if err := interpretFieldOptions(r, fld); err != nil { |
| return err |
| } |
| } |
| for _, ed := range fd.GetEnumTypes() { |
| if err := interpretEnumOptions(r, ed); err != nil { |
| return err |
| } |
| } |
| for _, sd := range fd.GetServices() { |
| opts := sd.GetServiceOptions() |
| if opts != nil { |
| if len(opts.UninterpretedOption) > 0 { |
| if remain, err := interpretOptions(r, sd, opts, opts.UninterpretedOption); err != nil { |
| return err |
| } else { |
| opts.UninterpretedOption = remain |
| } |
| } |
| } |
| for _, mtd := range sd.GetMethods() { |
| opts := mtd.GetMethodOptions() |
| if opts != nil { |
| if len(opts.UninterpretedOption) > 0 { |
| if remain, err := interpretOptions(r, mtd, opts, opts.UninterpretedOption); err != nil { |
| return err |
| } else { |
| opts.UninterpretedOption = remain |
| } |
| } |
| } |
| } |
| } |
| return nil |
| } |
| |
| func interpretMessageOptions(r *parseResult, md msgDescriptorish) error { |
| opts := md.GetMessageOptions() |
| if opts != nil { |
| if len(opts.UninterpretedOption) > 0 { |
| if remain, err := interpretOptions(r, md, opts, opts.UninterpretedOption); err != nil { |
| return err |
| } else { |
| opts.UninterpretedOption = remain |
| } |
| } |
| } |
| for _, fld := range md.GetFields() { |
| if err := interpretFieldOptions(r, fld); err != nil { |
| return err |
| } |
| } |
| for _, ood := range md.GetOneOfs() { |
| opts := ood.GetOneOfOptions() |
| if opts != nil { |
| if len(opts.UninterpretedOption) > 0 { |
| if remain, err := interpretOptions(r, ood, opts, opts.UninterpretedOption); err != nil { |
| return err |
| } else { |
| opts.UninterpretedOption = remain |
| } |
| } |
| } |
| } |
| for _, fld := range md.GetNestedExtensions() { |
| if err := interpretFieldOptions(r, fld); err != nil { |
| return err |
| } |
| } |
| for _, er := range md.GetExtensionRanges() { |
| opts := er.GetExtensionRangeOptions() |
| if opts != nil { |
| if len(opts.UninterpretedOption) > 0 { |
| if remain, err := interpretOptions(r, er, opts, opts.UninterpretedOption); err != nil { |
| return err |
| } else { |
| opts.UninterpretedOption = remain |
| } |
| } |
| } |
| } |
| for _, nmd := range md.GetNestedMessageTypes() { |
| if err := interpretMessageOptions(r, nmd); err != nil { |
| return err |
| } |
| } |
| for _, ed := range md.GetNestedEnumTypes() { |
| if err := interpretEnumOptions(r, ed); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |
| |
| func interpretFieldOptions(r *parseResult, fld fldDescriptorish) error { |
| opts := fld.GetFieldOptions() |
| if opts != nil { |
| if len(opts.UninterpretedOption) > 0 { |
| uo := opts.UninterpretedOption |
| scope := fmt.Sprintf("field %s", fld.GetFullyQualifiedName()) |
| |
| // process json_name pseudo-option |
| if index, err := findOption(r, scope, uo, "json_name"); err != nil && !r.lenient { |
| return err |
| } else if err == nil && index >= 0 { |
| opt := uo[index] |
| optNode := r.getOptionNode(opt) |
| |
| // attribute source code info |
| if on, ok := optNode.(*optionNode); ok { |
| r.interpretedOptions[on] = []int32{-1, internal.Field_jsonNameTag} |
| } |
| uo = removeOption(uo, index) |
| if opt.StringValue == nil { |
| return ErrorWithSourcePos{Pos: optNode.getValue().start(), Underlying: fmt.Errorf("%s: expecting string value for json_name option", scope)} |
| } |
| fld.AsFieldDescriptorProto().JsonName = proto.String(string(opt.StringValue)) |
| } |
| |
| // and process default pseudo-option |
| if index, err := processDefaultOption(r, scope, fld, uo); err != nil && !r.lenient { |
| return err |
| } else if err == nil && index >= 0 { |
| // attribute source code info |
| optNode := r.getOptionNode(uo[index]) |
| if on, ok := optNode.(*optionNode); ok { |
| r.interpretedOptions[on] = []int32{-1, internal.Field_defaultTag} |
| } |
| uo = removeOption(uo, index) |
| } |
| |
| if len(uo) == 0 { |
| // no real options, only pseudo-options above? clear out options |
| fld.AsFieldDescriptorProto().Options = nil |
| } else if remain, err := interpretOptions(r, fld, opts, uo); err != nil { |
| return err |
| } else { |
| opts.UninterpretedOption = remain |
| } |
| } |
| } |
| return nil |
| } |
| |
| func processDefaultOption(res *parseResult, scope string, fld fldDescriptorish, uos []*dpb.UninterpretedOption) (defaultIndex int, err error) { |
| found, err := findOption(res, scope, uos, "default") |
| if err != nil { |
| return -1, err |
| } else if found == -1 { |
| return -1, nil |
| } |
| opt := uos[found] |
| optNode := res.getOptionNode(opt) |
| fdp := fld.AsFieldDescriptorProto() |
| if fdp.GetLabel() == dpb.FieldDescriptorProto_LABEL_REPEATED { |
| return -1, ErrorWithSourcePos{Pos: optNode.getName().start(), Underlying: fmt.Errorf("%s: default value cannot be set because field is repeated", scope)} |
| } |
| if fdp.GetType() == dpb.FieldDescriptorProto_TYPE_GROUP || fdp.GetType() == dpb.FieldDescriptorProto_TYPE_MESSAGE { |
| return -1, ErrorWithSourcePos{Pos: optNode.getName().start(), Underlying: fmt.Errorf("%s: default value cannot be set because field is a message", scope)} |
| } |
| val := optNode.getValue() |
| if _, ok := val.(*aggregateLiteralNode); ok { |
| return -1, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%s: default value cannot be an aggregate", scope)} |
| } |
| mc := &messageContext{ |
| res: res, |
| file: fld.GetFile(), |
| elementName: fld.GetFullyQualifiedName(), |
| elementType: descriptorType(fld.AsProto()), |
| option: opt, |
| } |
| v, err := fieldValue(res, mc, fld, val, true) |
| if err != nil { |
| return -1, err |
| } |
| if str, ok := v.(string); ok { |
| fld.AsFieldDescriptorProto().DefaultValue = proto.String(str) |
| } else if b, ok := v.([]byte); ok { |
| fld.AsFieldDescriptorProto().DefaultValue = proto.String(encodeDefaultBytes(b)) |
| } else { |
| var flt float64 |
| var ok bool |
| if flt, ok = v.(float64); !ok { |
| var flt32 float32 |
| if flt32, ok = v.(float32); ok { |
| flt = float64(flt32) |
| } |
| } |
| if ok { |
| if math.IsInf(flt, 1) { |
| fld.AsFieldDescriptorProto().DefaultValue = proto.String("inf") |
| } else if ok && math.IsInf(flt, -1) { |
| fld.AsFieldDescriptorProto().DefaultValue = proto.String("-inf") |
| } else if ok && math.IsNaN(flt) { |
| fld.AsFieldDescriptorProto().DefaultValue = proto.String("nan") |
| } else { |
| fld.AsFieldDescriptorProto().DefaultValue = proto.String(fmt.Sprintf("%v", v)) |
| } |
| } else { |
| fld.AsFieldDescriptorProto().DefaultValue = proto.String(fmt.Sprintf("%v", v)) |
| } |
| } |
| return found, nil |
| } |
| |
| func encodeDefaultBytes(b []byte) string { |
| var buf bytes.Buffer |
| writeEscapedBytes(&buf, b) |
| return buf.String() |
| } |
| |
| func interpretEnumOptions(r *parseResult, ed enumDescriptorish) error { |
| opts := ed.GetEnumOptions() |
| if opts != nil { |
| if len(opts.UninterpretedOption) > 0 { |
| if remain, err := interpretOptions(r, ed, opts, opts.UninterpretedOption); err != nil { |
| return err |
| } else { |
| opts.UninterpretedOption = remain |
| } |
| } |
| } |
| for _, evd := range ed.GetValues() { |
| opts := evd.GetEnumValueOptions() |
| if opts != nil { |
| if len(opts.UninterpretedOption) > 0 { |
| if remain, err := interpretOptions(r, evd, opts, opts.UninterpretedOption); err != nil { |
| return err |
| } else { |
| opts.UninterpretedOption = remain |
| } |
| } |
| } |
| } |
| return nil |
| } |
| |
| func interpretOptions(res *parseResult, element descriptorish, opts proto.Message, uninterpreted []*dpb.UninterpretedOption) ([]*dpb.UninterpretedOption, error) { |
| optsd, err := desc.LoadMessageDescriptorForMessage(opts) |
| if err != nil { |
| if res.lenient { |
| return uninterpreted, nil |
| } |
| return nil, err |
| } |
| dm := dynamic.NewMessage(optsd) |
| err = dm.ConvertFrom(opts) |
| if err != nil { |
| if res.lenient { |
| return uninterpreted, nil |
| } |
| node := res.nodes[element.AsProto()] |
| return nil, ErrorWithSourcePos{Pos: node.start(), Underlying: err} |
| } |
| |
| mc := &messageContext{res: res, file: element.GetFile(), elementName: element.GetFullyQualifiedName(), elementType: descriptorType(element.AsProto())} |
| var remain []*dpb.UninterpretedOption |
| for _, uo := range uninterpreted { |
| node := res.getOptionNode(uo) |
| if !uo.Name[0].GetIsExtension() && uo.Name[0].GetNamePart() == "uninterpreted_option" { |
| if res.lenient { |
| remain = append(remain, uo) |
| continue |
| } |
| // uninterpreted_option might be found reflectively, but is not actually valid for use |
| return nil, ErrorWithSourcePos{Pos: node.getName().start(), Underlying: fmt.Errorf("%vinvalid option 'uninterpreted_option'", mc)} |
| } |
| mc.option = uo |
| path, err := interpretField(res, mc, element, dm, uo, 0, nil) |
| if err != nil { |
| if res.lenient { |
| remain = append(remain, uo) |
| continue |
| } |
| return nil, err |
| } |
| if optn, ok := node.(*optionNode); ok { |
| res.interpretedOptions[optn] = path |
| } |
| } |
| |
| if err := dm.ValidateRecursive(); err != nil { |
| // if lenient, we'll let this pass, but it means that some required field was not set! |
| // TODO: do this in a more granular way, so we can validate individual fields |
| // and leave them uninterpreted, instead of just having to live with the |
| // thing having invalid data in extensions. |
| if !res.lenient { |
| node := res.nodes[element.AsProto()] |
| return nil, ErrorWithSourcePos{Pos: node.start(), Underlying: fmt.Errorf("error in %s options: %v", descriptorType(element.AsProto()), err)} |
| } |
| } |
| |
| if res.lenient { |
| // If we're lenient, then we don't want to clobber the passed in message |
| // and leave it partially populated. So we convert into a copy first |
| optsClone := proto.Clone(opts) |
| if err := dm.ConvertTo(optsClone); err != nil { |
| // TODO: do this in a more granular way, so we can convert individual |
| // fields and leave bad ones uninterpreted instead of skipping all of |
| // the work we've done so far. |
| return uninterpreted, nil |
| } |
| // conversion from dynamic message above worked, so now |
| // it is safe to overwrite the passed in message |
| opts.Reset() |
| proto.Merge(opts, optsClone) |
| |
| } else { |
| // not lenient: try to convert into the passed in message |
| // and fail is not successful |
| if err := dm.ConvertTo(opts); err != nil { |
| node := res.nodes[element.AsProto()] |
| return nil, ErrorWithSourcePos{Pos: node.start(), Underlying: err} |
| } |
| } |
| |
| return remain, nil |
| } |
| |
| func interpretField(res *parseResult, mc *messageContext, element descriptorish, dm *dynamic.Message, opt *dpb.UninterpretedOption, nameIndex int, pathPrefix []int32) (path []int32, err error) { |
| var fld *desc.FieldDescriptor |
| nm := opt.GetName()[nameIndex] |
| node := res.getOptionNamePartNode(nm) |
| if nm.GetIsExtension() { |
| extName := nm.GetNamePart() |
| if extName[0] == '.' { |
| extName = extName[1:] /* skip leading dot */ |
| } |
| fld = findExtension(element.GetFile(), extName, false, map[fileDescriptorish]struct{}{}) |
| if fld == nil { |
| return nil, ErrorWithSourcePos{ |
| Pos: node.start(), |
| Underlying: fmt.Errorf("%vunrecognized extension %s of %s", |
| mc, extName, dm.GetMessageDescriptor().GetFullyQualifiedName()), |
| } |
| } |
| if fld.GetOwner().GetFullyQualifiedName() != dm.GetMessageDescriptor().GetFullyQualifiedName() { |
| return nil, ErrorWithSourcePos{ |
| Pos: node.start(), |
| Underlying: fmt.Errorf("%vextension %s should extend %s but instead extends %s", |
| mc, extName, dm.GetMessageDescriptor().GetFullyQualifiedName(), fld.GetOwner().GetFullyQualifiedName()), |
| } |
| } |
| } else { |
| fld = dm.GetMessageDescriptor().FindFieldByName(nm.GetNamePart()) |
| if fld == nil { |
| return nil, ErrorWithSourcePos{ |
| Pos: node.start(), |
| Underlying: fmt.Errorf("%vfield %s of %s does not exist", |
| mc, nm.GetNamePart(), dm.GetMessageDescriptor().GetFullyQualifiedName()), |
| } |
| } |
| } |
| |
| path = append(pathPrefix, fld.GetNumber()) |
| |
| if len(opt.GetName()) > nameIndex+1 { |
| nextnm := opt.GetName()[nameIndex+1] |
| nextnode := res.getOptionNamePartNode(nextnm) |
| if fld.GetType() != dpb.FieldDescriptorProto_TYPE_MESSAGE { |
| return nil, ErrorWithSourcePos{ |
| Pos: nextnode.start(), |
| Underlying: fmt.Errorf("%vcannot set field %s because %s is not a message", |
| mc, nextnm.GetNamePart(), nm.GetNamePart()), |
| } |
| } |
| if fld.IsRepeated() { |
| return nil, ErrorWithSourcePos{ |
| Pos: nextnode.start(), |
| Underlying: fmt.Errorf("%vcannot set field %s because %s is repeated (must use an aggregate)", |
| mc, nextnm.GetNamePart(), nm.GetNamePart()), |
| } |
| } |
| var fdm *dynamic.Message |
| var err error |
| if dm.HasField(fld) { |
| var v interface{} |
| v, err = dm.TryGetField(fld) |
| fdm, _ = v.(*dynamic.Message) |
| } else { |
| fdm = dynamic.NewMessage(fld.GetMessageType()) |
| err = dm.TrySetField(fld, fdm) |
| } |
| if err != nil { |
| return nil, ErrorWithSourcePos{Pos: node.start(), Underlying: err} |
| } |
| // recurse to set next part of name |
| return interpretField(res, mc, element, fdm, opt, nameIndex+1, path) |
| } |
| |
| optNode := res.getOptionNode(opt) |
| if err := setOptionField(res, mc, dm, fld, node, optNode.getValue()); err != nil { |
| return nil, err |
| } |
| if fld.IsRepeated() { |
| path = append(path, int32(dm.FieldLength(fld))-1) |
| } |
| return path, nil |
| } |
| |
| func findExtension(fd fileDescriptorish, name string, public bool, checked map[fileDescriptorish]struct{}) *desc.FieldDescriptor { |
| if _, ok := checked[fd]; ok { |
| return nil |
| } |
| checked[fd] = struct{}{} |
| d := fd.FindSymbol(name) |
| if d != nil { |
| if fld, ok := d.(*desc.FieldDescriptor); ok { |
| return fld |
| } |
| return nil |
| } |
| |
| // When public = false, we are searching only directly imported symbols. But we |
| // also need to search transitive public imports due to semantics of public imports. |
| if public { |
| for _, dep := range fd.GetPublicDependencies() { |
| d := findExtension(dep, name, true, checked) |
| if d != nil { |
| return d |
| } |
| } |
| } else { |
| for _, dep := range fd.GetDependencies() { |
| d := findExtension(dep, name, true, checked) |
| if d != nil { |
| return d |
| } |
| } |
| } |
| return nil |
| } |
| |
| func setOptionField(res *parseResult, mc *messageContext, dm *dynamic.Message, fld *desc.FieldDescriptor, name node, val valueNode) error { |
| v := val.value() |
| if sl, ok := v.([]valueNode); ok { |
| // handle slices a little differently than the others |
| if !fld.IsRepeated() { |
| return ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vvalue is an array but field is not repeated", mc)} |
| } |
| origPath := mc.optAggPath |
| defer func() { |
| mc.optAggPath = origPath |
| }() |
| for index, item := range sl { |
| mc.optAggPath = fmt.Sprintf("%s[%d]", origPath, index) |
| if v, err := fieldValue(res, mc, richFldDescriptorish{FieldDescriptor: fld}, item, false); err != nil { |
| return err |
| } else if err = dm.TryAddRepeatedField(fld, v); err != nil { |
| return ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%verror setting value: %s", mc, err)} |
| } |
| } |
| return nil |
| } |
| |
| v, err := fieldValue(res, mc, richFldDescriptorish{FieldDescriptor: fld}, val, false) |
| if err != nil { |
| return err |
| } |
| if fld.IsRepeated() { |
| err = dm.TryAddRepeatedField(fld, v) |
| } else { |
| if dm.HasField(fld) { |
| return ErrorWithSourcePos{Pos: name.start(), Underlying: fmt.Errorf("%vnon-repeated option field %s already set", mc, fieldName(fld))} |
| } |
| err = dm.TrySetField(fld, v) |
| } |
| if err != nil { |
| return ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%verror setting value: %s", mc, err)} |
| } |
| |
| return nil |
| } |
| |
| type messageContext struct { |
| res *parseResult |
| file fileDescriptorish |
| elementType string |
| elementName string |
| option *dpb.UninterpretedOption |
| optAggPath string |
| } |
| |
| func (c *messageContext) String() string { |
| var ctx bytes.Buffer |
| if c.elementType != "file" { |
| fmt.Fprintf(&ctx, "%s %s: ", c.elementType, c.elementName) |
| } |
| if c.option != nil && c.option.Name != nil { |
| ctx.WriteString("option ") |
| writeOptionName(&ctx, c.option.Name) |
| if c.res.nodes == nil { |
| // if we have no source position info, try to provide as much context |
| // as possible (if nodes != nil, we don't need this because any errors |
| // will actually have file and line numbers) |
| if c.optAggPath != "" { |
| fmt.Fprintf(&ctx, " at %s", c.optAggPath) |
| } |
| } |
| ctx.WriteString(": ") |
| } |
| return ctx.String() |
| } |
| |
| func writeOptionName(buf *bytes.Buffer, parts []*dpb.UninterpretedOption_NamePart) { |
| first := true |
| for _, p := range parts { |
| if first { |
| first = false |
| } else { |
| buf.WriteByte('.') |
| } |
| nm := p.GetNamePart() |
| if nm[0] == '.' { |
| // skip leading dot |
| nm = nm[1:] |
| } |
| if p.GetIsExtension() { |
| buf.WriteByte('(') |
| buf.WriteString(nm) |
| buf.WriteByte(')') |
| } else { |
| buf.WriteString(nm) |
| } |
| } |
| } |
| |
| func fieldName(fld *desc.FieldDescriptor) string { |
| if fld.IsExtension() { |
| return fld.GetFullyQualifiedName() |
| } else { |
| return fld.GetName() |
| } |
| } |
| |
| func valueKind(val interface{}) string { |
| switch val := val.(type) { |
| case identifier: |
| return "identifier" |
| case bool: |
| return "bool" |
| case int64: |
| if val < 0 { |
| return "negative integer" |
| } |
| return "integer" |
| case uint64: |
| return "integer" |
| case float64: |
| return "double" |
| case string, []byte: |
| return "string" |
| case []*aggregateEntryNode: |
| return "message" |
| default: |
| return fmt.Sprintf("%T", val) |
| } |
| } |
| |
| func fieldValue(res *parseResult, mc *messageContext, fld fldDescriptorish, val valueNode, enumAsString bool) (interface{}, error) { |
| v := val.value() |
| t := fld.AsFieldDescriptorProto().GetType() |
| switch t { |
| case dpb.FieldDescriptorProto_TYPE_ENUM: |
| if id, ok := v.(identifier); ok { |
| ev := fld.GetEnumType().FindValueByName(string(id)) |
| if ev == nil { |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%venum %s has no value named %s", mc, fld.GetEnumType().GetFullyQualifiedName(), id)} |
| } |
| if enumAsString { |
| return ev.GetName(), nil |
| } else { |
| return ev.GetNumber(), nil |
| } |
| } |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vexpecting enum, got %s", mc, valueKind(v))} |
| case dpb.FieldDescriptorProto_TYPE_MESSAGE, dpb.FieldDescriptorProto_TYPE_GROUP: |
| if aggs, ok := v.([]*aggregateEntryNode); ok { |
| fmd := fld.GetMessageType() |
| fdm := dynamic.NewMessage(fmd) |
| origPath := mc.optAggPath |
| defer func() { |
| mc.optAggPath = origPath |
| }() |
| for _, a := range aggs { |
| if origPath == "" { |
| mc.optAggPath = a.name.value() |
| } else { |
| mc.optAggPath = origPath + "." + a.name.value() |
| } |
| var ffld *desc.FieldDescriptor |
| if a.name.isExtension { |
| n := a.name.name.val |
| ffld = findExtension(mc.file, n, false, map[fileDescriptorish]struct{}{}) |
| if ffld == nil { |
| // may need to qualify with package name |
| pkg := mc.file.GetPackage() |
| if pkg != "" { |
| ffld = findExtension(mc.file, pkg+"."+n, false, map[fileDescriptorish]struct{}{}) |
| } |
| } |
| } else { |
| ffld = fmd.FindFieldByName(a.name.value()) |
| } |
| if ffld == nil { |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vfield %s not found", mc, a.name.name.val)} |
| } |
| if err := setOptionField(res, mc, fdm, ffld, a.name, a.val); err != nil { |
| return nil, err |
| } |
| } |
| return fdm, nil |
| } |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vexpecting message, got %s", mc, valueKind(v))} |
| case dpb.FieldDescriptorProto_TYPE_BOOL: |
| if b, ok := v.(bool); ok { |
| return b, nil |
| } |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vexpecting bool, got %s", mc, valueKind(v))} |
| case dpb.FieldDescriptorProto_TYPE_BYTES: |
| if str, ok := v.(string); ok { |
| return []byte(str), nil |
| } |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vexpecting bytes, got %s", mc, valueKind(v))} |
| case dpb.FieldDescriptorProto_TYPE_STRING: |
| if str, ok := v.(string); ok { |
| return str, nil |
| } |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vexpecting string, got %s", mc, valueKind(v))} |
| case dpb.FieldDescriptorProto_TYPE_INT32, dpb.FieldDescriptorProto_TYPE_SINT32, dpb.FieldDescriptorProto_TYPE_SFIXED32: |
| if i, ok := v.(int64); ok { |
| if i > math.MaxInt32 || i < math.MinInt32 { |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vvalue %d is out of range for int32", mc, i)} |
| } |
| return int32(i), nil |
| } |
| if ui, ok := v.(uint64); ok { |
| if ui > math.MaxInt32 { |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vvalue %d is out of range for int32", mc, ui)} |
| } |
| return int32(ui), nil |
| } |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vexpecting int32, got %s", mc, valueKind(v))} |
| case dpb.FieldDescriptorProto_TYPE_UINT32, dpb.FieldDescriptorProto_TYPE_FIXED32: |
| if i, ok := v.(int64); ok { |
| if i > math.MaxUint32 || i < 0 { |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vvalue %d is out of range for uint32", mc, i)} |
| } |
| return uint32(i), nil |
| } |
| if ui, ok := v.(uint64); ok { |
| if ui > math.MaxUint32 { |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vvalue %d is out of range for uint32", mc, ui)} |
| } |
| return uint32(ui), nil |
| } |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vexpecting uint32, got %s", mc, valueKind(v))} |
| case dpb.FieldDescriptorProto_TYPE_INT64, dpb.FieldDescriptorProto_TYPE_SINT64, dpb.FieldDescriptorProto_TYPE_SFIXED64: |
| if i, ok := v.(int64); ok { |
| return i, nil |
| } |
| if ui, ok := v.(uint64); ok { |
| if ui > math.MaxInt64 { |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vvalue %d is out of range for int64", mc, ui)} |
| } |
| return int64(ui), nil |
| } |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vexpecting int64, got %s", mc, valueKind(v))} |
| case dpb.FieldDescriptorProto_TYPE_UINT64, dpb.FieldDescriptorProto_TYPE_FIXED64: |
| if i, ok := v.(int64); ok { |
| if i < 0 { |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vvalue %d is out of range for uint64", mc, i)} |
| } |
| return uint64(i), nil |
| } |
| if ui, ok := v.(uint64); ok { |
| return ui, nil |
| } |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vexpecting uint64, got %s", mc, valueKind(v))} |
| case dpb.FieldDescriptorProto_TYPE_DOUBLE: |
| if d, ok := v.(float64); ok { |
| return d, nil |
| } |
| if i, ok := v.(int64); ok { |
| return float64(i), nil |
| } |
| if u, ok := v.(uint64); ok { |
| return float64(u), nil |
| } |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vexpecting double, got %s", mc, valueKind(v))} |
| case dpb.FieldDescriptorProto_TYPE_FLOAT: |
| if d, ok := v.(float64); ok { |
| if (d > math.MaxFloat32 || d < -math.MaxFloat32) && !math.IsInf(d, 1) && !math.IsInf(d, -1) && !math.IsNaN(d) { |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vvalue %f is out of range for float", mc, d)} |
| } |
| return float32(d), nil |
| } |
| if i, ok := v.(int64); ok { |
| return float32(i), nil |
| } |
| if u, ok := v.(uint64); ok { |
| return float32(u), nil |
| } |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vexpecting float, got %s", mc, valueKind(v))} |
| default: |
| return nil, ErrorWithSourcePos{Pos: val.start(), Underlying: fmt.Errorf("%vunrecognized field type: %s", mc, t)} |
| } |
| } |