base_db/
change.rs

1//! Defines a unit of change that can applied to the database to get the next
2//! state. Changes are transactional.
3
4use std::fmt;
5
6use salsa::Durability;
7use triomphe::Arc;
8use vfs::FileId;
9
10use crate::{CrateGraphBuilder, CratesIdMap, RootQueryDb, SourceRoot, SourceRootId};
11
12/// Encapsulate a bunch of raw `.set` calls on the database.
13#[derive(Default)]
14pub struct FileChange {
15    pub roots: Option<Vec<SourceRoot>>,
16    pub files_changed: Vec<(FileId, Option<String>)>,
17    pub crate_graph: Option<CrateGraphBuilder>,
18}
19
20impl fmt::Debug for FileChange {
21    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
22        let mut d = fmt.debug_struct("Change");
23        if let Some(roots) = &self.roots {
24            d.field("roots", roots);
25        }
26        if !self.files_changed.is_empty() {
27            d.field("files_changed", &self.files_changed.len());
28        }
29        if self.crate_graph.is_some() {
30            d.field("crate_graph", &self.crate_graph);
31        }
32        d.finish()
33    }
34}
35
36impl FileChange {
37    pub fn set_roots(&mut self, roots: Vec<SourceRoot>) {
38        self.roots = Some(roots);
39    }
40
41    pub fn change_file(&mut self, file_id: FileId, new_text: Option<String>) {
42        self.files_changed.push((file_id, new_text))
43    }
44
45    pub fn set_crate_graph(&mut self, graph: CrateGraphBuilder) {
46        self.crate_graph = Some(graph);
47    }
48
49    pub fn apply(self, db: &mut dyn RootQueryDb) -> Option<CratesIdMap> {
50        let _p = tracing::info_span!("FileChange::apply").entered();
51        if let Some(roots) = self.roots {
52            for (idx, root) in roots.into_iter().enumerate() {
53                let root_id = SourceRootId(idx as u32);
54                let durability = source_root_durability(&root);
55                for file_id in root.iter() {
56                    db.set_file_source_root_with_durability(file_id, root_id, durability);
57                }
58
59                db.set_source_root_with_durability(root_id, Arc::new(root), durability);
60            }
61        }
62
63        for (file_id, text) in self.files_changed {
64            let source_root_id = db.file_source_root(file_id);
65            let source_root = db.source_root(source_root_id.source_root_id(db));
66
67            let durability = file_text_durability(&source_root.source_root(db));
68            // XXX: can't actually remove the file, just reset the text
69            let text = text.unwrap_or_default();
70            db.set_file_text_with_durability(file_id, &text, durability)
71        }
72
73        if let Some(crate_graph) = self.crate_graph {
74            return Some(crate_graph.set_in_db(db));
75        }
76        None
77    }
78}
79
80fn source_root_durability(source_root: &SourceRoot) -> Durability {
81    if source_root.is_library { Durability::MEDIUM } else { Durability::LOW }
82}
83
84fn file_text_durability(source_root: &SourceRoot) -> Durability {
85    if source_root.is_library { Durability::HIGH } else { Durability::LOW }
86}