prost_reflect/descriptor/
mod.rs

1mod api;
2mod build;
3mod error;
4mod global;
5mod tag;
6#[cfg(test)]
7mod tests;
8pub(crate) mod types;
9
10pub use self::error::DescriptorError;
11use self::types::{DescriptorProto, EnumDescriptorProto};
12
13use std::{
14    collections::{BTreeMap, HashMap, HashSet},
15    convert::TryInto,
16    fmt,
17    ops::Range,
18    sync::Arc,
19};
20
21use crate::{descriptor::types::FileDescriptorProto, Value};
22
23pub(crate) const MAP_ENTRY_KEY_NUMBER: u32 = 1;
24pub(crate) const MAP_ENTRY_VALUE_NUMBER: u32 = 2;
25
26pub(crate) const RESERVED_MESSAGE_FIELD_NUMBERS: Range<i32> = 19_000..20_000;
27pub(crate) const VALID_MESSAGE_FIELD_NUMBERS: Range<i32> = 1..536_870_912;
28
29/// Cardinality determines whether a field is optional, required, or repeated.
30#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
31pub enum Cardinality {
32    /// The field appears zero or one times.
33    Optional,
34    /// The field appears exactly one time. This cardinality is invalid with Proto3.
35    Required,
36    /// The field appears zero or more times.
37    Repeated,
38}
39
40/// The syntax of a proto file.
41#[derive(Copy, Clone, PartialEq, Eq, Hash)]
42pub enum Syntax {
43    /// The `proto2` syntax.
44    Proto2,
45    /// The `proto3` syntax.
46    Proto3,
47}
48
49/// The type of a protobuf message field.
50#[derive(Clone, PartialEq, Eq)]
51pub enum Kind {
52    /// The protobuf `double` type.
53    Double,
54    /// The protobuf `float` type.
55    Float,
56    /// The protobuf `int32` type.
57    Int32,
58    /// The protobuf `int64` type.
59    Int64,
60    /// The protobuf `uint32` type.
61    Uint32,
62    /// The protobuf `uint64` type.
63    Uint64,
64    /// The protobuf `sint32` type.
65    Sint32,
66    /// The protobuf `sint64` type.
67    Sint64,
68    /// The protobuf `fixed32` type.
69    Fixed32,
70    /// The protobuf `fixed64` type.
71    Fixed64,
72    /// The protobuf `sfixed32` type.
73    Sfixed32,
74    /// The protobuf `sfixed64` type.
75    Sfixed64,
76    /// The protobuf `bool` type.
77    Bool,
78    /// The protobuf `string` type.
79    String,
80    /// The protobuf `bytes` type.
81    Bytes,
82    /// A protobuf message type.
83    Message(MessageDescriptor),
84    /// A protobuf enum type.
85    Enum(EnumDescriptor),
86}
87
88#[derive(Copy, Clone)]
89enum KindIndex {
90    Double,
91    Float,
92    Int32,
93    Int64,
94    Uint32,
95    Uint64,
96    Sint32,
97    Sint64,
98    Fixed32,
99    Fixed64,
100    Sfixed32,
101    Sfixed64,
102    Bool,
103    String,
104    Bytes,
105    Message(MessageIndex),
106    Enum(EnumIndex),
107    Group(MessageIndex),
108}
109
110type DescriptorIndex = u32;
111type FileIndex = DescriptorIndex;
112type ServiceIndex = DescriptorIndex;
113type MethodIndex = DescriptorIndex;
114type MessageIndex = DescriptorIndex;
115type FieldIndex = DescriptorIndex;
116type OneofIndex = DescriptorIndex;
117type ExtensionIndex = DescriptorIndex;
118type EnumIndex = DescriptorIndex;
119type EnumValueIndex = DescriptorIndex;
120
121/// A `DescriptorPool` is a collection of related descriptors. Typically it will be created from
122/// a [`FileDescriptorSet`][prost_types::FileDescriptorSet] output by the protobuf compiler
123/// (see [`DescriptorPool::from_file_descriptor_set`]) but it may also be built up by adding files individually.
124///
125/// Methods like [`MessageDescriptor::extensions`] will be scoped to just the files contained within the parent
126/// `DescriptorPool`.
127///
128/// This type uses reference counting internally so it is cheap to clone. Modifying an instance of a
129/// pool will not update any existing clones of the instance.
130#[derive(Clone, Default)]
131pub struct DescriptorPool {
132    inner: Arc<DescriptorPoolInner>,
133}
134
135#[derive(Clone, Default)]
136struct DescriptorPoolInner {
137    names: HashMap<Box<str>, Definition>,
138    file_names: HashMap<Box<str>, FileIndex>,
139    files: Vec<FileDescriptorInner>,
140    messages: Vec<MessageDescriptorInner>,
141    enums: Vec<EnumDescriptorInner>,
142    extensions: Vec<ExtensionDescriptorInner>,
143    services: Vec<ServiceDescriptorInner>,
144}
145
146#[derive(Clone)]
147struct Identity {
148    file: FileIndex,
149    path: Box<[i32]>,
150    full_name: Box<str>,
151    name_index: usize,
152}
153
154#[derive(Clone, Debug)]
155struct Definition {
156    file: FileIndex,
157    path: Box<[i32]>,
158    kind: DefinitionKind,
159}
160
161#[derive(Copy, Clone, Debug)]
162enum DefinitionKind {
163    Package,
164    Message(MessageIndex),
165    Field(MessageIndex),
166    Oneof(MessageIndex),
167    Service(ServiceIndex),
168    Method(ServiceIndex),
169    Enum(EnumIndex),
170    EnumValue(EnumIndex),
171    Extension(ExtensionIndex),
172}
173
174/// A single source file containing protobuf messages and services.
175#[derive(Clone, PartialEq, Eq)]
176pub struct FileDescriptor {
177    pool: DescriptorPool,
178    index: FileIndex,
179}
180
181#[derive(Clone)]
182struct FileDescriptorInner {
183    syntax: Syntax,
184    raw: FileDescriptorProto,
185    prost: prost_types::FileDescriptorProto,
186    dependencies: Vec<FileIndex>,
187    transitive_dependencies: HashSet<FileIndex>,
188}
189
190/// A protobuf message definition.
191#[derive(Clone, PartialEq, Eq)]
192pub struct MessageDescriptor {
193    pool: DescriptorPool,
194    index: MessageIndex,
195}
196
197#[derive(Clone)]
198struct MessageDescriptorInner {
199    id: Identity,
200    parent: Option<MessageIndex>,
201    extensions: Vec<ExtensionIndex>,
202    fields: Vec<FieldDescriptorInner>,
203    field_numbers: BTreeMap<u32, FieldIndex>,
204    field_names: HashMap<Box<str>, FieldIndex>,
205    field_json_names: HashMap<Box<str>, FieldIndex>,
206    oneofs: Vec<OneofDescriptorInner>,
207}
208
209/// A oneof field in a protobuf message.
210#[derive(Clone, PartialEq, Eq)]
211pub struct OneofDescriptor {
212    message: MessageDescriptor,
213    index: OneofIndex,
214}
215
216#[derive(Clone)]
217struct OneofDescriptorInner {
218    id: Identity,
219    fields: Vec<FieldIndex>,
220}
221
222/// A protobuf message definition.
223#[derive(Clone, PartialEq, Eq)]
224pub struct FieldDescriptor {
225    message: MessageDescriptor,
226    index: FieldIndex,
227}
228
229#[derive(Clone)]
230struct FieldDescriptorInner {
231    id: Identity,
232    number: u32,
233    json_name: Box<str>,
234    kind: KindIndex,
235    oneof: Option<OneofIndex>,
236    is_packed: bool,
237    supports_presence: bool,
238    cardinality: Cardinality,
239    default: Option<Value>,
240}
241
242/// A protobuf extension field definition.
243#[derive(Clone, PartialEq, Eq)]
244pub struct ExtensionDescriptor {
245    pool: DescriptorPool,
246    index: ExtensionIndex,
247}
248
249#[derive(Clone)]
250pub struct ExtensionDescriptorInner {
251    id: Identity,
252    parent: Option<MessageIndex>,
253    number: u32,
254    json_name: Box<str>,
255    extendee: MessageIndex,
256    kind: KindIndex,
257    is_packed: bool,
258    cardinality: Cardinality,
259    default: Option<Value>,
260}
261
262/// A protobuf enum type.
263#[derive(Clone, PartialEq, Eq)]
264pub struct EnumDescriptor {
265    pool: DescriptorPool,
266    index: EnumIndex,
267}
268
269#[derive(Clone)]
270struct EnumDescriptorInner {
271    id: Identity,
272    parent: Option<MessageIndex>,
273    values: Vec<EnumValueDescriptorInner>,
274    value_numbers: Vec<(i32, EnumValueIndex)>,
275    value_names: HashMap<Box<str>, EnumValueIndex>,
276    allow_alias: bool,
277}
278
279/// A value in a protobuf enum type.
280#[derive(Clone, PartialEq, Eq)]
281pub struct EnumValueDescriptor {
282    parent: EnumDescriptor,
283    index: EnumValueIndex,
284}
285
286#[derive(Clone)]
287struct EnumValueDescriptorInner {
288    id: Identity,
289    number: i32,
290}
291
292/// A protobuf service definition.
293#[derive(Clone, PartialEq, Eq)]
294pub struct ServiceDescriptor {
295    pool: DescriptorPool,
296    index: ServiceIndex,
297}
298
299#[derive(Clone)]
300struct ServiceDescriptorInner {
301    id: Identity,
302    methods: Vec<MethodDescriptorInner>,
303}
304
305/// A method definition for a [`ServiceDescriptor`].
306#[derive(Clone, PartialEq, Eq)]
307pub struct MethodDescriptor {
308    service: ServiceDescriptor,
309    index: MethodIndex,
310}
311
312#[derive(Clone)]
313struct MethodDescriptorInner {
314    id: Identity,
315    input: MessageIndex,
316    output: MessageIndex,
317}
318
319impl Identity {
320    fn new(file: FileIndex, path: &[i32], full_name: &str, name: &str) -> Identity {
321        debug_assert!(full_name.ends_with(name));
322        let name_index = full_name.len() - name.len();
323        debug_assert!(name_index == 0 || full_name.as_bytes()[name_index - 1] == b'.');
324        Identity {
325            file,
326            path: path.into(),
327            full_name: full_name.into(),
328            name_index,
329        }
330    }
331
332    fn full_name(&self) -> &str {
333        &self.full_name
334    }
335
336    fn name(&self) -> &str {
337        &self.full_name[self.name_index..]
338    }
339}
340
341impl KindIndex {
342    fn is_packable(&self) -> bool {
343        match self {
344            KindIndex::Double
345            | KindIndex::Float
346            | KindIndex::Int32
347            | KindIndex::Int64
348            | KindIndex::Uint32
349            | KindIndex::Uint64
350            | KindIndex::Sint32
351            | KindIndex::Sint64
352            | KindIndex::Fixed32
353            | KindIndex::Fixed64
354            | KindIndex::Sfixed32
355            | KindIndex::Sfixed64
356            | KindIndex::Bool
357            | KindIndex::Enum(_) => true,
358            KindIndex::String | KindIndex::Bytes | KindIndex::Message(_) | KindIndex::Group(_) => {
359                false
360            }
361        }
362    }
363
364    fn is_message(&self) -> bool {
365        matches!(self, KindIndex::Message(_) | KindIndex::Group(_))
366    }
367}
368
369impl fmt::Debug for KindIndex {
370    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
371        match self {
372            KindIndex::Double => write!(f, "double"),
373            KindIndex::Float => write!(f, "float"),
374            KindIndex::Int32 => write!(f, "int32"),
375            KindIndex::Int64 => write!(f, "int64"),
376            KindIndex::Uint32 => write!(f, "uint32"),
377            KindIndex::Uint64 => write!(f, "uint64"),
378            KindIndex::Sint32 => write!(f, "sint32"),
379            KindIndex::Sint64 => write!(f, "sint64"),
380            KindIndex::Fixed32 => write!(f, "fixed32"),
381            KindIndex::Fixed64 => write!(f, "fixed64"),
382            KindIndex::Sfixed32 => write!(f, "sfixed32"),
383            KindIndex::Sfixed64 => write!(f, "sfixed64"),
384            KindIndex::Bool => write!(f, "bool"),
385            KindIndex::String => write!(f, "string"),
386            KindIndex::Bytes => write!(f, "bytes"),
387            KindIndex::Message(_) | KindIndex::Group(_) => write!(f, "message"),
388            KindIndex::Enum(_) => write!(f, "enum"),
389        }
390    }
391}
392
393impl DefinitionKind {
394    fn is_parent(&self) -> bool {
395        match self {
396            DefinitionKind::Package => true,
397            DefinitionKind::Message(_) => true,
398            DefinitionKind::Field(_) => false,
399            DefinitionKind::Oneof(_) => false,
400            DefinitionKind::Service(_) => true,
401            DefinitionKind::Method(_) => false,
402            DefinitionKind::Enum(_) => true,
403            DefinitionKind::EnumValue(_) => false,
404            DefinitionKind::Extension(_) => false,
405        }
406    }
407}
408
409impl DescriptorPoolInner {
410    fn get_by_name(&self, name: &str) -> Option<&Definition> {
411        let name = name.strip_prefix('.').unwrap_or(name);
412        self.names.get(name)
413    }
414}
415
416fn to_index(i: usize) -> DescriptorIndex {
417    i.try_into().expect("index too large")
418}
419
420fn find_message_proto<'a>(file: &'a FileDescriptorProto, path: &[i32]) -> &'a DescriptorProto {
421    debug_assert_ne!(path.len(), 0);
422    debug_assert_eq!(path.len() % 2, 0);
423
424    let mut message: Option<&'a types::DescriptorProto> = None;
425    for part in path.chunks(2) {
426        match part[0] {
427            tag::file::MESSAGE_TYPE => message = Some(&file.message_type[part[1] as usize]),
428            tag::message::NESTED_TYPE => {
429                message = Some(&message.unwrap().nested_type[part[1] as usize])
430            }
431            _ => panic!("invalid message path"),
432        }
433    }
434
435    message.unwrap()
436}
437
438fn find_enum_proto<'a>(file: &'a FileDescriptorProto, path: &[i32]) -> &'a EnumDescriptorProto {
439    debug_assert_ne!(path.len(), 0);
440    debug_assert_eq!(path.len() % 2, 0);
441    if path.len() == 2 {
442        debug_assert_eq!(path[0], tag::file::ENUM_TYPE);
443        &file.enum_type[path[1] as usize]
444    } else {
445        let message = find_message_proto(file, &path[..path.len() - 2]);
446        debug_assert_eq!(path[path.len() - 2], tag::message::ENUM_TYPE);
447        &message.enum_type[path[path.len() - 1] as usize]
448    }
449}
450
451#[test]
452fn assert_descriptor_send_sync() {
453    fn test_send_sync<T: Send + Sync>() {}
454
455    test_send_sync::<DescriptorPool>();
456    test_send_sync::<Kind>();
457    test_send_sync::<DescriptorError>();
458}