protobuf/reflect/file/
mod.rs
1use std::collections::HashSet;
2use std::hash::Hash;
3use std::hash::Hasher;
4use std::sync::Arc;
5
6use crate::descriptor::DescriptorProto;
7use crate::descriptor::FileDescriptorProto;
8use crate::reflect::file::dynamic::DynamicFileDescriptor;
9use crate::reflect::file::fds::build_fds;
10use crate::reflect::file::index::EnumIndices;
11use crate::reflect::file::index::FileDescriptorCommon;
12use crate::reflect::file::index::MessageIndices;
13use crate::reflect::name::protobuf_name_starts_with_package;
14use crate::reflect::service::ServiceDescriptor;
15use crate::reflect::EnumDescriptor;
16use crate::reflect::FieldDescriptor;
17use crate::reflect::GeneratedFileDescriptor;
18use crate::reflect::MessageDescriptor;
19use crate::reflect::Syntax;
20
21pub(crate) mod building;
22pub(crate) mod dynamic;
23pub(crate) mod fds;
24pub(crate) mod generated;
25pub(crate) mod index;
26pub(crate) mod syntax;
27
28#[derive(Clone, Debug)]
29pub(crate) enum FileDescriptorImpl {
30 Generated(&'static GeneratedFileDescriptor),
31 Dynamic(Arc<DynamicFileDescriptor>),
32}
33
34impl PartialEq for FileDescriptorImpl {
35 fn eq(&self, other: &Self) -> bool {
36 match (self, other) {
37 (FileDescriptorImpl::Generated(a), FileDescriptorImpl::Generated(b)) => {
38 *a as *const GeneratedFileDescriptor == *b as *const GeneratedFileDescriptor
39 }
40 (FileDescriptorImpl::Dynamic(a), FileDescriptorImpl::Dynamic(b)) => Arc::ptr_eq(a, b),
41 _ => false,
42 }
43 }
44}
45
46impl Hash for FileDescriptorImpl {
47 fn hash<H: Hasher>(&self, state: &mut H) {
48 match self {
49 FileDescriptorImpl::Generated(g) => {
50 Hash::hash(&(*g as *const GeneratedFileDescriptor), state)
51 }
52 FileDescriptorImpl::Dynamic(a) => {
53 Hash::hash(&(&**a as *const DynamicFileDescriptor), state)
54 }
55 }
56 }
57}
58
59impl Eq for FileDescriptorImpl {}
60
61#[derive(Clone, PartialEq, Eq, Hash, Debug)]
69pub struct FileDescriptor {
70 pub(crate) imp: FileDescriptorImpl,
71}
72
73impl FileDescriptor {
74 pub(crate) fn common(&self) -> &FileDescriptorCommon {
75 match &self.imp {
76 FileDescriptorImpl::Generated(g) => &g.common,
77 FileDescriptorImpl::Dynamic(d) => &d.common,
78 }
79 }
80
81 pub(crate) fn common_for_generated_descriptor(&self) -> &'static FileDescriptorCommon {
83 match &self.imp {
84 FileDescriptorImpl::Generated(g) => &g.common,
85 FileDescriptorImpl::Dynamic(..) => panic!("not generated"),
86 }
87 }
88
89 pub(crate) fn message_indices(&self, index: usize) -> &MessageIndices {
90 &self.common().messages[index]
91 }
92
93 pub(crate) fn message_by_index(&self, index: usize) -> MessageDescriptor {
94 MessageDescriptor {
95 file_descriptor: self.clone(),
96 index,
97 }
98 }
99
100 pub(crate) fn message_proto_by_index(&self, index: usize) -> &DescriptorProto {
101 &self.common().messages[index].proto
102 }
103
104 pub(crate) fn enum_indices(&self, index: usize) -> &EnumIndices {
105 &self.common().enums[index]
106 }
107
108 pub fn name(&self) -> &str {
110 self.proto().name()
111 }
112
113 pub fn package(&self) -> &str {
115 self.proto().package()
116 }
117
118 pub fn syntax(&self) -> Syntax {
120 Syntax::parse(self.proto().syntax()).unwrap_or(Syntax::Proto2)
121 }
122
123 pub fn messages(&self) -> impl Iterator<Item = MessageDescriptor> + '_ {
125 self.common()
126 .top_level_messages
127 .iter()
128 .map(|i| MessageDescriptor::new(self.clone(), *i))
129 }
130
131 pub fn enums(&self) -> impl Iterator<Item = EnumDescriptor> + '_ {
133 self.proto()
134 .enum_type
135 .iter()
136 .enumerate()
137 .map(|(i, _)| EnumDescriptor::new(self.clone(), i))
138 }
139
140 pub fn services(&self) -> impl Iterator<Item = ServiceDescriptor> + '_ {
142 self.proto()
143 .service
144 .iter()
145 .enumerate()
146 .map(|(i, _)| ServiceDescriptor::new(self.clone(), i))
147 }
148
149 pub fn extensions(&self) -> impl Iterator<Item = FieldDescriptor> + '_ {
151 self.common()
152 .extension_field_range()
153 .map(move |index| FieldDescriptor {
154 file_descriptor: self.clone(),
155 index,
156 })
157 }
158
159 pub fn message_by_package_relative_name(&self, name: &str) -> Option<MessageDescriptor> {
163 self.common()
164 .message_by_name_to_package
165 .get(name)
166 .map(|&index| MessageDescriptor::new(self.clone(), index))
167 }
168
169 pub fn enum_by_package_relative_name(&self, name: &str) -> Option<EnumDescriptor> {
173 self.common()
174 .enums_by_name_to_package
175 .get(name)
176 .map(|&index| EnumDescriptor::new(self.clone(), index))
177 }
178
179 pub fn message_by_full_name(&self, name: &str) -> Option<MessageDescriptor> {
183 if let Some(name_to_package) =
184 protobuf_name_starts_with_package(name, self.proto().package())
185 {
186 self.message_by_package_relative_name(name_to_package)
187 } else {
188 None
189 }
190 }
191
192 pub fn enum_by_full_name(&self, name: &str) -> Option<EnumDescriptor> {
196 if let Some(name_to_package) =
197 protobuf_name_starts_with_package(name, self.proto().package())
198 {
199 self.enum_by_package_relative_name(name_to_package)
200 } else {
201 None
202 }
203 }
204
205 #[doc(hidden)]
207 pub fn new_generated_2(generated: &'static GeneratedFileDescriptor) -> FileDescriptor {
208 FileDescriptor {
209 imp: FileDescriptorImpl::Generated(generated),
210 }
211 }
212
213 pub fn new_dynamic(
215 proto: FileDescriptorProto,
216 dependencies: &[FileDescriptor],
217 ) -> crate::Result<FileDescriptor> {
218 Ok(FileDescriptor {
219 imp: FileDescriptorImpl::Dynamic(Arc::new(DynamicFileDescriptor::new(
220 proto,
221 dependencies,
222 )?)),
223 })
224 }
225
226 pub fn new_dynamic_fds(
228 protos: Vec<FileDescriptorProto>,
229 dependencies: &[FileDescriptor],
230 ) -> crate::Result<Vec<FileDescriptor>> {
231 build_fds(protos, dependencies)
232 }
233
234 pub fn proto(&self) -> &FileDescriptorProto {
236 match &self.imp {
237 FileDescriptorImpl::Generated(g) => &g.proto,
238 FileDescriptorImpl::Dynamic(d) => &d.proto,
239 }
240 }
241
242 pub fn deps(&self) -> &[FileDescriptor] {
244 &self.common().dependencies
245 }
246
247 pub fn public_deps(&self) -> impl Iterator<Item = FileDescriptor> + '_ {
249 self.proto()
250 .public_dependency
251 .iter()
252 .map(|&i| self.deps()[i as usize].clone())
253 }
254
255 fn _all_files(&self) -> Vec<&FileDescriptor> {
256 let mut r = Vec::new();
257 let mut visited = HashSet::new();
258
259 let mut stack = Vec::new();
260 stack.push(self);
261 while let Some(file) = stack.pop() {
262 if !visited.insert(file) {
263 continue;
264 }
265
266 r.push(file);
267 stack.extend(file.deps());
268 }
269
270 r
271 }
272}
273
274#[cfg(test)]
275mod test {
276 use crate::descriptor;
277
278 #[test]
279 #[cfg_attr(miri, ignore)]
280 fn eq() {
281 assert!(descriptor::file_descriptor() == &descriptor::file_descriptor().clone());
282 }
283}