pub type FreezeResult<T> = std::result::Result<T, FreezeError>;
#[derive(Debug)]
pub struct FreezeError {
pub err_msg: String,
pub contexts: Vec<String>,
}
impl From<FreezeError> for anyhow::Error {
#[cold]
fn from(e: FreezeError) -> Self {
let mut anyhow = anyhow::anyhow!(e.err_msg);
for context in e.contexts.into_iter().rev() {
anyhow = anyhow.context(context);
}
anyhow
}
}
impl From<FreezeError> for starlark_syntax::Error {
#[cold]
fn from(e: FreezeError) -> Self {
starlark_syntax::Error::new_kind(starlark_syntax::ErrorKind::Freeze(e.into()))
}
}
impl FreezeError {
pub fn new(err_msg: String) -> Self {
Self {
err_msg,
contexts: Vec::new(),
}
}
pub fn context(mut self, context: &str) -> Self {
self.contexts.push(context.to_owned());
self
}
}
pub trait FreezeErrorContext<T>: Sealed {
#[track_caller]
fn freeze_error_context(self, context: &str) -> FreezeResult<T>;
}
pub trait Sealed: Sized {}
impl<T> Sealed for std::result::Result<T, FreezeError> {}
impl<T> FreezeErrorContext<T> for std::result::Result<T, FreezeError> {
fn freeze_error_context(self, c: &str) -> FreezeResult<T> {
match self {
Ok(x) => Ok(x),
Err(e) => Err(e.context(c)),
}
}
}