...

Source file src/github.com/golang/protobuf/descriptor/descriptor.go

Documentation: github.com/golang/protobuf/descriptor

     1  // Copyright 2016 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 descriptor provides functions for obtaining the protocol buffer
     6  // descriptors of generated Go types.
     7  //
     8  // Deprecated: See the "google.golang.org/protobuf/reflect/protoreflect" package
     9  // for how to obtain an EnumDescriptor or MessageDescriptor in order to
    10  // programatically interact with the protobuf type system.
    11  package descriptor
    12  
    13  import (
    14  	"bytes"
    15  	"compress/gzip"
    16  	"io/ioutil"
    17  	"sync"
    18  
    19  	"github.com/golang/protobuf/proto"
    20  	"google.golang.org/protobuf/reflect/protodesc"
    21  	"google.golang.org/protobuf/reflect/protoreflect"
    22  	"google.golang.org/protobuf/runtime/protoimpl"
    23  
    24  	descriptorpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
    25  )
    26  
    27  // Message is proto.Message with a method to return its descriptor.
    28  //
    29  // Deprecated: The Descriptor method may not be generated by future
    30  // versions of protoc-gen-go, meaning that this interface may not
    31  // be implemented by many concrete message types.
    32  type Message interface {
    33  	proto.Message
    34  	Descriptor() ([]byte, []int)
    35  }
    36  
    37  // ForMessage returns the file descriptor proto containing
    38  // the message and the message descriptor proto for the message itself.
    39  // The returned proto messages must not be mutated.
    40  //
    41  // Deprecated: Not all concrete message types satisfy the Message interface.
    42  // Use MessageDescriptorProto instead. If possible, the calling code should
    43  // be rewritten to use protobuf reflection instead.
    44  // See package "google.golang.org/protobuf/reflect/protoreflect" for details.
    45  func ForMessage(m Message) (*descriptorpb.FileDescriptorProto, *descriptorpb.DescriptorProto) {
    46  	return MessageDescriptorProto(m)
    47  }
    48  
    49  type rawDesc struct {
    50  	fileDesc []byte
    51  	indexes  []int
    52  }
    53  
    54  var rawDescCache sync.Map // map[protoreflect.Descriptor]*rawDesc
    55  
    56  func deriveRawDescriptor(d protoreflect.Descriptor) ([]byte, []int) {
    57  	// Fast-path: check whether raw descriptors are already cached.
    58  	origDesc := d
    59  	if v, ok := rawDescCache.Load(origDesc); ok {
    60  		return v.(*rawDesc).fileDesc, v.(*rawDesc).indexes
    61  	}
    62  
    63  	// Slow-path: derive the raw descriptor from the v2 descriptor.
    64  
    65  	// Start with the leaf (a given enum or message declaration) and
    66  	// ascend upwards until we hit the parent file descriptor.
    67  	var idxs []int
    68  	for {
    69  		idxs = append(idxs, d.Index())
    70  		d = d.Parent()
    71  		if d == nil {
    72  			// TODO: We could construct a FileDescriptor stub for standalone
    73  			// descriptors to satisfy the API.
    74  			return nil, nil
    75  		}
    76  		if _, ok := d.(protoreflect.FileDescriptor); ok {
    77  			break
    78  		}
    79  	}
    80  
    81  	// Obtain the raw file descriptor.
    82  	fd := d.(protoreflect.FileDescriptor)
    83  	b, _ := proto.Marshal(protodesc.ToFileDescriptorProto(fd))
    84  	file := protoimpl.X.CompressGZIP(b)
    85  
    86  	// Reverse the indexes, since we populated it in reverse.
    87  	for i, j := 0, len(idxs)-1; i < j; i, j = i+1, j-1 {
    88  		idxs[i], idxs[j] = idxs[j], idxs[i]
    89  	}
    90  
    91  	if v, ok := rawDescCache.LoadOrStore(origDesc, &rawDesc{file, idxs}); ok {
    92  		return v.(*rawDesc).fileDesc, v.(*rawDesc).indexes
    93  	}
    94  	return file, idxs
    95  }
    96  
    97  // EnumRawDescriptor returns the GZIP'd raw file descriptor representing
    98  // the enum and the index path to reach the enum declaration.
    99  // The returned slices must not be mutated.
   100  func EnumRawDescriptor(e proto.GeneratedEnum) ([]byte, []int) {
   101  	if ev, ok := e.(interface{ EnumDescriptor() ([]byte, []int) }); ok {
   102  		return ev.EnumDescriptor()
   103  	}
   104  	ed := protoimpl.X.EnumTypeOf(e)
   105  	return deriveRawDescriptor(ed.Descriptor())
   106  }
   107  
   108  // MessageRawDescriptor returns the GZIP'd raw file descriptor representing
   109  // the message and the index path to reach the message declaration.
   110  // The returned slices must not be mutated.
   111  func MessageRawDescriptor(m proto.GeneratedMessage) ([]byte, []int) {
   112  	if mv, ok := m.(interface{ Descriptor() ([]byte, []int) }); ok {
   113  		return mv.Descriptor()
   114  	}
   115  	md := protoimpl.X.MessageTypeOf(m)
   116  	return deriveRawDescriptor(md.Descriptor())
   117  }
   118  
   119  var fileDescCache sync.Map // map[*byte]*descriptorpb.FileDescriptorProto
   120  
   121  func deriveFileDescriptor(rawDesc []byte) *descriptorpb.FileDescriptorProto {
   122  	// Fast-path: check whether descriptor protos are already cached.
   123  	if v, ok := fileDescCache.Load(&rawDesc[0]); ok {
   124  		return v.(*descriptorpb.FileDescriptorProto)
   125  	}
   126  
   127  	// Slow-path: derive the descriptor proto from the GZIP'd message.
   128  	zr, err := gzip.NewReader(bytes.NewReader(rawDesc))
   129  	if err != nil {
   130  		panic(err)
   131  	}
   132  	b, err := ioutil.ReadAll(zr)
   133  	if err != nil {
   134  		panic(err)
   135  	}
   136  	fd := new(descriptorpb.FileDescriptorProto)
   137  	if err := proto.Unmarshal(b, fd); err != nil {
   138  		panic(err)
   139  	}
   140  	if v, ok := fileDescCache.LoadOrStore(&rawDesc[0], fd); ok {
   141  		return v.(*descriptorpb.FileDescriptorProto)
   142  	}
   143  	return fd
   144  }
   145  
   146  // EnumDescriptorProto returns the file descriptor proto representing
   147  // the enum and the enum descriptor proto for the enum itself.
   148  // The returned proto messages must not be mutated.
   149  func EnumDescriptorProto(e proto.GeneratedEnum) (*descriptorpb.FileDescriptorProto, *descriptorpb.EnumDescriptorProto) {
   150  	rawDesc, idxs := EnumRawDescriptor(e)
   151  	if rawDesc == nil || idxs == nil {
   152  		return nil, nil
   153  	}
   154  	fd := deriveFileDescriptor(rawDesc)
   155  	if len(idxs) == 1 {
   156  		return fd, fd.EnumType[idxs[0]]
   157  	}
   158  	md := fd.MessageType[idxs[0]]
   159  	for _, i := range idxs[1 : len(idxs)-1] {
   160  		md = md.NestedType[i]
   161  	}
   162  	ed := md.EnumType[idxs[len(idxs)-1]]
   163  	return fd, ed
   164  }
   165  
   166  // MessageDescriptorProto returns the file descriptor proto representing
   167  // the message and the message descriptor proto for the message itself.
   168  // The returned proto messages must not be mutated.
   169  func MessageDescriptorProto(m proto.GeneratedMessage) (*descriptorpb.FileDescriptorProto, *descriptorpb.DescriptorProto) {
   170  	rawDesc, idxs := MessageRawDescriptor(m)
   171  	if rawDesc == nil || idxs == nil {
   172  		return nil, nil
   173  	}
   174  	fd := deriveFileDescriptor(rawDesc)
   175  	md := fd.MessageType[idxs[0]]
   176  	for _, i := range idxs[1:] {
   177  		md = md.NestedType[i]
   178  	}
   179  	return fd, md
   180  }
   181  

View as plain text