blob: 5491afda1e8f8a9f730d26e57e5bdada90e4a20b [file] [log] [blame]
Abhay Kumar40252eb2025-10-13 13:25:53 +00001package desc
2
3import (
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
17type 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.
23func WrapDescriptor(d protoreflect.Descriptor) (Descriptor, error) {
24 return wrapDescriptor(d, mapCache{})
25}
26
27func 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.
52func 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.
67func WrapFile(d protoreflect.FileDescriptor) (*FileDescriptor, error) {
68 return wrapFile(d, mapCache{})
69}
70
71func 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.
81func WrapMessage(d protoreflect.MessageDescriptor) (*MessageDescriptor, error) {
82 return wrapMessage(d, mapCache{})
83}
84
85func 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.
102func WrapField(d protoreflect.FieldDescriptor) (*FieldDescriptor, error) {
103 return wrapField(d, mapCache{})
104}
105
106func 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.
126func WrapOneOf(d protoreflect.OneofDescriptor) (*OneOfDescriptor, error) {
127 return wrapOneOf(d, mapCache{})
128}
129
130func 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.
143func WrapEnum(d protoreflect.EnumDescriptor) (*EnumDescriptor, error) {
144 return wrapEnum(d, mapCache{})
145}
146
147func 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.
164func WrapEnumValue(d protoreflect.EnumValueDescriptor) (*EnumValueDescriptor, error) {
165 return wrapEnumValue(d, mapCache{})
166}
167
168func 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.
181func WrapService(d protoreflect.ServiceDescriptor) (*ServiceDescriptor, error) {
182 return wrapService(d, mapCache{})
183}
184
185func 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.
198func WrapMethod(d protoreflect.MethodDescriptor) (*MethodDescriptor, error) {
199 return wrapMethod(d, mapCache{})
200}
201
202func 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}