use crate::processor::ProcessorSet;
use super::IDialect;
pub trait IProcessorDialect: IDialect {
fn get_prefix(&self) -> Option<&str>;
fn get_dialect_processor_precedence(&self) -> i32;
fn get_processors(&self, dialect_prefix: Option<&str>) -> Option<ProcessorSet>;
}
#[cfg(test)]
mod tests {
use std::sync::atomic::{AtomicI32, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
use super::IProcessorDialect;
use crate::dialect::IDialect;
use crate::processor::{IProcessor, ProcessorSet};
use crate::templatemode::TemplateMode;
struct ProbeProcessor {
template_mode: Option<TemplateMode>,
precedence: i32,
}
impl IProcessor for ProbeProcessor {
fn get_template_mode(&self) -> Option<TemplateMode> {
self.template_mode
}
fn get_precedence(&self) -> i32 {
self.precedence
}
}
struct MutableProcessorDialect {
name: Option<String>,
prefix: Option<String>,
precedence: AtomicI32,
calls: AtomicUsize,
last_prefix: Mutex<Option<Option<String>>>,
}
impl IDialect for MutableProcessorDialect {
fn get_name(&self) -> Option<&str> {
self.name.as_deref()
}
}
impl IProcessorDialect for MutableProcessorDialect {
fn get_prefix(&self) -> Option<&str> {
self.prefix.as_deref()
}
fn get_dialect_processor_precedence(&self) -> i32 {
self.precedence.load(Ordering::SeqCst)
}
fn get_processors(&self, dialect_prefix: Option<&str>) -> Option<ProcessorSet> {
self.calls.fetch_add(1, Ordering::SeqCst);
*self.last_prefix.lock().expect("last prefix lock") =
Some(dialect_prefix.map(str::to_owned));
if dialect_prefix == Some("return-null") {
return None;
}
let mut processors = ProcessorSet::new();
processors.insert(None);
processors.insert(Some(Arc::new(ProbeProcessor {
template_mode: Some(TemplateMode::HTML),
precedence: i32::MIN,
})));
processors.insert(Some(Arc::new(ProbeProcessor {
template_mode: None,
precedence: i32::MAX,
})));
Some(processors)
}
}
#[test]
fn preserves_nullable_prefixes_sets_elements_boundaries_and_dynamic_dispatch() {
let dialect = MutableProcessorDialect {
name: Some("probe".to_owned()),
prefix: None,
precedence: AtomicI32::new(i32::MIN),
calls: AtomicUsize::new(0),
last_prefix: Mutex::new(None),
};
let contract: &dyn IProcessorDialect = &dialect;
assert_eq!(contract.get_name(), Some("probe"));
assert_eq!(contract.get_prefix(), None);
assert_eq!(contract.get_dialect_processor_precedence(), i32::MIN);
let processors = contract
.get_processors(None)
.expect("null prefix still returns a set");
let observed = processors
.iter()
.map(|processor| {
processor.map(|value| (value.get_template_mode(), value.get_precedence()))
})
.collect::<Vec<_>>();
assert_eq!(
observed,
[
None,
Some((Some(TemplateMode::HTML), i32::MIN)),
Some((None, i32::MAX)),
]
);
assert_eq!(
*dialect.last_prefix.lock().expect("last prefix lock"),
Some(None)
);
dialect.precedence.store(i32::MAX, Ordering::SeqCst);
assert_eq!(contract.get_dialect_processor_precedence(), i32::MAX);
assert!(contract.get_processors(Some("return-null")).is_none());
assert_eq!(
*dialect.last_prefix.lock().expect("last prefix lock"),
Some(Some("return-null".to_owned()))
);
assert_eq!(dialect.calls.load(Ordering::SeqCst), 2);
}
}