github.com/jhump/protoreflect@v1.16.0/desc/wrap.go (about)

     1  package desc
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/bufbuild/protocompile/protoutil"
     7  	"google.golang.org/protobuf/reflect/protoreflect"
     8  )
     9  
    10  // DescriptorWrapper wraps a protoreflect.Descriptor. All of the Descriptor
    11  // implementations in this package implement this interface. This can be
    12  // used to recover the underlying descriptor. Each descriptor type in this
    13  // package also provides a strongly-typed form of this method, such as the
    14  // following method for *FileDescriptor:
    15  //
    16  //	UnwrapFile() protoreflect.FileDescriptor
    17  type DescriptorWrapper interface {
    18  	Unwrap() protoreflect.Descriptor
    19  }
    20  
    21  // WrapDescriptor wraps the given descriptor, returning a desc.Descriptor
    22  // value that represents the same element.
    23  func WrapDescriptor(d protoreflect.Descriptor) (Descriptor, error) {
    24  	return wrapDescriptor(d, mapCache{})
    25  }
    26  
    27  func wrapDescriptor(d protoreflect.Descriptor, cache descriptorCache) (Descriptor, error) {
    28  	switch d := d.(type) {
    29  	case protoreflect.FileDescriptor:
    30  		return wrapFile(d, cache)
    31  	case protoreflect.MessageDescriptor:
    32  		return wrapMessage(d, cache)
    33  	case protoreflect.FieldDescriptor:
    34  		return wrapField(d, cache)
    35  	case protoreflect.OneofDescriptor:
    36  		return wrapOneOf(d, cache)
    37  	case protoreflect.EnumDescriptor:
    38  		return wrapEnum(d, cache)
    39  	case protoreflect.EnumValueDescriptor:
    40  		return wrapEnumValue(d, cache)
    41  	case protoreflect.ServiceDescriptor:
    42  		return wrapService(d, cache)
    43  	case protoreflect.MethodDescriptor:
    44  		return wrapMethod(d, cache)
    45  	default:
    46  		return nil, fmt.Errorf("unknown descriptor type: %T", d)
    47  	}
    48  }
    49  
    50  // WrapFiles wraps the given file descriptors, returning a slice of *desc.FileDescriptor
    51  // values that represent the same files.
    52  func WrapFiles(d []protoreflect.FileDescriptor) ([]*FileDescriptor, error) {
    53  	cache := mapCache{}
    54  	results := make([]*FileDescriptor, len(d))
    55  	for i := range d {
    56  		var err error
    57  		results[i], err = wrapFile(d[i], cache)
    58  		if err != nil {
    59  			return nil, err
    60  		}
    61  	}
    62  	return results, nil
    63  }
    64  
    65  // WrapFile wraps the given file descriptor, returning a *desc.FileDescriptor
    66  // value that represents the same file.
    67  func WrapFile(d protoreflect.FileDescriptor) (*FileDescriptor, error) {
    68  	return wrapFile(d, mapCache{})
    69  }
    70  
    71  func wrapFile(d protoreflect.FileDescriptor, cache descriptorCache) (*FileDescriptor, error) {
    72  	if res := cache.get(d); res != nil {
    73  		return res.(*FileDescriptor), nil
    74  	}
    75  	fdp := protoutil.ProtoFromFileDescriptor(d)
    76  	return convertFile(d, fdp, cache)
    77  }
    78  
    79  // WrapMessage wraps the given message descriptor, returning a *desc.MessageDescriptor
    80  // value that represents the same message.
    81  func WrapMessage(d protoreflect.MessageDescriptor) (*MessageDescriptor, error) {
    82  	return wrapMessage(d, mapCache{})
    83  }
    84  
    85  func wrapMessage(d protoreflect.MessageDescriptor, cache descriptorCache) (*MessageDescriptor, error) {
    86  	parent, err := wrapDescriptor(d.Parent(), cache)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	switch p := parent.(type) {
    91  	case *FileDescriptor:
    92  		return p.messages[d.Index()], nil
    93  	case *MessageDescriptor:
    94  		return p.nested[d.Index()], nil
    95  	default:
    96  		return nil, fmt.Errorf("message has unexpected parent type: %T", parent)
    97  	}
    98  }
    99  
   100  // WrapField wraps the given field descriptor, returning a *desc.FieldDescriptor
   101  // value that represents the same field.
   102  func WrapField(d protoreflect.FieldDescriptor) (*FieldDescriptor, error) {
   103  	return wrapField(d, mapCache{})
   104  }
   105  
   106  func wrapField(d protoreflect.FieldDescriptor, cache descriptorCache) (*FieldDescriptor, error) {
   107  	parent, err := wrapDescriptor(d.Parent(), cache)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	switch p := parent.(type) {
   112  	case *FileDescriptor:
   113  		return p.extensions[d.Index()], nil
   114  	case *MessageDescriptor:
   115  		if d.IsExtension() {
   116  			return p.extensions[d.Index()], nil
   117  		}
   118  		return p.fields[d.Index()], nil
   119  	default:
   120  		return nil, fmt.Errorf("field has unexpected parent type: %T", parent)
   121  	}
   122  }
   123  
   124  // WrapOneOf wraps the given oneof descriptor, returning a *desc.OneOfDescriptor
   125  // value that represents the same oneof.
   126  func WrapOneOf(d protoreflect.OneofDescriptor) (*OneOfDescriptor, error) {
   127  	return wrapOneOf(d, mapCache{})
   128  }
   129  
   130  func wrapOneOf(d protoreflect.OneofDescriptor, cache descriptorCache) (*OneOfDescriptor, error) {
   131  	parent, err := wrapDescriptor(d.Parent(), cache)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  	if p, ok := parent.(*MessageDescriptor); ok {
   136  		return p.oneOfs[d.Index()], nil
   137  	}
   138  	return nil, fmt.Errorf("oneof has unexpected parent type: %T", parent)
   139  }
   140  
   141  // WrapEnum wraps the given enum descriptor, returning a *desc.EnumDescriptor
   142  // value that represents the same enum.
   143  func WrapEnum(d protoreflect.EnumDescriptor) (*EnumDescriptor, error) {
   144  	return wrapEnum(d, mapCache{})
   145  }
   146  
   147  func wrapEnum(d protoreflect.EnumDescriptor, cache descriptorCache) (*EnumDescriptor, error) {
   148  	parent, err := wrapDescriptor(d.Parent(), cache)
   149  	if err != nil {
   150  		return nil, err
   151  	}
   152  	switch p := parent.(type) {
   153  	case *FileDescriptor:
   154  		return p.enums[d.Index()], nil
   155  	case *MessageDescriptor:
   156  		return p.enums[d.Index()], nil
   157  	default:
   158  		return nil, fmt.Errorf("enum has unexpected parent type: %T", parent)
   159  	}
   160  }
   161  
   162  // WrapEnumValue wraps the given enum value descriptor, returning a *desc.EnumValueDescriptor
   163  // value that represents the same enum value.
   164  func WrapEnumValue(d protoreflect.EnumValueDescriptor) (*EnumValueDescriptor, error) {
   165  	return wrapEnumValue(d, mapCache{})
   166  }
   167  
   168  func wrapEnumValue(d protoreflect.EnumValueDescriptor, cache descriptorCache) (*EnumValueDescriptor, error) {
   169  	parent, err := wrapDescriptor(d.Parent(), cache)
   170  	if err != nil {
   171  		return nil, err
   172  	}
   173  	if p, ok := parent.(*EnumDescriptor); ok {
   174  		return p.values[d.Index()], nil
   175  	}
   176  	return nil, fmt.Errorf("enum value has unexpected parent type: %T", parent)
   177  }
   178  
   179  // WrapService wraps the given service descriptor, returning a *desc.ServiceDescriptor
   180  // value that represents the same service.
   181  func WrapService(d protoreflect.ServiceDescriptor) (*ServiceDescriptor, error) {
   182  	return wrapService(d, mapCache{})
   183  }
   184  
   185  func wrapService(d protoreflect.ServiceDescriptor, cache descriptorCache) (*ServiceDescriptor, error) {
   186  	parent, err := wrapDescriptor(d.Parent(), cache)
   187  	if err != nil {
   188  		return nil, err
   189  	}
   190  	if p, ok := parent.(*FileDescriptor); ok {
   191  		return p.services[d.Index()], nil
   192  	}
   193  	return nil, fmt.Errorf("service has unexpected parent type: %T", parent)
   194  }
   195  
   196  // WrapMethod wraps the given method descriptor, returning a *desc.MethodDescriptor
   197  // value that represents the same method.
   198  func WrapMethod(d protoreflect.MethodDescriptor) (*MethodDescriptor, error) {
   199  	return wrapMethod(d, mapCache{})
   200  }
   201  
   202  func wrapMethod(d protoreflect.MethodDescriptor, cache descriptorCache) (*MethodDescriptor, error) {
   203  	parent, err := wrapDescriptor(d.Parent(), cache)
   204  	if err != nil {
   205  		return nil, err
   206  	}
   207  	if p, ok := parent.(*ServiceDescriptor); ok {
   208  		return p.methods[d.Index()], nil
   209  	}
   210  	return nil, fmt.Errorf("method has unexpected parent type: %T", parent)
   211  }