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