use std::{
error::Error,
fmt::{Display, Formatter},
};
use lady_deirdre::{
analysis::{AnalysisError, AnalysisResult},
arena::{Id, Identifiable},
};
use crate::report::system_panic;
pub type ModuleResult<T> = Result<T, ModuleError>;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
pub enum ModuleError {
Interrupted(Id),
Timeout(Id),
Cursor(Id),
}
impl Error for ModuleError {}
impl Identifiable for ModuleError {
#[inline(always)]
fn id(&self) -> Id {
match self {
Self::Interrupted(id) => *id,
Self::Timeout(id) => *id,
Self::Cursor(id) => *id,
}
}
}
impl Display for ModuleError {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Interrupted(id) => formatter.write_fmt(format_args!(
"Cannot complete module {id} analysis request because the \
operation was interrupted.",
)),
Self::Timeout(id) => {
formatter.write_fmt(format_args!("Module {id} analysis request timed out.",))
}
Self::Cursor(id) => formatter.write_fmt(format_args!(
"The specified source code site or range of sites is not valid for module {id}.",
)),
}
}
}
pub(crate) trait ModuleResultEx<T>: Sized {
fn into_module_result(self, id: Id) -> ModuleResult<T>;
fn forward(self) -> AnalysisResult<T>;
}
impl<T> ModuleResultEx<T> for AnalysisResult<T> {
#[track_caller]
#[inline(always)]
fn into_module_result(self, id: Id) -> ModuleResult<T> {
match self {
Ok(ok) => Ok(ok),
Err(error) => match error {
AnalysisError::Interrupted => Err(ModuleError::Interrupted(id)),
AnalysisError::Timeout if cfg!(not(debug_assertions)) => {
Err(ModuleError::Timeout(id))
}
_ => system_panic!("Analysis internal error. {error}",),
},
}
}
#[track_caller]
#[inline(always)]
fn forward(self) -> AnalysisResult<T> {
match self {
Ok(ok) => Ok(ok),
Err(error) if !error.is_abnormal() => Err(error),
Err(error) => system_panic!("Analysis internal error. {error}",),
}
}
}