rust/crates/base_db/src/change.rs
Aleksey Kladov 8716c4cec3 Move ide::AnalysisChange -> base_db::Change
This seems like a better factoring logically; ideally, clients shouldn't touch
`set_` methods of the database directly. Additionally, I think this
should remove the unfortunate duplication in fixture code.
2020-10-02 16:45:08 +02:00

98 lines
3.3 KiB
Rust

//! Defines a unit of change that can applied to the database to get the next
//! state. Changes are transactional.
use std::{fmt, sync::Arc};
use rustc_hash::FxHashSet;
use salsa::Durability;
use vfs::FileId;
use crate::{CrateGraph, SourceDatabaseExt, SourceRoot, SourceRootId};
/// Encapsulate a bunch of raw `.set` calls on the database.
#[derive(Default)]
pub struct Change {
pub roots: Option<Vec<SourceRoot>>,
pub files_changed: Vec<(FileId, Option<Arc<String>>)>,
pub crate_graph: Option<CrateGraph>,
}
impl fmt::Debug for Change {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let mut d = fmt.debug_struct("AnalysisChange");
if let Some(roots) = &self.roots {
d.field("roots", roots);
}
if !self.files_changed.is_empty() {
d.field("files_changed", &self.files_changed.len());
}
if self.crate_graph.is_some() {
d.field("crate_graph", &self.crate_graph);
}
d.finish()
}
}
impl Change {
pub fn new() -> Change {
Change::default()
}
pub fn set_roots(&mut self, roots: Vec<SourceRoot>) {
self.roots = Some(roots);
}
pub fn change_file(&mut self, file_id: FileId, new_text: Option<Arc<String>>) {
self.files_changed.push((file_id, new_text))
}
pub fn set_crate_graph(&mut self, graph: CrateGraph) {
self.crate_graph = Some(graph);
}
pub fn apply(self, db: &mut dyn SourceDatabaseExt) {
let _p = profile::span("RootDatabase::apply_change");
// db.request_cancellation();
// log::info!("apply_change {:?}", change);
if let Some(roots) = self.roots {
let mut local_roots = FxHashSet::default();
let mut library_roots = FxHashSet::default();
for (idx, root) in roots.into_iter().enumerate() {
let root_id = SourceRootId(idx as u32);
let durability = durability(&root);
if root.is_library {
library_roots.insert(root_id);
} else {
local_roots.insert(root_id);
}
for file_id in root.iter() {
db.set_file_source_root_with_durability(file_id, root_id, durability);
}
db.set_source_root_with_durability(root_id, Arc::new(root), durability);
}
// db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
// db.set_library_roots_with_durability(Arc::new(library_roots), Durability::HIGH);
}
for (file_id, text) in self.files_changed {
let source_root_id = db.file_source_root(file_id);
let source_root = db.source_root(source_root_id);
let durability = durability(&source_root);
// XXX: can't actually remove the file, just reset the text
let text = text.unwrap_or_default();
db.set_file_text_with_durability(file_id, text, durability)
}
if let Some(crate_graph) = self.crate_graph {
db.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH)
}
}
}
fn durability(source_root: &SourceRoot) -> Durability {
if source_root.is_library {
Durability::HIGH
} else {
Durability::LOW
}
}