use std::fmt;
#[derive(Debug)]
#[non_exhaustive]
pub enum ViewError {
Render {
source: askama::Error,
},
}
impl From<askama::Error> for ViewError {
fn from(source: askama::Error) -> Self {
Self::Render { source }
}
}
impl fmt::Display for ViewError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Render { source } => write!(formatter, "view rendering failed: {source}"),
}
}
}
impl std::error::Error for ViewError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Render { source } => Some(source),
}
}
}
impl From<ViewError> for crate::Error {
fn from(error: ViewError) -> Self {
report(&error);
crate::Error::Other("view rendering failed".into())
}
}
fn report(error: &ViewError) {
#[cfg(feature = "observe")]
tracing::error!(%error, "a view failed to render; the client gets a generic 500");
#[cfg(not(feature = "observe"))]
let _ = error;
}
#[cfg(test)]
mod tests {
use crate::view::test_support::Unformattable;
use crate::view::view;
#[test]
fn the_framework_error_carries_no_template_detail() {
let failure = view(Unformattable::default()).render().unwrap_err();
let detail = failure.to_string();
assert!(detail.starts_with("view rendering failed"));
let framework: crate::Error = failure.into();
assert_eq!(framework.status(), 500);
assert_eq!(framework.code(), "internal_error");
assert_eq!(
framework.to_string(),
"internal error: view rendering failed"
);
}
}