1use std::{borrow::Borrow, cmp::Ord, path::Path};
2
3use rpds::RedBlackTreeMapSync;
4use tinymist_std::ImmutPath;
5use typst::diag::FileResult;
6
7use crate::{AccessModel, Bytes, FileId, FileSnapshot, PathAccessModel};
8
9#[derive(Default, Debug, Clone)]
12pub struct OverlayAccessModel<K: Ord, M> {
13 files: RedBlackTreeMapSync<K, FileSnapshot>,
14 pub inner: M,
16}
17
18impl<K: Ord + Clone, M> OverlayAccessModel<K, M> {
19 pub fn new(inner: M) -> Self {
21 Self {
22 files: RedBlackTreeMapSync::default(),
23 inner,
24 }
25 }
26
27 pub fn inner(&self) -> &M {
29 &self.inner
30 }
31
32 pub fn inner_mut(&mut self) -> &mut M {
34 &mut self.inner
35 }
36
37 pub fn clear_shadow(&mut self) {
39 self.files = RedBlackTreeMapSync::default();
40 }
41
42 pub fn file_paths(&self) -> Vec<K> {
44 self.files.keys().cloned().collect()
45 }
46
47 pub fn add_file<Q: Ord + ?Sized>(
49 &mut self,
50 path: &Q,
51 snap: FileSnapshot,
52 cast: impl Fn(&Q) -> K,
53 ) where
54 K: Borrow<Q>,
55 {
56 match self.files.get_mut(path) {
57 Some(e) => {
58 *e = snap;
59 }
60 None => {
61 self.files.insert_mut(cast(path), snap);
62 }
63 }
64 }
65
66 pub fn remove_file<Q: Ord + ?Sized>(&mut self, path: &Q)
68 where
69 K: Borrow<Q>,
70 {
71 self.files.remove_mut(path);
72 }
73}
74
75impl<M: PathAccessModel> PathAccessModel for OverlayAccessModel<ImmutPath, M> {
76 fn content(&self, src: &Path) -> FileResult<Bytes> {
77 if let Some(content) = self.files.get(src) {
78 return content.content().cloned();
79 }
80
81 self.inner.content(src)
82 }
83}
84
85impl<M: AccessModel> AccessModel for OverlayAccessModel<FileId, M> {
86 fn reset(&mut self) {
87 self.inner.reset();
88 }
89
90 fn content(&self, src: FileId) -> (Option<ImmutPath>, FileResult<Bytes>) {
91 if let Some(content) = self.files.get(&src) {
92 return (None, content.content().cloned());
93 }
94
95 self.inner.content(src)
96 }
97}