use prost_reflect::{DescriptorPool, DynamicMessage};
use crate::{
Error, RuntimeError, ValidationError, Validator, ValidatorOption, Violation,
normalize_edition_descriptor_set,
};
pub struct RuntimeBridge {
pool: DescriptorPool,
validator: Validator,
}
impl RuntimeBridge {
#[must_use]
pub fn from_fds(fds: &[u8]) -> Self {
let normalized = normalize_edition_descriptor_set(fds);
let pool = DescriptorPool::decode(normalized.as_slice())
.expect("prost-protovalidate bridge: embedded descriptor set must decode");
let validator =
Validator::with_options(&[ValidatorOption::AdditionalDescriptorSetBytes(normalized)]);
Self { pool, validator }
}
pub fn validate_wire(&self, full_name: &str, wire_bytes: &[u8]) -> Result<(), Error> {
let descriptor = self.pool.get_message_by_name(full_name).ok_or_else(|| {
Error::Runtime(RuntimeError {
cause: format!("bridge: message type `{full_name}` not found in descriptor pool"),
})
})?;
let dynamic = DynamicMessage::decode(descriptor, wire_bytes).map_err(|e| {
Error::Runtime(RuntimeError {
cause: format!("bridge: failed to decode `{full_name}`: {e}"),
})
})?;
self.validator.validate(&dynamic)
}
}
#[must_use]
pub fn error_to_validation_error(error: Error) -> ValidationError {
match error {
Error::Validation(err) => err,
Error::Compilation(err) => ValidationError::single(Violation::new("", "", err.cause)),
Error::Runtime(err) => ValidationError::single(Violation::new("", "", err.cause)),
}
}