Index: common/proto/google/descutil/util.go |
diff --git a/common/proto/google/descutil/util.go b/common/proto/google/descutil/util.go |
new file mode 100644 |
index 0000000000000000000000000000000000000000..881a1c309228c6ce867525e8f8a013c320e2ea26 |
--- /dev/null |
+++ b/common/proto/google/descutil/util.go |
@@ -0,0 +1,251 @@ |
+// Copyright 2015 The LUCI Authors. All rights reserved. |
+// Use of this source code is governed under the Apache License, Version 2.0 |
+// that can be found in the LICENSE file. |
+ |
+package descutil |
+ |
+import ( |
+ "strings" |
+ |
+ pb "google.golang.org/genproto/protobuf" |
+) |
+ |
+// splitFullName splits package name and service/type name. |
+func splitFullName(fullName string) (pkg string, name string) { |
+ lastDot := strings.LastIndex(fullName, ".") |
+ if lastDot < 0 { |
+ return "", fullName |
+ } |
+ return fullName[:lastDot], fullName[lastDot+1:] |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// FileDescriptorSet |
+ |
+// FindFile searches for a FileDescriptorProto by name. |
+func FindFile(s *pb.FileDescriptorSet, name string) int { |
+ for i, x := range s.GetFile() { |
+ if x.GetName() == name { |
+ return i |
+ } |
+ } |
+ return -1 |
+} |
+ |
+// Resolve searches for an object by full name. obj can be one of |
+// *ServiceDescriptorProto, |
+// *MethodDescriptorProto, |
+// *DescriptorProto, |
+// *FieldDescriptorProto, |
+// *DescriptorProto, |
+// *EnumDescriptorProto, |
+// *EnumValueDescriptorProto or |
+// nil |
+// |
+// For path, see comment in SourceCodeInfo message. |
+func Resolve(s *pb.FileDescriptorSet, fullName string) (file *pb.FileDescriptorProto, obj interface{}, path []int) { |
+ if fullName == "" { |
+ return nil, nil, nil |
+ } |
+ pkg, name := splitFullName(fullName) |
+ |
+ // Check top-level objects. |
+ for _, f := range s.GetFile() { |
+ if f.GetPackage() == pkg { |
+ if i := FindServiceForFile(f, name); i != -1 { |
+ return f, f.Service[i], []int{FileDescriptorProtoServiceTag, i} |
+ } |
+ if i := FindMessageForFile(f, name); i != -1 { |
+ return f, f.MessageType[i], []int{FileDescriptorProtoMessageTag, i} |
+ } |
+ if i := FindEnumForFile(f, name); i != -1 { |
+ return f, f.EnumType[i], []int{FileDescriptorProtoEnumTag, i} |
+ } |
+ } |
+ } |
+ |
+ // Recurse. |
+ var parent interface{} |
+ file, parent, path = Resolve(s, pkg) |
+ switch parent := parent.(type) { |
+ |
+ case *pb.ServiceDescriptorProto: |
+ if i := FindMethodForService(parent, name); i != -1 { |
+ return file, parent.Method[i], append(path, ServiceDescriptorProtoMethodTag, i) |
+ } |
+ |
+ case *pb.DescriptorProto: |
+ if i := FindMessage(parent, name); i != -1 { |
+ return file, parent.NestedType[i], append(path, DescriptorProtoNestedTypeTag, i) |
+ } |
+ if i := FindEnum(parent, name); i != -1 { |
+ return file, parent.EnumType[i], append(path, DescriptorProtoEnumTypeTag, i) |
+ } |
+ if i := FindField(parent, name); i != -1 { |
+ return file, parent.Field[i], append(path, DescriptorProtoFieldTag, i) |
+ } |
+ if i := FindOneOf(parent, name); i != -1 { |
+ return file, parent.OneofDecl[i], append(path, DescriptorProtoOneOfTag, i) |
+ } |
+ |
+ case *pb.EnumDescriptorProto: |
+ if i := FindEnumValue(parent, name); i != -1 { |
+ return file, parent.Value[i], append(path, EnumDescriptorProtoValueTag, i) |
+ } |
+ } |
+ |
+ return nil, nil, nil |
+} |
+ |
+// FindService searches for a service by full name. |
+func FindService(s *pb.FileDescriptorSet, fullName string) (file *pb.FileDescriptorProto, serviceIndex int) { |
+ pkg, name := splitFullName(fullName) |
+ for _, f := range s.GetFile() { |
+ if f.GetPackage() == pkg { |
+ if i := FindServiceForFile(f, name); i != -1 { |
+ return f, i |
+ } |
+ } |
+ } |
+ return nil, -1 |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// FileDescriptorProto |
+ |
+// FindServiceForFile searches for a FileDescriptorProto by name. |
+func FindServiceForFile(f *pb.FileDescriptorProto, name string) int { |
+ for i, x := range f.GetService() { |
+ if x.GetName() == name { |
+ return i |
+ } |
+ } |
+ return -1 |
+} |
+ |
+// FindMessageForFile searches for a DescriptorProto by name. |
+func FindMessageForFile(f *pb.FileDescriptorProto, name string) int { |
+ for i, x := range f.GetMessageType() { |
+ if x.GetName() == name { |
+ return i |
+ } |
+ } |
+ return -1 |
+} |
+ |
+// FindEnumForFile searches for an EnumDescriptorProto by name. |
+func FindEnumForFile(f *pb.FileDescriptorProto, name string) int { |
+ for i, x := range f.GetEnumType() { |
+ if x.GetName() == name { |
+ return i |
+ } |
+ } |
+ return -1 |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// ServiceDescriptorProto |
+ |
+// FindMethodForService searches for a MethodDescriptorProto by name. |
+func FindMethodForService(s *pb.ServiceDescriptorProto, name string) int { |
+ for i, x := range s.GetMethod() { |
+ if x.GetName() == name { |
+ return i |
+ } |
+ } |
+ return -1 |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// DescriptorProto (a message) |
+ |
+// FindField searches for a FieldDescriptorProto by name. |
+func FindField(d *pb.DescriptorProto, name string) int { |
+ for i, x := range d.GetField() { |
+ if x.GetName() == name { |
+ return i |
+ } |
+ } |
+ return -1 |
+} |
+ |
+// FindMessage searches for a nested DescriptorProto by name. |
+func FindMessage(d *pb.DescriptorProto, name string) int { |
+ for i, x := range d.GetNestedType() { |
+ if x.GetName() == name { |
+ return i |
+ } |
+ } |
+ return -1 |
+} |
+ |
+// FindEnum searches for a nested EnumDescriptorProto by name. |
+func FindEnum(d *pb.DescriptorProto, name string) int { |
+ for i, x := range d.GetEnumType() { |
+ if x.GetName() == name { |
+ return i |
+ } |
+ } |
+ return -1 |
+} |
+ |
+// FindOneOf searches for a nested OneofDescriptorProto by name. |
+func FindOneOf(d *pb.DescriptorProto, name string) int { |
+ for i, x := range d.GetOneofDecl() { |
+ if x.GetName() == name { |
+ return i |
+ } |
+ } |
+ return -1 |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// FieldDescriptorProto |
+ |
+// Repeated returns true if the field is repeated. |
+func Repeated(f *pb.FieldDescriptorProto) bool { |
+ return f.GetLabel() == pb.FieldDescriptorProto_LABEL_REPEATED |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// EnumDescriptorProto |
+ |
+// FindEnumValue searches for an EnumValueDescriptorProto by name. |
+func FindEnumValue(e *pb.EnumDescriptorProto, name string) int { |
+ for i, x := range e.GetValue() { |
+ if x.GetName() == name { |
+ return i |
+ } |
+ } |
+ return -1 |
+} |
+ |
+// FindValueByNumber searches for an EnumValueDescriptorProto by number. |
+func FindValueByNumber(e *pb.EnumDescriptorProto, number int32) int { |
+ for i, x := range e.GetValue() { |
+ if x.GetNumber() == number { |
+ return i |
+ } |
+ } |
+ return -1 |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// SourceCodeInfo |
+ |
+// FindLocation searches for a location by path. |
+func FindLocation(s *pb.SourceCodeInfo, path []int) *pb.SourceCodeInfo_Location { |
+Outer: |
+ for _, l := range s.GetLocation() { |
+ if len(path) != len(l.Path) { |
+ continue |
+ } |
+ for i := range path { |
+ if int32(path[i]) != l.Path[i] { |
+ continue Outer |
+ } |
+ } |
+ return l |
+ } |
+ return nil |
+} |