use crate::cache::{TemplateLoader, TemplateSource};
use crate::error::{Result, TemplateError};
use encoding_rs::Encoding;
#[derive(Default)]
pub struct StringLoader {
templates: std::sync::Mutex<Vec<(String, Vec<u8>)>>,
}
impl StringLoader {
pub fn put(&self, name: &str, text: &str) {
self.put_bytes(name, text.as_bytes());
}
pub fn put_bytes(&self, name: &str, bytes: &[u8]) {
let mut t = self.templates.lock().unwrap();
t.retain(|(n, _)| n != name);
t.push((name.to_string(), bytes.to_vec()));
}
}
impl TemplateLoader for StringLoader {
fn find(&self, name: &str) -> Result<Option<Box<dyn TemplateSource>>> {
let t = self.templates.lock().unwrap();
Ok(t.iter()
.find(|(n, _)| n == name)
.map(|(n, _)| Box::new(StringSource(n.clone())) as Box<dyn TemplateSource>))
}
fn read(&self, src: &dyn TemplateSource) -> Result<String> {
self.read_encoded(src, "UTF-8")
}
fn read_encoded(&self, src: &dyn TemplateSource, encoding: &str) -> Result<String> {
let t = self.templates.lock().unwrap();
let bytes = t
.iter()
.find(|(n, _)| n == &src.name())
.map(|(_, b)| b.clone())
.ok_or_else(|| TemplateError::NotFound { name: src.name() })?;
let enc = Encoding::for_label(encoding.as_bytes()).ok_or_else(|| {
TemplateError::misc(format!(
"Unknown encoding: \"{encoding}\". Did you mean to use an IANA character set name?"
))
})?;
let (text, _, _) = enc.decode(&bytes);
Ok(text.into_owned())
}
}
pub struct StringSource(String);
impl TemplateSource for StringSource {
fn name(&self) -> String {
self.0.clone()
}
}