#![allow(clippy::enum_variant_names)]
use crate::cancelation::Canceled;
use mun_hir::{HirDatabase, Upcast};
use mun_target::spec::Target;
use salsa::{Database, Durability, Snapshot};
use std::panic;
#[salsa::database(
mun_hir::SourceDatabaseStorage,
mun_hir::DefDatabaseStorage,
mun_hir::HirDatabaseStorage,
mun_hir::AstDatabaseStorage,
mun_hir::InternDatabaseStorage
)]
pub(crate) struct AnalysisDatabase {
storage: salsa::Storage<Self>,
}
impl Default for AnalysisDatabase {
fn default() -> Self {
let mut db = AnalysisDatabase {
storage: Default::default(),
};
db.set_target(Target::host_target().expect("could not determine host target spec"));
db
}
}
impl AnalysisDatabase {
pub fn request_cancelation(&mut self) {
self.salsa_runtime_mut().synthetic_write(Durability::LOW);
}
}
impl salsa::Database for AnalysisDatabase {
fn on_propagated_panic(&self) -> ! {
Canceled::throw()
}
fn salsa_event(&self, event: salsa::Event) {
match event.kind {
salsa::EventKind::DidValidateMemoizedValue { .. }
| salsa::EventKind::WillExecute { .. } => {
self.check_canceled();
}
_ => (),
}
}
}
impl Upcast<dyn mun_hir::AstDatabase> for AnalysisDatabase {
fn upcast(&self) -> &(dyn mun_hir::AstDatabase + 'static) {
self
}
}
impl Upcast<dyn mun_hir::SourceDatabase> for AnalysisDatabase {
fn upcast(&self) -> &(dyn mun_hir::SourceDatabase + 'static) {
self
}
}
impl Upcast<dyn mun_hir::DefDatabase> for AnalysisDatabase {
fn upcast(&self) -> &(dyn mun_hir::DefDatabase + 'static) {
self
}
}
impl Upcast<dyn mun_hir::HirDatabase> for AnalysisDatabase {
fn upcast(&self) -> &(dyn mun_hir::HirDatabase + 'static) {
self
}
}
impl AnalysisDatabase {
fn check_canceled(&self) {
if self.salsa_runtime().is_current_revision_canceled() {
Canceled::throw()
}
}
pub fn catch_canceled<F, T>(&self, f: F) -> Result<T, Canceled>
where
Self: Sized + panic::RefUnwindSafe,
F: FnOnce(&Self) -> T + panic::UnwindSafe,
{
panic::catch_unwind(|| f(self)).map_err(|err| match err.downcast::<Canceled>() {
Ok(canceled) => *canceled,
Err(payload) => panic::resume_unwind(payload),
})
}
}
impl salsa::ParallelDatabase for AnalysisDatabase {
fn snapshot(&self) -> Snapshot<Self> {
Snapshot::new(AnalysisDatabase {
storage: self.storage.snapshot(),
})
}
}