pub(crate) mod builtin;
#[cfg(feature = "wasm")]
pub(crate) mod wasm;
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
pub struct HandlerIdentity {
pub handler_id: String,
pub handler_version: String,
pub handler_api_version: u32,
pub effective_capabilities: Vec<String>,
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum HandlerLoadError {
#[error("handler pack error: {0}")]
Pack(#[from] crate::handler_package::HandlerPackError),
#[error("handler does not cover all model capabilities: missing {missing:?}")]
CapabilityMissing { missing: Vec<String> },
#[error("handler failed to initialize: {0}")]
Init(String),
#[error("guest metadata does not match signed manifest: {0}")]
MetadataMismatch(String),
}
pub fn effective_capabilities(
model: &[String],
handler: &[String],
) -> Result<Vec<String>, HandlerLoadError> {
let mut model_sorted = model.to_vec();
model_sorted.sort();
let mut handler_sorted = handler.to_vec();
handler_sorted.sort();
let effective: Vec<String> = model_sorted
.iter()
.filter(|capability| handler_sorted.binary_search(capability).is_ok())
.cloned()
.collect();
if effective.len() != model.len() {
let missing: Vec<String> = model_sorted
.iter()
.filter(|capability| handler_sorted.binary_search(capability).is_err())
.cloned()
.collect();
return Err(HandlerLoadError::CapabilityMissing { missing });
}
Ok(effective)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn effective_capabilities_intersect() {
let model = vec!["a".into(), "b".into()];
let handler = vec!["a".into(), "b".into(), "c".into()];
let result = effective_capabilities(&model, &handler).unwrap();
assert_eq!(result, vec!["a", "b"]);
}
#[test]
fn effective_capabilities_reject_missing() {
let model = vec!["a".into(), "b".into()];
let handler = vec!["a".into()];
let error = effective_capabilities(&model, &handler).unwrap_err();
assert!(
matches!(error, HandlerLoadError::CapabilityMissing { missing } if missing == vec!["b"])
);
}
}