typst_as_lib/
cached_file_resolver.rs1use std::{
2 borrow::Cow,
3 collections::HashMap,
4 sync::{Arc, Mutex},
5};
6
7use typst::{
8 diag::FileResult,
9 foundations::Bytes,
10 syntax::{FileId, Source},
11};
12
13use crate::file_resolver::FileResolver;
14
15pub struct CachedFileResolver<T> {
16 pub file_resolver: T,
17 pub in_memory_source_cache: Option<Arc<Mutex<HashMap<FileId, Source>>>>,
18 pub in_memory_binary_cache: Option<Arc<Mutex<HashMap<FileId, Bytes>>>>,
19}
20
21impl<T> CachedFileResolver<T> {
22 pub fn new(file_resolver: T) -> Self {
23 CachedFileResolver {
24 file_resolver,
25 in_memory_source_cache: None,
26 in_memory_binary_cache: None,
27 }
28 }
29
30 pub fn with_in_memory_source_cache(self) -> Self {
31 Self {
32 in_memory_source_cache: Some(Default::default()),
33 ..self
34 }
35 }
36
37 pub fn with_in_memory_binary_cache(self) -> Self {
38 Self {
39 in_memory_binary_cache: Some(Default::default()),
40 ..self
41 }
42 }
43}
44
45impl<T> FileResolver for CachedFileResolver<T>
46where
47 T: FileResolver,
48{
49 fn resolve_binary(&self, id: FileId) -> FileResult<Cow<'_, Bytes>> {
50 let Self {
51 in_memory_binary_cache,
52 ..
53 } = self;
54
55 if let Some(in_memory_binary_cache) = in_memory_binary_cache
56 && let Ok(in_memory_binary_cache) = in_memory_binary_cache.lock()
57 && let Some(cached) = in_memory_binary_cache.get(&id)
58 {
59 return Ok(Cow::Owned(cached.clone()));
60 }
61 let resolved = self.file_resolver.resolve_binary(id)?;
62 if let Some(in_memory_binary_cache) = in_memory_binary_cache
63 && let Ok(mut in_memory_binary_cache) = in_memory_binary_cache.lock()
64 {
65 in_memory_binary_cache.insert(id, resolved.as_ref().clone());
66 }
67 Ok(resolved)
68 }
69
70 fn resolve_source(&self, id: FileId) -> FileResult<Cow<'_, Source>> {
71 let Self {
72 in_memory_source_cache,
73 ..
74 } = self;
75
76 if let Some(in_memory_source_cache) = in_memory_source_cache
77 && let Ok(in_memory_source_cache) = in_memory_source_cache.lock()
78 && let Some(cached) = in_memory_source_cache.get(&id)
79 {
80 return Ok(Cow::Owned(cached.clone()));
81 }
82 let resolved = self.file_resolver.resolve_source(id)?;
83 if let Some(in_memory_source_cache) = in_memory_source_cache
84 && let Ok(mut in_memory_source_cache) = in_memory_source_cache.lock()
85 {
86 in_memory_source_cache.insert(id, resolved.as_ref().clone());
87 }
88 Ok(resolved)
89 }
90}
91
92pub trait IntoCachedFileResolver {
93 fn into_cached(self) -> CachedFileResolver<Self>
94 where
95 Self: Sized;
96}