tinymist_vfs/
snapshot.rs

1use core::fmt;
2
3use typst::diag::{FileError, FileResult};
4
5use crate::{Bytes, ImmutPath};
6
7/// A file snapshot that is notified by some external source
8///
9/// Note: The error is boxed to avoid large stack size
10#[derive(Clone, PartialEq, Eq)]
11pub struct FileSnapshot(Result<Bytes, Box<FileError>>);
12
13#[derive(Debug)]
14#[allow(dead_code)]
15struct FileContent {
16    len: usize,
17}
18
19impl fmt::Debug for FileSnapshot {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        match self.0.as_ref() {
22            Ok(v) => f
23                .debug_struct("FileSnapshot")
24                .field("content", &FileContent { len: v.len() })
25                .finish(),
26            Err(e) => f.debug_struct("FileSnapshot").field("error", &e).finish(),
27        }
28    }
29}
30
31impl FileSnapshot {
32    /// content of the file
33    #[inline]
34    #[track_caller]
35    pub fn content(&self) -> FileResult<&Bytes> {
36        self.0.as_ref().map_err(|e| *e.clone())
37    }
38
39    /// Whether the related file is a file
40    #[inline]
41    #[track_caller]
42    pub fn is_file(&self) -> FileResult<bool> {
43        self.content().map(|_| true)
44    }
45}
46
47impl std::ops::Deref for FileSnapshot {
48    type Target = Result<Bytes, Box<FileError>>;
49
50    fn deref(&self) -> &Self::Target {
51        &self.0
52    }
53}
54
55impl std::ops::DerefMut for FileSnapshot {
56    fn deref_mut(&mut self) -> &mut Self::Target {
57        &mut self.0
58    }
59}
60
61/// Convenient function to create a [`FileSnapshot`] from tuple
62impl From<FileResult<Bytes>> for FileSnapshot {
63    fn from(result: FileResult<Bytes>) -> Self {
64        Self(result.map_err(Box::new))
65    }
66}
67
68/// A set of changes to the filesystem.
69///
70/// The correct order of applying changes is:
71/// 1. Remove files
72/// 2. Upsert (Insert or Update) files
73#[derive(Debug, Clone, Default)]
74pub struct FileChangeSet {
75    /// Files to remove
76    pub removes: Vec<ImmutPath>,
77    /// Files to insert or update
78    pub inserts: Vec<(ImmutPath, FileSnapshot)>,
79}
80
81impl FileChangeSet {
82    /// Create a new empty changeset
83    pub fn is_empty(&self) -> bool {
84        self.inserts.is_empty() && self.removes.is_empty()
85    }
86
87    /// Create a new changeset with removing files
88    pub fn new_removes(removes: Vec<ImmutPath>) -> Self {
89        Self {
90            removes,
91            inserts: vec![],
92        }
93    }
94
95    /// Create a new changeset with inserting files
96    pub fn new_inserts(inserts: Vec<(ImmutPath, FileSnapshot)>) -> Self {
97        Self {
98            removes: vec![],
99            inserts,
100        }
101    }
102
103    /// Utility function to insert a possible file to insert or update
104    pub fn may_insert(&mut self, v: Option<(ImmutPath, FileSnapshot)>) {
105        if let Some(v) = v {
106            self.inserts.push(v);
107        }
108    }
109
110    /// Utility function to insert multiple possible files to insert or update
111    pub fn may_extend(&mut self, v: Option<impl Iterator<Item = (ImmutPath, FileSnapshot)>>) {
112        if let Some(v) = v {
113            self.inserts.extend(v);
114        }
115    }
116}