use std::collections::HashMap;
use sup_xml_core::error::XmlError;
use sup_xml_core::xpath::XPathValue;
pub trait ExtensionFunctions {
fn call(
&self,
ns_uri: &str,
name: &str,
args: Vec<XPathValue>,
) -> Option<Result<XPathValue, XmlError>>;
}
type ExtensionFn = Box<dyn Fn(Vec<XPathValue>) -> Result<XPathValue, XmlError>>;
#[derive(Default)]
pub struct Extensions {
fns: HashMap<String, HashMap<String, ExtensionFn>>,
}
impl Extensions {
pub fn new() -> Self { Self::default() }
pub fn register<F>(
&mut self,
ns_uri: impl Into<String>,
name: impl Into<String>,
f: F,
) -> &mut Self
where
F: Fn(Vec<XPathValue>) -> Result<XPathValue, XmlError> + 'static,
{
self.fns.entry(ns_uri.into())
.or_default()
.insert(name.into(), Box::new(f));
self
}
}
impl ExtensionFunctions for Extensions {
fn call(
&self,
ns_uri: &str,
name: &str,
args: Vec<XPathValue>,
) -> Option<Result<XPathValue, XmlError>> {
let f = self.fns.get(ns_uri)?.get(name)?;
Some(f(args))
}
}
impl std::fmt::Debug for Extensions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut names: Vec<String> = Vec::new();
for (ns, m) in &self.fns {
for k in m.keys() {
names.push(format!("{{{ns}}}{k}"));
}
}
names.sort();
f.debug_struct("Extensions").field("registered", &names).finish()
}
}