use std::sync::Arc;
use crate::error::Result;
use crate::model::{Extension, Model};
pub trait ExtensionHandler: Send + Sync {
fn extension_type(&self) -> Extension;
fn namespace(&self) -> &'static str {
self.extension_type().namespace()
}
fn name(&self) -> &'static str {
self.extension_type().name()
}
fn validate(&self, model: &Model) -> Result<()>;
fn is_used_in_model(&self, _model: &Model) -> bool {
true
}
fn pre_write(&self, _model: &mut Model) -> Result<()> {
Ok(())
}
fn post_parse(&self, _model: &mut Model) -> Result<()> {
Ok(())
}
}
#[derive(Clone)]
pub struct ExtensionRegistry {
handlers: Vec<Arc<dyn ExtensionHandler>>,
}
impl ExtensionRegistry {
pub fn new() -> Self {
Self {
handlers: Vec::new(),
}
}
pub fn register(&mut self, handler: Arc<dyn ExtensionHandler>) {
self.handlers.push(handler);
}
pub fn get_handler(&self, extension: Extension) -> Option<&dyn ExtensionHandler> {
self.handlers
.iter()
.find(|h| h.extension_type() == extension)
.map(|h| h.as_ref())
}
pub fn validate_all(&self, model: &Model) -> Result<()> {
for handler in &self.handlers {
handler.validate(model)?;
}
Ok(())
}
pub fn post_parse_all(&self, model: &mut Model) -> Result<()> {
for handler in &self.handlers {
if handler.is_used_in_model(model) {
handler.post_parse(model)?;
}
}
Ok(())
}
pub fn pre_write_all(&self, model: &mut Model) -> Result<()> {
for handler in &self.handlers {
if handler.is_used_in_model(model) {
handler.pre_write(model)?;
}
}
Ok(())
}
pub fn handlers(&self) -> &[Arc<dyn ExtensionHandler>] {
&self.handlers
}
}
impl Default for ExtensionRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
struct TestExtensionHandler {
ext_type: Extension,
should_fail: bool,
}
impl ExtensionHandler for TestExtensionHandler {
fn extension_type(&self) -> Extension {
self.ext_type
}
fn validate(&self, _model: &Model) -> Result<()> {
if self.should_fail {
Err(crate::Error::InvalidModel(format!(
"{} validation failed",
self.name()
)))
} else {
Ok(())
}
}
}
#[test]
fn test_extension_registry_basic() {
let mut registry = ExtensionRegistry::new();
assert!(registry.handlers().is_empty());
let handler = Arc::new(TestExtensionHandler {
ext_type: Extension::Material,
should_fail: false,
});
registry.register(handler);
assert_eq!(registry.handlers().len(), 1);
assert!(registry.get_handler(Extension::Material).is_some());
assert!(registry.get_handler(Extension::Production).is_none());
}
#[test]
fn test_extension_handler_properties() {
let handler = TestExtensionHandler {
ext_type: Extension::Material,
should_fail: false,
};
assert_eq!(handler.extension_type(), Extension::Material);
assert_eq!(handler.name(), "Material");
assert_eq!(
handler.namespace(),
"http://schemas.microsoft.com/3dmanufacturing/material/2015/02"
);
}
#[test]
fn test_validate_all_success() {
let mut registry = ExtensionRegistry::new();
registry.register(Arc::new(TestExtensionHandler {
ext_type: Extension::Material,
should_fail: false,
}));
registry.register(Arc::new(TestExtensionHandler {
ext_type: Extension::Production,
should_fail: false,
}));
let model = Model::new();
assert!(registry.validate_all(&model).is_ok());
}
#[test]
fn test_validate_all_failure() {
let mut registry = ExtensionRegistry::new();
registry.register(Arc::new(TestExtensionHandler {
ext_type: Extension::Material,
should_fail: false,
}));
registry.register(Arc::new(TestExtensionHandler {
ext_type: Extension::Production,
should_fail: true,
}));
let model = Model::new();
assert!(registry.validate_all(&model).is_err());
}
}