use std::sync::Arc;
use buffa::Message as _;
use buffa_descriptor::generated::descriptor::FileDescriptorSet;
use crate::{
enumeration::EnumDescriptor, error::DescriptorError, file::FileDescriptor,
message::MessageDescriptor,
};
pub(crate) type MessageIndex = u32;
pub(crate) type EnumIndex = u32;
pub(crate) type FileIndex = u32;
#[derive(Clone, Default)]
pub struct DescriptorPool {
pub(crate) inner: Arc<PoolInner>,
}
impl std::fmt::Debug for DescriptorPool {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DescriptorPool")
.field("files", &self.inner.files.len())
.field("messages", &self.inner.messages.len())
.field("enums", &self.inner.enums.len())
.finish()
}
}
#[derive(Clone, Default)]
pub(crate) struct PoolInner {
pub(crate) names: hashbrown::HashMap<Box<str>, Definition>,
pub(crate) file_names: hashbrown::HashMap<Box<str>, FileIndex>,
pub(crate) files: Vec<FileEntry>,
pub(crate) messages: Vec<MessageEntry>,
pub(crate) enums: Vec<EnumEntry>,
pub(crate) services: Vec<crate::service::ServiceEntry>,
pub(crate) service_names: hashbrown::HashMap<Box<str>, crate::service::ServiceIndex>,
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum Definition {
Message(MessageIndex),
Enum(EnumIndex),
}
#[derive(Clone)]
pub(crate) struct FileEntry {
pub(crate) proto: buffa_descriptor::generated::descriptor::FileDescriptorProto,
pub(crate) messages: Vec<MessageIndex>,
pub(crate) enums: Vec<EnumIndex>,
pub(crate) service_indices: Vec<crate::service::ServiceIndex>,
}
#[derive(Clone)]
pub(crate) struct MessageEntry {
pub(crate) full_name: Box<str>,
pub(crate) name: Box<str>,
pub(crate) file: FileIndex,
pub(crate) parent: Option<MessageIndex>,
pub(crate) proto_path: Vec<u32>,
pub(crate) fields: Vec<FieldEntry>,
pub(crate) oneofs: Vec<OneofEntry>,
pub(crate) nested_messages: Vec<MessageIndex>,
pub(crate) nested_enums: Vec<EnumIndex>,
pub(crate) by_number: hashbrown::HashMap<u32, u32>,
pub(crate) by_name: hashbrown::HashMap<Box<str>, u32>,
pub(crate) by_json_name: hashbrown::HashMap<Box<str>, u32>,
pub(crate) is_map_entry: bool,
}
#[derive(Clone)]
pub(crate) struct FieldEntry {
pub(crate) name: Box<str>,
pub(crate) full_name: Box<str>,
pub(crate) json_name: Box<str>,
pub(crate) number: u32,
pub(crate) kind: KindRef,
pub(crate) cardinality: crate::field::Cardinality,
pub(crate) supports_presence: bool,
pub(crate) is_packed: bool,
pub(crate) oneof_index: Option<u32>,
pub(crate) proto_field_index: u32,
#[cfg(feature = "dynamic")]
pub(crate) parsed_default: Option<crate::dynamic::Value>,
}
#[derive(Clone, Copy, Debug)]
pub(crate) enum KindRef {
Double,
Float,
Int32,
Int64,
Uint32,
Uint64,
Sint32,
Sint64,
Fixed32,
Fixed64,
Sfixed32,
Sfixed64,
Bool,
String,
Bytes,
Message(MessageIndex),
Enum(EnumIndex),
}
#[derive(Clone)]
pub(crate) struct OneofEntry {
pub(crate) name: Box<str>,
pub(crate) full_name: Box<str>,
pub(crate) is_synthetic: bool,
pub(crate) field_indices: Vec<u32>,
pub(crate) proto_index: u32,
}
#[derive(Clone)]
pub(crate) struct EnumEntry {
pub(crate) full_name: Box<str>,
pub(crate) name: Box<str>,
pub(crate) file: FileIndex,
pub(crate) parent: Option<MessageIndex>,
pub(crate) values: Vec<EnumValueEntry>,
pub(crate) proto_path: Vec<u32>,
pub(crate) by_name: hashbrown::HashMap<Box<str>, u32>,
pub(crate) by_number: hashbrown::HashMap<i32, u32>,
}
#[derive(Clone)]
pub(crate) struct EnumValueEntry {
pub(crate) name: Box<str>,
pub(crate) full_name: Box<str>,
pub(crate) number: i32,
}
const _: fn() = || {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<DescriptorPool>();
assert_send_sync::<crate::message::MessageDescriptor>();
assert_send_sync::<crate::field::FieldDescriptor>();
assert_send_sync::<crate::enumeration::EnumDescriptor>();
assert_send_sync::<crate::oneof::OneofDescriptor>();
assert_send_sync::<crate::file::FileDescriptor>();
assert_send_sync::<crate::service::ServiceDescriptor>();
assert_send_sync::<crate::service::MethodDescriptor>();
};
impl DescriptorPool {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn decode(bytes: &[u8]) -> Result<Self, DescriptorError> {
let fds = FileDescriptorSet::decode_from_slice(bytes)?;
Self::from_file_descriptor_set(fds)
}
pub fn from_file_descriptor_set(fds: FileDescriptorSet) -> Result<Self, DescriptorError> {
let mut pool = Self::new();
pool.add_file_descriptor_set(fds)?;
Ok(pool)
}
pub fn add_file_descriptor_set(
&mut self,
fds: FileDescriptorSet,
) -> Result<(), DescriptorError> {
let inner = Arc::make_mut(&mut self.inner);
crate::pool_build::ingest_file_descriptor_set(inner, fds)
}
pub fn files(&self) -> impl ExactSizeIterator<Item = FileDescriptor> + '_ {
(0..self.inner.files.len() as u32).map(move |idx| FileDescriptor {
pool: self.clone(),
index: idx,
})
}
pub fn all_messages(&self) -> impl ExactSizeIterator<Item = MessageDescriptor> + '_ {
(0..self.inner.messages.len() as u32).map(move |idx| MessageDescriptor {
pool: self.clone(),
index: idx,
})
}
pub fn all_enums(&self) -> impl ExactSizeIterator<Item = EnumDescriptor> + '_ {
(0..self.inner.enums.len() as u32).map(move |idx| EnumDescriptor {
pool: self.clone(),
index: idx,
})
}
#[must_use]
pub fn get_message_by_name(&self, full_name: &str) -> Option<MessageDescriptor> {
let key = full_name.strip_prefix('.').unwrap_or(full_name);
match self.inner.names.get(key)? {
Definition::Message(idx) => Some(MessageDescriptor {
pool: self.clone(),
index: *idx,
}),
Definition::Enum(_) => None,
}
}
#[must_use]
pub fn get_enum_by_name(&self, full_name: &str) -> Option<EnumDescriptor> {
let key = full_name.strip_prefix('.').unwrap_or(full_name);
match self.inner.names.get(key)? {
Definition::Enum(idx) => Some(EnumDescriptor {
pool: self.clone(),
index: *idx,
}),
Definition::Message(_) => None,
}
}
#[must_use]
pub fn get_file_by_name(&self, name: &str) -> Option<FileDescriptor> {
self.inner.file_names.get(name).map(|idx| FileDescriptor {
pool: self.clone(),
index: *idx,
})
}
}