use std::collections::BTreeMap;
use std::fmt;
use super::{builtin, xsd};
pub const XSD_DATATYPE_LIBRARY: &str = "http://www.w3.org/2001/XMLSchema-datatypes";
#[derive(Clone, Debug, Default)]
pub struct DatatypeContext {
bindings: Vec<(String, String)>,
}
impl DatatypeContext {
pub(crate) fn empty() -> Self {
Self {
bindings: Vec::new(),
}
}
pub(crate) fn from_bindings(bindings: Vec<(String, String)>) -> Self {
Self { bindings }
}
pub fn resolve(&self, prefix: &str) -> Option<&str> {
self.bindings
.iter()
.rev()
.find(|(bound_prefix, _)| bound_prefix == prefix)
.map(|(_, uri)| uri.as_str())
}
}
pub trait DatatypeLibrary: Send + Sync {
fn validate_params(&self, type_name: &str, params: &[(&str, &str)]) -> Result<(), String>;
fn matches(
&self,
type_name: &str,
params: &[(&str, &str)],
value: &str,
context: &DatatypeContext,
) -> bool;
fn values_equal(
&self,
type_name: &str,
expected: &str,
expected_context: &DatatypeContext,
actual: &str,
actual_context: &DatatypeContext,
) -> bool;
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DatatypeError {
library: String,
message: String,
}
impl DatatypeError {
pub(crate) fn unsupported_library(library: impl Into<String>) -> Self {
let library = library.into();
Self {
message: format!("unsupported datatype library `{library}`"),
library,
}
}
pub(crate) fn type_problem(library: impl Into<String>, type_name: &str, reason: &str) -> Self {
let library = library.into();
Self {
message: format!("datatype `{type_name}` in library `{library}`: {reason}"),
library,
}
}
pub fn library(&self) -> &str {
&self.library
}
}
impl fmt::Display for DatatypeError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(&self.message)
}
}
impl std::error::Error for DatatypeError {}
pub struct DatatypeRegistry {
libraries: BTreeMap<String, Box<dyn DatatypeLibrary>>,
}
impl DatatypeRegistry {
pub fn new() -> Self {
let mut registry = Self::builtin_only();
registry.register(XSD_DATATYPE_LIBRARY, xsd::XsdLibrary);
registry
}
pub fn builtin_only() -> Self {
let mut libraries: BTreeMap<String, Box<dyn DatatypeLibrary>> = BTreeMap::new();
libraries.insert(String::new(), Box::new(builtin::BuiltinLibrary));
Self { libraries }
}
pub fn register(
&mut self,
library_uri: impl Into<String>,
library: impl DatatypeLibrary + 'static,
) -> &mut Self {
self.libraries.insert(library_uri.into(), Box::new(library));
self
}
pub(crate) fn get(&self, library_uri: &str) -> Option<&dyn DatatypeLibrary> {
self.libraries.get(library_uri).map(Box::as_ref)
}
}
impl Default for DatatypeRegistry {
fn default() -> Self {
Self::new()
}
}