typst_as_lib/
cached_file_resolver.rs

1use 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            if let Ok(in_memory_binary_cache) = in_memory_binary_cache.lock() {
57                if let Some(cached) = in_memory_binary_cache.get(&id) {
58                    return Ok(Cow::Owned(cached.clone()));
59                }
60            }
61        }
62        let resolved = self.file_resolver.resolve_binary(id)?;
63        if let Some(in_memory_binary_cache) = in_memory_binary_cache {
64            if let Ok(mut in_memory_binary_cache) = in_memory_binary_cache.lock() {
65                in_memory_binary_cache.insert(id, resolved.as_ref().clone());
66            }
67        }
68        Ok(resolved)
69    }
70
71    fn resolve_source(&self, id: FileId) -> FileResult<Cow<Source>> {
72        let Self {
73            in_memory_source_cache,
74            ..
75        } = self;
76
77        if let Some(in_memory_source_cache) = in_memory_source_cache {
78            if let Ok(in_memory_source_cache) = in_memory_source_cache.lock() {
79                if let Some(cached) = in_memory_source_cache.get(&id) {
80                    return Ok(Cow::Owned(cached.clone()));
81                }
82            }
83        }
84        let resolved = self.file_resolver.resolve_source(id)?;
85        if let Some(in_memory_source_cache) = in_memory_source_cache {
86            if let Ok(mut in_memory_source_cache) = in_memory_source_cache.lock() {
87                in_memory_source_cache.insert(id, resolved.as_ref().clone());
88            }
89        }
90        Ok(resolved)
91    }
92}
93
94pub trait IntoCachedFileResolver {
95    fn into_cached(self) -> CachedFileResolver<Self>
96    where
97        Self: Sized;
98}