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