use crate::block::Block;
use crate::document::Document;
use crate::error::Result;
use std::fmt;
pub trait BlockProcessor: Send + Sync {
fn name(&self) -> &str;
fn description(&self) -> &str;
fn process_block(&self, block: &mut Block) -> Result<bool>;
fn process_document(&self, _document: &mut Document) -> Result<()> {
Ok(())
}
}
pub trait BlockValidator: Send + Sync {
fn name(&self) -> &str;
fn validate_block(&self, block: &Block) -> Result<()>;
}
pub trait ContentTransformer: Send + Sync {
fn name(&self) -> &str;
fn transform(&self, content: &str) -> Result<String>;
}
pub trait PluginLifecycle {
fn on_init(&mut self) -> Result<()> {
Ok(())
}
fn on_unload(&mut self) -> Result<()> {
Ok(())
}
}
pub struct PluginRegistry {
processors: Vec<Box<dyn BlockProcessor>>,
validators: Vec<Box<dyn BlockValidator>>,
transformers: Vec<Box<dyn ContentTransformer>>,
}
impl PluginRegistry {
pub fn new() -> Self {
Self {
processors: Vec::new(),
validators: Vec::new(),
transformers: Vec::new(),
}
}
pub fn register_processor(&mut self, processor: Box<dyn BlockProcessor>) {
self.processors.push(processor);
}
pub fn register_validator(&mut self, validator: Box<dyn BlockValidator>) {
self.validators.push(validator);
}
pub fn register_transformer(&mut self, transformer: Box<dyn ContentTransformer>) {
self.transformers.push(transformer);
}
pub fn process_block(&self, block: &mut Block) -> Result<()> {
for processor in &self.processors {
processor.process_block(block)?;
}
Ok(())
}
pub fn process_document(&self, document: &mut Document) -> Result<()> {
for processor in &self.processors {
processor.process_document(document)?;
}
Ok(())
}
pub fn validate_block(&self, block: &Block) -> Result<()> {
for validator in &self.validators {
validator.validate_block(block)?;
}
Ok(())
}
pub fn transform_content(&self, content: &str) -> Result<String> {
let mut result = content.to_string();
for transformer in &self.transformers {
result = transformer.transform(&result)?;
}
Ok(result)
}
pub fn processor_count(&self) -> usize {
self.processors.len()
}
pub fn validator_count(&self) -> usize {
self.validators.len()
}
pub fn transformer_count(&self) -> usize {
self.transformers.len()
}
pub fn processor_names(&self) -> Vec<&str> {
self.processors.iter().map(|p| p.name()).collect()
}
pub fn validator_names(&self) -> Vec<&str> {
self.validators.iter().map(|v| v.name()).collect()
}
pub fn transformer_names(&self) -> Vec<&str> {
self.transformers.iter().map(|t| t.name()).collect()
}
pub fn clear(&mut self) {
self.processors.clear();
self.validators.clear();
self.transformers.clear();
}
}
impl Default for PluginRegistry {
fn default() -> Self {
Self::new()
}
}
impl fmt::Debug for PluginRegistry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PluginRegistry")
.field("processor_count", &self.processor_count())
.field("validator_count", &self.validator_count())
.field("transformer_count", &self.transformer_count())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::BlockType;
struct MockProcessor;
impl BlockProcessor for MockProcessor {
fn name(&self) -> &str {
"MockProcessor"
}
fn description(&self) -> &str {
"A mock processor for testing"
}
fn process_block(&self, block: &mut Block) -> Result<bool> {
block.content = format!("[PROCESSED] {}", block.content);
Ok(true)
}
}
struct MockValidator;
impl BlockValidator for MockValidator {
fn name(&self) -> &str {
"MockValidator"
}
fn validate_block(&self, block: &Block) -> Result<()> {
if block.content.is_empty() {
Err(crate::error::BlocksError::EmptyContent {
block_type: "Mock".to_string(),
})
} else {
Ok(())
}
}
}
struct MockTransformer;
impl ContentTransformer for MockTransformer {
fn name(&self) -> &str {
"MockTransformer"
}
fn transform(&self, content: &str) -> Result<String> {
Ok(content.to_uppercase())
}
}
#[test]
fn test_register_processor() {
let mut registry = PluginRegistry::new();
assert_eq!(registry.processor_count(), 0);
registry.register_processor(Box::new(MockProcessor));
assert_eq!(registry.processor_count(), 1);
assert_eq!(registry.processor_names(), vec!["MockProcessor"]);
}
#[test]
fn test_register_validator() {
let mut registry = PluginRegistry::new();
assert_eq!(registry.validator_count(), 0);
registry.register_validator(Box::new(MockValidator));
assert_eq!(registry.validator_count(), 1);
assert_eq!(registry.validator_names(), vec!["MockValidator"]);
}
#[test]
fn test_register_transformer() {
let mut registry = PluginRegistry::new();
assert_eq!(registry.transformer_count(), 0);
registry.register_transformer(Box::new(MockTransformer));
assert_eq!(registry.transformer_count(), 1);
assert_eq!(registry.transformer_names(), vec!["MockTransformer"]);
}
#[test]
fn test_process_block() {
let mut reg = PluginRegistry::new();
reg.register_processor(Box::new(MockProcessor));
let mut block = Block::new(BlockType::Text, "test".to_string());
let original = block.content.clone();
reg.process_block(&mut block).unwrap();
assert!(block.content.contains("[PROCESSED]"));
assert!(block.content.contains(&original));
}
#[test]
fn test_validate_block() {
let mut registry = PluginRegistry::new();
registry.register_validator(Box::new(MockValidator));
let block = Block::new(BlockType::Text, "test".to_string());
assert!(registry.validate_block(&block).is_ok());
let empty_block = Block::new(BlockType::Text, "".to_string());
assert!(registry.validate_block(&empty_block).is_err());
}
#[test]
fn test_transform_content() {
let mut registry = PluginRegistry::new();
registry.register_transformer(Box::new(MockTransformer));
let result = registry.transform_content("hello").unwrap();
assert_eq!(result, "HELLO");
}
#[test]
fn test_clear_registry() {
let mut registry = PluginRegistry::new();
registry.register_processor(Box::new(MockProcessor));
registry.register_validator(Box::new(MockValidator));
registry.register_transformer(Box::new(MockTransformer));
assert!(registry.processor_count() > 0);
registry.clear();
assert_eq!(registry.processor_count(), 0);
assert_eq!(registry.validator_count(), 0);
assert_eq!(registry.transformer_count(), 0);
}
#[test]
fn test_debug_format() {
let mut registry = PluginRegistry::new();
registry.register_processor(Box::new(MockProcessor));
let debug_str = format!("{:?}", registry);
assert!(debug_str.contains("PluginRegistry"));
}
}