tectonic/io/
format_cache.rs1use std::{
7 io::{BufReader, Write},
8 path::PathBuf,
9};
10use tectonic_errors::{anyhow::bail, Result};
11
12use super::{InputHandle, InputOrigin, IoProvider, OpenResult};
13use crate::{digest::DigestData, status::StatusBackend};
14
15pub struct FormatCache {
22 bundle_digest: DigestData,
23 formats_base: PathBuf,
24}
25
26impl FormatCache {
27 pub fn new(bundle_digest: DigestData, formats_base: PathBuf) -> FormatCache {
33 FormatCache {
34 bundle_digest,
35 formats_base,
36 }
37 }
38
39 #[allow(clippy::manual_split_once)] fn path_for_format(&mut self, name: &str) -> Result<PathBuf> {
43 let stem = match name.split('.').next() {
47 Some(s) => s,
48 None => {
49 bail!("incomprehensible format file name \"{}\"", name);
50 }
51 };
52
53 let mut p = self.formats_base.clone();
54 p.push(format!(
55 "{}-{}-{}.fmt",
56 self.bundle_digest,
57 stem,
58 crate::FORMAT_SERIAL
59 ));
60 Ok(p)
61 }
62}
63
64impl IoProvider for FormatCache {
65 fn input_open_format(
66 &mut self,
67 name: &str,
68 _status: &mut dyn StatusBackend,
69 ) -> OpenResult<InputHandle> {
70 let path = match self.path_for_format(name) {
71 Ok(p) => p,
72 Err(e) => return OpenResult::Err(e),
73 };
74
75 let f = match super::try_open_file(path) {
76 OpenResult::Ok(f) => f,
77 OpenResult::NotAvailable => return OpenResult::NotAvailable,
78 OpenResult::Err(e) => return OpenResult::Err(e),
79 };
80
81 OpenResult::Ok(InputHandle::new_read_only(
82 name,
83 BufReader::new(f),
84 InputOrigin::Other,
85 ))
86 }
87
88 fn write_format(
89 &mut self,
90 name: &str,
91 data: &[u8],
92 _status: &mut dyn StatusBackend,
93 ) -> Result<()> {
94 let final_path = self.path_for_format(name)?;
95 let mut temp_dest = tempfile::Builder::new()
96 .prefix("format_")
97 .rand_bytes(6)
98 .tempfile_in(&self.formats_base)?;
99 temp_dest.write_all(data)?;
100 temp_dest.persist(final_path)?;
101 Ok(())
102 }
103}