#![deny(missing_docs)]
use std::{
io::{BufReader, Write},
path::PathBuf,
};
use tectonic_errors::{anyhow::bail, Result};
use super::{InputHandle, InputOrigin, IoProvider, OpenResult};
use crate::{digest::DigestData, status::StatusBackend};
pub struct FormatCache {
bundle_digest: DigestData,
formats_base: PathBuf,
}
impl FormatCache {
pub fn new(bundle_digest: DigestData, formats_base: PathBuf) -> FormatCache {
FormatCache {
bundle_digest,
formats_base,
}
}
#[allow(clippy::manual_split_once)] fn path_for_format(&mut self, name: &str) -> Result<PathBuf> {
let stem = match name.split('.').next() {
Some(s) => s,
None => {
bail!("incomprehensible format file name \"{}\"", name);
}
};
let mut p = self.formats_base.clone();
p.push(format!(
"{}-{}-{}.fmt",
self.bundle_digest.to_string(),
stem,
crate::FORMAT_SERIAL
));
Ok(p)
}
}
impl IoProvider for FormatCache {
fn input_open_format(
&mut self,
name: &str,
_status: &mut dyn StatusBackend,
) -> OpenResult<InputHandle> {
let path = match self.path_for_format(name) {
Ok(p) => p,
Err(e) => return OpenResult::Err(e),
};
let f = match super::try_open_file(&path) {
OpenResult::Ok(f) => f,
OpenResult::NotAvailable => return OpenResult::NotAvailable,
OpenResult::Err(e) => return OpenResult::Err(e),
};
OpenResult::Ok(InputHandle::new_read_only(
name,
BufReader::new(f),
InputOrigin::Other,
))
}
fn write_format(
&mut self,
name: &str,
data: &[u8],
_status: &mut dyn StatusBackend,
) -> Result<()> {
let final_path = self.path_for_format(name)?;
let mut temp_dest = tempfile::Builder::new()
.prefix("format_")
.rand_bytes(6)
.tempfile_in(&self.formats_base)?;
temp_dest.write_all(data)?;
temp_dest.persist(&final_path)?;
Ok(())
}
}