use std::sync::Arc;
use prost_reflect::{DescriptorPool, MethodDescriptor};
#[derive(Clone, Debug, Default)]
pub struct RpcSelection {
names: Arc<[Name]>,
}
#[derive(Debug)]
struct Name {
service: String,
method: Option<String>,
}
impl RpcSelection {
pub fn new(
pool: &DescriptorPool,
names: impl IntoIterator<Item = impl AsRef<str>>,
) -> Result<Self, String> {
let names = names
.into_iter()
.map(|name| {
let name = name.as_ref();
let (service, method) = match name.split_once('/') {
Some((service, method)) => (service, Some(method)),
None => (name, None),
};
let known = pool.get_service_by_name(service).is_some_and(|found| {
method.is_none_or(|method| found.methods().any(|m| m.name() == method))
});
if !known {
return Err(format!(
"{name:?} is not a service or method of the proto descriptors"
));
}
Ok(Name {
service: service.to_owned(),
method: method.map(str::to_owned),
})
})
.collect::<Result<Vec<_>, _>>()?;
Ok(Self {
names: names.into(),
})
}
pub(crate) fn is_all(&self) -> bool {
self.names.is_empty()
}
pub(crate) fn selects(&self, method: &MethodDescriptor) -> bool {
self.is_all() || {
let service = method.parent_service();
self.names.iter().any(|name| {
name.service == service.full_name()
&& name.method.as_deref().is_none_or(|m| m == method.name())
})
}
}
}