1use std::sync::Arc;
4
5use buffa::Message as _;
6use buffa_descriptor::generated::descriptor::FileDescriptorSet;
7
8use crate::{
9 enumeration::EnumDescriptor, error::DescriptorError, file::FileDescriptor,
10 message::MessageDescriptor,
11};
12
13pub(crate) type MessageIndex = u32;
15pub(crate) type EnumIndex = u32;
17pub(crate) type FileIndex = u32;
19
20#[derive(Clone, Default)]
28pub struct DescriptorPool {
29 pub(crate) inner: Arc<PoolInner>,
30}
31
32impl std::fmt::Debug for DescriptorPool {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 f.debug_struct("DescriptorPool")
35 .field("files", &self.inner.files.len())
36 .field("messages", &self.inner.messages.len())
37 .field("enums", &self.inner.enums.len())
38 .finish()
39 }
40}
41
42#[derive(Clone, Default)]
43pub(crate) struct PoolInner {
44 pub(crate) names: hashbrown::HashMap<Box<str>, Definition>,
45 pub(crate) file_names: hashbrown::HashMap<Box<str>, FileIndex>,
46 pub(crate) files: Vec<FileEntry>,
47 pub(crate) messages: Vec<MessageEntry>,
48 pub(crate) enums: Vec<EnumEntry>,
49 pub(crate) services: Vec<crate::service::ServiceEntry>,
50 pub(crate) service_names: hashbrown::HashMap<Box<str>, crate::service::ServiceIndex>,
51}
52
53#[derive(Debug, Clone, Copy)]
55pub(crate) enum Definition {
56 Message(MessageIndex),
57 Enum(EnumIndex),
58}
59
60#[derive(Clone)]
61pub(crate) struct FileEntry {
62 pub(crate) proto: buffa_descriptor::generated::descriptor::FileDescriptorProto,
63 pub(crate) messages: Vec<MessageIndex>,
66 pub(crate) enums: Vec<EnumIndex>,
68 pub(crate) service_indices: Vec<crate::service::ServiceIndex>,
70}
71
72#[derive(Clone)]
73pub(crate) struct MessageEntry {
74 pub(crate) full_name: Box<str>,
76 pub(crate) name: Box<str>,
78 pub(crate) file: FileIndex,
80 pub(crate) parent: Option<MessageIndex>,
82 pub(crate) proto_path: Vec<u32>,
86 pub(crate) fields: Vec<FieldEntry>,
88 pub(crate) oneofs: Vec<OneofEntry>,
92 pub(crate) nested_messages: Vec<MessageIndex>,
94 pub(crate) nested_enums: Vec<EnumIndex>,
96 pub(crate) by_number: hashbrown::HashMap<u32, u32>,
98 pub(crate) by_name: hashbrown::HashMap<Box<str>, u32>,
100 pub(crate) by_json_name: hashbrown::HashMap<Box<str>, u32>,
102 pub(crate) is_map_entry: bool,
105}
106
107#[derive(Clone)]
108pub(crate) struct FieldEntry {
109 pub(crate) name: Box<str>,
110 pub(crate) full_name: Box<str>,
111 pub(crate) json_name: Box<str>,
112 pub(crate) number: u32,
113 pub(crate) kind: KindRef,
114 pub(crate) cardinality: crate::field::Cardinality,
115 pub(crate) supports_presence: bool,
116 pub(crate) is_packed: bool,
117 pub(crate) oneof_index: Option<u32>,
120 pub(crate) proto_field_index: u32,
123 #[cfg(feature = "dynamic")]
128 pub(crate) parsed_default: Option<crate::dynamic::Value>,
129}
130
131#[derive(Clone, Copy, Debug)]
135pub(crate) enum KindRef {
136 Double,
137 Float,
138 Int32,
139 Int64,
140 Uint32,
141 Uint64,
142 Sint32,
143 Sint64,
144 Fixed32,
145 Fixed64,
146 Sfixed32,
147 Sfixed64,
148 Bool,
149 String,
150 Bytes,
151 Message(MessageIndex),
152 Enum(EnumIndex),
153}
154
155#[derive(Clone)]
156pub(crate) struct OneofEntry {
157 pub(crate) name: Box<str>,
158 pub(crate) full_name: Box<str>,
159 pub(crate) is_synthetic: bool,
160 pub(crate) field_indices: Vec<u32>,
162 pub(crate) proto_index: u32,
164}
165
166#[derive(Clone)]
167pub(crate) struct EnumEntry {
168 pub(crate) full_name: Box<str>,
169 pub(crate) name: Box<str>,
170 pub(crate) file: FileIndex,
171 pub(crate) parent: Option<MessageIndex>,
172 pub(crate) values: Vec<EnumValueEntry>,
173 pub(crate) proto_path: Vec<u32>,
176 pub(crate) by_name: hashbrown::HashMap<Box<str>, u32>,
178 pub(crate) by_number: hashbrown::HashMap<i32, u32>,
182}
183
184#[derive(Clone)]
185pub(crate) struct EnumValueEntry {
186 pub(crate) name: Box<str>,
187 pub(crate) full_name: Box<str>,
188 pub(crate) number: i32,
189}
190
191const _: fn() = || {
196 fn assert_send_sync<T: Send + Sync>() {}
197 assert_send_sync::<DescriptorPool>();
198 assert_send_sync::<crate::message::MessageDescriptor>();
199 assert_send_sync::<crate::field::FieldDescriptor>();
200 assert_send_sync::<crate::enumeration::EnumDescriptor>();
201 assert_send_sync::<crate::oneof::OneofDescriptor>();
202 assert_send_sync::<crate::file::FileDescriptor>();
203 assert_send_sync::<crate::service::ServiceDescriptor>();
204 assert_send_sync::<crate::service::MethodDescriptor>();
205};
206
207impl DescriptorPool {
208 #[must_use]
210 pub fn new() -> Self {
211 Self::default()
212 }
213
214 pub fn decode(bytes: &[u8]) -> Result<Self, DescriptorError> {
221 let fds = FileDescriptorSet::decode_from_slice(bytes)?;
222 Self::from_file_descriptor_set(fds)
223 }
224
225 pub fn from_file_descriptor_set(fds: FileDescriptorSet) -> Result<Self, DescriptorError> {
230 let mut pool = Self::new();
231 pool.add_file_descriptor_set(fds)?;
232 Ok(pool)
233 }
234
235 pub fn add_file_descriptor_set(
240 &mut self,
241 fds: FileDescriptorSet,
242 ) -> Result<(), DescriptorError> {
243 let inner = Arc::make_mut(&mut self.inner);
244 crate::pool_build::ingest_file_descriptor_set(inner, fds)
245 }
246
247 pub fn files(&self) -> impl ExactSizeIterator<Item = FileDescriptor> + '_ {
249 (0..self.inner.files.len() as u32).map(move |idx| FileDescriptor {
250 pool: self.clone(),
251 index: idx,
252 })
253 }
254
255 pub fn all_messages(&self) -> impl ExactSizeIterator<Item = MessageDescriptor> + '_ {
258 (0..self.inner.messages.len() as u32).map(move |idx| MessageDescriptor {
259 pool: self.clone(),
260 index: idx,
261 })
262 }
263
264 pub fn all_enums(&self) -> impl ExactSizeIterator<Item = EnumDescriptor> + '_ {
266 (0..self.inner.enums.len() as u32).map(move |idx| EnumDescriptor {
267 pool: self.clone(),
268 index: idx,
269 })
270 }
271
272 #[must_use]
275 pub fn get_message_by_name(&self, full_name: &str) -> Option<MessageDescriptor> {
276 let key = full_name.strip_prefix('.').unwrap_or(full_name);
277 match self.inner.names.get(key)? {
278 Definition::Message(idx) => Some(MessageDescriptor {
279 pool: self.clone(),
280 index: *idx,
281 }),
282 Definition::Enum(_) => None,
283 }
284 }
285
286 #[must_use]
288 pub fn get_enum_by_name(&self, full_name: &str) -> Option<EnumDescriptor> {
289 let key = full_name.strip_prefix('.').unwrap_or(full_name);
290 match self.inner.names.get(key)? {
291 Definition::Enum(idx) => Some(EnumDescriptor {
292 pool: self.clone(),
293 index: *idx,
294 }),
295 Definition::Message(_) => None,
296 }
297 }
298
299 #[must_use]
301 pub fn get_file_by_name(&self, name: &str) -> Option<FileDescriptor> {
302 self.inner.file_names.get(name).map(|idx| FileDescriptor {
303 pool: self.clone(),
304 index: *idx,
305 })
306 }
307}