use quillmark_core::{
Backend, Diagnostic, Document, OutputFormat, Quill, RenderError, RenderOptions, RenderResult,
RenderSession, Severity,
};
use std::collections::HashMap;
use std::sync::Arc;
pub struct Quillmark {
backends: HashMap<String, Arc<dyn Backend>>,
}
impl Quillmark {
pub fn new() -> Self {
#[allow(unused_mut)]
let mut engine = Self {
backends: HashMap::new(),
};
#[cfg(feature = "typst")]
{
engine.register_backend(Box::new(quillmark_typst::TypstBackend));
}
engine
}
pub fn register_backend(&mut self, backend: Box<dyn Backend>) {
let id = backend.id().to_string();
self.backends.insert(id, Arc::from(backend));
}
pub fn registered_backends(&self) -> Vec<&str> {
self.backends.keys().map(|s| s.as_str()).collect()
}
fn resolve_backend(&self, quill: &Quill) -> Result<&Arc<dyn Backend>, RenderError> {
let backend_id = quill.backend_id();
self.backends
.get(backend_id)
.ok_or_else(|| RenderError::UnsupportedBackend {
diags: vec![Diagnostic::new(
Severity::Error,
format!("Backend '{}' not registered or not enabled", backend_id),
)
.with_code("engine::backend_not_found".to_string())
.with_hint(format!(
"Available backends: {}",
self.backends.keys().cloned().collect::<Vec<_>>().join(", ")
))],
})
}
pub fn open(&self, quill: &Quill, doc: &Document) -> Result<RenderSession, RenderError> {
let backend = self.resolve_backend(quill)?;
quill.check_quill_reference(doc)?;
let json_data = quill.compile_data(doc)?;
let plate_content = quill
.plate()
.filter(|s| !s.is_empty())
.unwrap_or("")
.to_string();
backend.open(&plate_content, quill, &json_data)
}
pub fn render(
&self,
quill: &Quill,
doc: &Document,
opts: &RenderOptions,
) -> Result<RenderResult, RenderError> {
let default_format = self.supported_formats(quill)?.first().copied();
let session = self.open(quill, doc)?;
let resolved = RenderOptions {
output_format: opts.output_format.or(default_format),
ppi: opts.ppi,
pages: opts.pages.clone(),
producer: opts.producer.clone(),
};
session.render(&resolved)
}
pub fn supported_formats(
&self,
quill: &Quill,
) -> Result<&'static [OutputFormat], RenderError> {
Ok(self.resolve_backend(quill)?.supported_formats())
}
pub fn supports_canvas(&self, quill: &Quill) -> bool {
self.resolve_backend(quill)
.map(|b| b.supports_canvas())
.unwrap_or(false)
}
}
impl Default for Quillmark {
fn default() -> Self {
Self::new()
}
}