use std::path::Path;
use std::sync::Arc;
use model::ImageMacro;
use resources::{CachingLoader, Font, FontLoader, Loader, Template, TemplateLoader};
use util::cache::ThreadSafeCache;
use super::error::CaptionError;
use super::output::CaptionOutput;
use super::task::CaptionTask;
const DEFAULT_TEMPLATE_CAPACITY: usize = 128;
const DEFAULT_FONT_CAPACITY: usize = 16;
#[derive(Clone, Debug)]
pub struct Engine<Tl = TemplateLoader, Fl = FontLoader>
where Tl: Loader<Item=Template>, Fl: Loader<Item=Font>
{
inner: Arc<Inner<Tl, Fl>>,
}
#[derive(Debug)]
pub(super) struct Inner<Tl, Fl>
where Tl: Loader<Item=Template>, Fl: Loader<Item=Font>
{
pub template_loader: CachingLoader<Tl>,
pub font_loader: CachingLoader<Fl>,
}
impl<Tl, Fl> From<Inner<Tl, Fl>> for Engine<Tl, Fl>
where Tl: Loader<Item=Template>, Fl: Loader<Item=Font>
{
fn from(inner: Inner<Tl, Fl>) -> Self {
Engine{inner: Arc::new(inner)}
}
}
impl Engine<TemplateLoader, FontLoader> {
#[inline]
pub fn new<Dt, Df>(template_directory: Dt, font_directory: Df) -> Self
where Dt: AsRef<Path>, Df: AsRef<Path>
{
Engine::with_loaders(
TemplateLoader::new(template_directory),
FontLoader::new(font_directory),
)
}
}
impl<Tl, Fl> Engine<Tl, Fl>
where Tl: Loader<Item=Template>, Fl: Loader<Item=Font>
{
#[inline]
pub fn with_loaders(template_loader: Tl, font_loader: Fl) -> Self {
Engine::from(Inner{
template_loader: CachingLoader::new(template_loader, DEFAULT_TEMPLATE_CAPACITY),
font_loader: CachingLoader::new(font_loader, DEFAULT_FONT_CAPACITY),
})
}
#[inline]
pub fn with_raw_loaders(template_loader: Tl, font_loader: Fl) -> Self {
Engine::from(Inner{
template_loader: CachingLoader::phony(template_loader),
font_loader: CachingLoader::phony(font_loader),
})
}
}
impl<Tl, Fl> Engine<Tl, Fl>
where Tl: Loader<Item=Template>, Fl: Loader<Item=Font>
{
#[inline]
pub fn caption(&self, image_macro: ImageMacro) -> Result<CaptionOutput, CaptionError<Tl, Fl>> {
CaptionTask::new(image_macro, self.inner.clone()).perform()
}
}
impl<Tl, Fl> Engine<Tl, Fl>
where Tl: Loader<Item=Template>, Fl: Loader<Item=Font>
{
pub fn preload_template(&self, name: &str) -> Result<(), Tl::Err> {
if !self.inner.template_loader.phony {
self.inner.template_loader.load(name)?;
}
Ok(())
}
pub fn preload_font(&self, name: &str) -> Result<(), Fl::Err> {
if !self.inner.font_loader.phony {
self.inner.font_loader.load(name)?;
}
Ok(())
}
pub fn template_cache(&self) -> Option<&ThreadSafeCache<String, Tl::Item>> {
if self.inner.template_loader.phony {
None
} else {
Some(self.inner.template_loader.cache())
}
}
pub fn font_cache(&self) -> Option<&ThreadSafeCache<String, Fl::Item>> {
if self.inner.font_loader.phony {
None
} else {
Some(self.inner.font_loader.cache())
}
}
}
#[cfg(test)]
mod tests {
use super::Engine;
#[test]
fn thread_safe() {
fn assert_sync<T: Sync>() {}
fn assert_send<T: Send>() {}
assert_sync::<Engine>();
assert_send::<Engine>();
}
}