protobuf/reflect/file/
index.rs

1use std::collections::HashMap;
2use std::ops::Range;
3
4use crate::descriptor::field_descriptor_proto::Label;
5use crate::descriptor::DescriptorProto;
6use crate::descriptor::EnumDescriptorProto;
7use crate::descriptor::FileDescriptorProto;
8use crate::owning_ref::OwningRef;
9use crate::reflect::error::ReflectError;
10use crate::reflect::field::index::FieldIndex;
11use crate::reflect::file::building::FileDescriptorBuilding;
12use crate::reflect::file::fds::fds_extend_with_public;
13use crate::reflect::message::is_initialized_is_always_true::compute_is_initialized_is_always_true;
14use crate::reflect::name::concat_paths;
15use crate::reflect::service::index::ServiceIndex;
16use crate::reflect::FileDescriptor;
17
18#[derive(Debug)]
19pub(crate) struct MessageIndices {
20    pub(crate) proto: OwningRef<FileDescriptorProto, DescriptorProto>,
21    pub(crate) name_to_package: String,
22    pub(crate) full_name: String,
23    pub(crate) enclosing_message: Option<usize>,
24    pub(crate) nested_messages: Vec<usize>,
25    pub(crate) nested_enums: Range<usize>,
26    pub(crate) oneofs: Range<usize>,
27    pub(crate) map_entry: bool,
28    pub(crate) message_index: MessageFieldIndices,
29    pub(crate) is_initialized_is_always_true: bool,
30}
31
32#[derive(Debug, Default)]
33pub(crate) struct MessageFieldIndices {
34    /// Index of the first field in global field index.
35    pub(crate) first_field_index: usize,
36    pub(crate) field_count: usize,
37    /// Extensions follow fields in global field index.
38    pub(crate) extension_count: usize,
39    // Following fields map to the local field index.
40    pub(crate) field_index_by_name: HashMap<String, usize>,
41    pub(crate) field_index_by_name_or_json_name: HashMap<String, usize>,
42    pub(crate) field_index_by_number: HashMap<u32, usize>,
43}
44
45impl MessageFieldIndices {
46    pub(crate) fn regular_field_range(&self) -> Range<usize> {
47        self.first_field_index..(self.first_field_index + self.field_count)
48    }
49
50    pub(crate) fn extension_field_range(&self) -> Range<usize> {
51        self.first_field_index + self.field_count
52            ..self.first_field_index + self.field_count + self.extension_count
53    }
54
55    pub(crate) fn slice_fields<'a>(&self, file_fields: &'a [FieldIndex]) -> &'a [FieldIndex] {
56        &file_fields[self.first_field_index..self.first_field_index + self.field_count]
57    }
58}
59
60#[derive(Debug)]
61pub(crate) struct EnumIndices {
62    pub(crate) proto: OwningRef<FileDescriptorProto, EnumDescriptorProto>,
63    pub(crate) name_to_package: String,
64    pub(crate) full_name: String,
65    pub(crate) enclosing_message: Option<usize>,
66    pub(crate) index_by_name: HashMap<String, usize>,
67    pub(crate) index_by_number: HashMap<i32, usize>,
68}
69
70impl EnumIndices {
71    pub(crate) fn new(
72        name_to_package: String,
73        enclosing_message: Option<usize>,
74        proto: OwningRef<FileDescriptorProto, EnumDescriptorProto>,
75        file: &FileDescriptorProto,
76    ) -> EnumIndices {
77        let mut index_by_name = HashMap::new();
78        let mut index_by_number = HashMap::new();
79        for (i, v) in proto.value.iter().enumerate() {
80            index_by_number.insert(v.number(), i);
81            index_by_name.insert(v.name().to_owned(), i);
82        }
83        let full_name = concat_paths(file.package(), &name_to_package);
84        EnumIndices {
85            proto,
86            full_name,
87            name_to_package,
88            enclosing_message,
89            index_by_name,
90            index_by_number,
91        }
92    }
93}
94
95#[derive(Debug)]
96pub(crate) struct OneofIndices {
97    pub(crate) containing_message: usize,
98    pub(crate) index_in_containing_message: usize,
99    /// Synthetic oneof for proto3 optional field.
100    pub(crate) synthetic: bool,
101    pub(crate) fields: Vec<usize>,
102}
103
104/// Common `FileDescriptor` data for generated and dynamic file descriptors.
105#[derive(Debug)]
106pub(crate) struct FileDescriptorCommon {
107    /// Direct dependencies of this file.
108    pub(crate) dependencies: Vec<FileDescriptor>,
109    /// All messages in this file.
110    pub(crate) messages: Vec<MessageIndices>,
111    pub(crate) message_by_name_to_package: HashMap<String, usize>,
112    pub(crate) top_level_messages: Vec<usize>,
113    pub(crate) enums: Vec<EnumIndices>,
114    pub(crate) enums_by_name_to_package: HashMap<String, usize>,
115    pub(crate) oneofs: Vec<OneofIndices>,
116    pub(crate) services: Vec<ServiceIndex>,
117    pub(crate) first_extension_field_index: usize,
118    /// All fields followed by file-level extensions.
119    pub(crate) fields: Vec<FieldIndex>,
120}
121
122impl FileDescriptorCommon {
123    pub(crate) fn extension_field_range(&self) -> Range<usize> {
124        self.first_extension_field_index..self.fields.len()
125    }
126
127    pub(crate) fn new(
128        file: OwningRef<FileDescriptorProto, FileDescriptorProto>,
129        dependencies: Vec<FileDescriptor>,
130    ) -> crate::Result<FileDescriptorCommon> {
131        let deps_with_public = fds_extend_with_public(dependencies.clone());
132
133        let mut messages = Vec::new();
134        let mut enums = Vec::new();
135        let mut oneofs = Vec::new();
136        let mut top_level_messages = Vec::new();
137
138        // Top-level enums start with zero
139        for e in file.flat_map_slice(|f| &f.enum_type) {
140            enums.push(EnumIndices::new(e.name().to_owned(), None, e, file.owner()));
141        }
142
143        for message in file.flat_map_slice(|f| &f.message_type) {
144            let message_index = Self::index_message_and_inners(
145                file.owner(),
146                message,
147                None,
148                "",
149                &mut messages,
150                &mut enums,
151                &mut oneofs,
152            )?;
153            top_level_messages.push(message_index);
154        }
155
156        let message_by_name_to_package = Self::build_message_by_name_to_package(&messages);
157        let enums_by_name_to_package = Self::build_enum_by_name_to_package(&enums);
158
159        let mut services = Vec::new();
160
161        for service in &file.service {
162            let service_index = ServiceIndex::index(
163                service,
164                &FileDescriptorBuilding {
165                    current_file_descriptor: file.owner(),
166                    deps_with_public: &deps_with_public,
167                    message_by_name_to_package: &message_by_name_to_package,
168                    messages: &messages,
169                    enums_by_name_to_package: &enums_by_name_to_package,
170                },
171            )?;
172            services.push(service_index);
173        }
174
175        let mut fields = Vec::new();
176
177        Self::build_message_index(
178            file.owner(),
179            &deps_with_public,
180            &mut messages,
181            &mut fields,
182            &message_by_name_to_package,
183            &enums_by_name_to_package,
184        )?;
185
186        let first_extension_field_index = fields.len();
187        for ext in file.flat_map_slice(|f| &f.extension) {
188            fields.push(FieldIndex::index(
189                None,
190                ext,
191                &FileDescriptorBuilding {
192                    current_file_descriptor: file.owner(),
193                    deps_with_public: &deps_with_public,
194                    message_by_name_to_package: &message_by_name_to_package,
195                    messages: &messages,
196                    enums_by_name_to_package: &enums_by_name_to_package,
197                },
198            )?);
199        }
200
201        compute_is_initialized_is_always_true(&mut messages, &fields, file.owner());
202
203        Ok(FileDescriptorCommon {
204            dependencies,
205            messages,
206            message_by_name_to_package,
207            enums,
208            top_level_messages,
209            enums_by_name_to_package,
210            oneofs,
211            services,
212            first_extension_field_index,
213            fields,
214        })
215    }
216
217    fn is_map_entry(message: &DescriptorProto) -> crate::Result<bool> {
218        // Must be consistent with
219        // DescriptorBuilder::ValidateMapEntry
220
221        if !message.options.map_entry() {
222            return Ok(false);
223        }
224
225        if !message.name().ends_with("Entry") {
226            return Err(ReflectError::MapEntryNameMustEndWithEntry.into());
227        }
228        if !message.extension.is_empty()
229            || !message.extension_range.is_empty()
230            || !message.nested_type.is_empty()
231            || !message.enum_type.is_empty()
232        {
233            return Err(ReflectError::MapEntryMustHaveNo.into());
234        }
235
236        if message.field.len() != 2 {
237            return Err(ReflectError::MapEntryIncorrectFields.into());
238        }
239
240        let key = &message.field[0];
241        let value = &message.field[1];
242
243        if key.number() != 1
244            || key.name() != "key"
245            || key.label() != Label::LABEL_OPTIONAL
246            || value.number() != 2
247            || value.name() != "value"
248            || value.label() != Label::LABEL_OPTIONAL
249        {
250            return Err(ReflectError::MapEntryIncorrectFields.into());
251        }
252
253        Ok(true)
254    }
255
256    fn index_message_and_inners(
257        file: &FileDescriptorProto,
258        message: OwningRef<FileDescriptorProto, DescriptorProto>,
259        parent: Option<usize>,
260        parent_name_to_package: &str,
261        messages: &mut Vec<MessageIndices>,
262        enums: &mut Vec<EnumIndices>,
263        oneofs: &mut Vec<OneofIndices>,
264    ) -> crate::Result<usize> {
265        let name_to_package = concat_paths(parent_name_to_package, message.name());
266
267        let message_index = messages.len();
268        messages.push(MessageIndices {
269            proto: message.clone(),
270            full_name: concat_paths(file.package(), &name_to_package),
271            name_to_package: name_to_package.clone(),
272            enclosing_message: parent,
273            nested_messages: Vec::with_capacity(message.nested_type.len()),
274            nested_enums: enums.len()..enums.len() + message.enum_type.len(),
275            oneofs: oneofs.len()..oneofs.len() + message.oneof_decl.len(),
276            message_index: MessageFieldIndices::default(),
277            map_entry: Self::is_map_entry(&message)?,
278            // Initialized later.
279            is_initialized_is_always_true: false,
280        });
281
282        for e in message.flat_map_slice(|m| &m.enum_type) {
283            enums.push(EnumIndices::new(
284                concat_paths(&name_to_package, e.name()),
285                Some(message_index),
286                e,
287                file,
288            ));
289        }
290
291        for (i, _oneof) in message.oneof_decl.iter().enumerate() {
292            let fields: Vec<_> = message
293                .field
294                .iter()
295                .enumerate()
296                .filter(|(_, f)| f.has_oneof_index() && f.oneof_index() == i as i32)
297                .collect();
298            let synthetic = fields.len() == 1 && fields[0].1.proto3_optional();
299            oneofs.push(OneofIndices {
300                containing_message: message_index,
301                index_in_containing_message: i,
302                synthetic,
303                fields: fields.iter().map(|(i, _)| *i).collect(),
304            });
305        }
306
307        for nested in message.flat_map_slice(|m| &m.nested_type) {
308            let nested_index = Self::index_message_and_inners(
309                file,
310                nested,
311                Some(message_index),
312                &name_to_package,
313                messages,
314                enums,
315                oneofs,
316            )?;
317            messages[message_index].nested_messages.push(nested_index);
318        }
319
320        Ok(message_index)
321    }
322
323    fn build_message_by_name_to_package(messages: &[MessageIndices]) -> HashMap<String, usize> {
324        messages
325            .iter()
326            .enumerate()
327            .map(|(i, m)| (m.name_to_package.to_owned(), i))
328            .collect()
329    }
330
331    fn build_enum_by_name_to_package(enums: &[EnumIndices]) -> HashMap<String, usize> {
332        enums
333            .iter()
334            .enumerate()
335            .map(|(i, e)| (e.name_to_package.to_owned(), i))
336            .collect()
337    }
338
339    fn build_message_index(
340        file: &FileDescriptorProto,
341        deps_with_public: &[FileDescriptor],
342        messages: &mut [MessageIndices],
343        fields: &mut Vec<FieldIndex>,
344        message_by_name_to_package: &HashMap<String, usize>,
345        enums_by_name_to_package: &HashMap<String, usize>,
346    ) -> crate::Result<()> {
347        for i in 0..messages.len() {
348            let message_proto = &messages[i].proto;
349            let building = FileDescriptorBuilding {
350                current_file_descriptor: file,
351                deps_with_public,
352                message_by_name_to_package,
353                messages,
354                enums_by_name_to_package,
355            };
356            let message_index = Self::index_message(i, message_proto, &building, fields)?;
357            messages[i].message_index = message_index;
358        }
359        Ok(())
360    }
361
362    fn index_message(
363        message_index: usize,
364        proto: &OwningRef<FileDescriptorProto, DescriptorProto>,
365        building: &FileDescriptorBuilding,
366        fields: &mut Vec<FieldIndex>,
367    ) -> crate::Result<MessageFieldIndices> {
368        let mut index_by_name = HashMap::new();
369        let mut index_by_name_or_json_name = HashMap::new();
370        let mut index_by_number = HashMap::new();
371
372        let first_field_index = fields.len();
373
374        for field in proto.flat_map_slice(|m| &m.field) {
375            fields.push(FieldIndex::index(Some(message_index), field, building)?);
376        }
377
378        let field_count = proto.field.len();
379
380        for (i, f) in proto.field.iter().enumerate() {
381            let field_index = &fields[first_field_index + i];
382
383            if index_by_number.insert(f.number() as u32, i).is_some() {
384                return Err(ReflectError::NonUniqueFieldName(f.name().to_owned()).into());
385            }
386            if index_by_name.insert(f.name().to_owned(), i).is_some() {
387                return Err(ReflectError::NonUniqueFieldName(f.name().to_owned()).into());
388            }
389            if index_by_name_or_json_name
390                .insert(f.name().to_owned(), i)
391                .is_some()
392            {
393                return Err(ReflectError::NonUniqueFieldName(f.name().to_owned()).into());
394            }
395
396            if field_index.json_name != f.name() {
397                if index_by_name_or_json_name
398                    .insert(field_index.json_name.clone(), i)
399                    .is_some()
400                {
401                    return Err(ReflectError::NonUniqueFieldName(f.name().to_owned()).into());
402                }
403            }
404        }
405
406        for ext in proto.flat_map_slice(|m| &m.extension) {
407            fields.push(FieldIndex::index(Some(message_index), ext, building)?);
408        }
409
410        let extension_count = proto.extension.len();
411
412        Ok(MessageFieldIndices {
413            first_field_index,
414            field_count,
415            extension_count,
416            field_index_by_name: index_by_name,
417            field_index_by_name_or_json_name: index_by_name_or_json_name,
418            field_index_by_number: index_by_number,
419        })
420    }
421}