use crate::metadata::ErrorMetadata;
use std::any::TypeId;
use std::error::Error as StdError;
pub type JsonRenderFn =
fn(&(dyn StdError + 'static)) -> Option<Result<serde_json::Value, serde_json::Error>>;
pub type DebugRenderFn = fn(&(dyn StdError + 'static)) -> Option<String>;
pub type HtmlRenderFn = fn(&(dyn StdError + 'static)) -> Option<String>;
pub type GraphqlRenderFn =
fn(&(dyn StdError + 'static)) -> Option<Result<serde_json::Value, serde_json::Error>>;
pub type TextRenderFn = fn(&(dyn StdError + 'static)) -> Option<String>;
pub type HttpStatusFn = fn(&(dyn StdError + 'static)) -> Option<http::StatusCode>;
pub type JsonRpcRenderFn =
fn(&(dyn StdError + 'static)) -> Option<Result<serde_json::Value, serde_json::Error>>;
pub type HttpHeadersFn =
fn(&(dyn StdError + 'static)) -> Option<Vec<(http::HeaderName, http::HeaderValue)>>;
pub struct ErrorRegistryEntry {
pub type_id: TypeId,
pub type_name: &'static str,
pub metadata: &'static ErrorMetadata,
pub render_json: JsonRenderFn,
pub render_debug: DebugRenderFn,
pub render_html: HtmlRenderFn,
pub render_graphql: GraphqlRenderFn,
pub render_text: TextRenderFn,
pub http_status: HttpStatusFn,
pub render_jsonrpc: JsonRpcRenderFn,
pub http_headers: HttpHeadersFn,
}
#[doc(hidden)]
#[linkme::distributed_slice]
pub static ERROR_REGISTRY: [ErrorRegistryEntry] = [..];
fn render_with<T, F>(error: &(dyn StdError + 'static), get_render_fn: F) -> Option<T>
where
F: Fn(&ErrorRegistryEntry) -> fn(&(dyn StdError + 'static)) -> Option<T>,
{
for entry in ERROR_REGISTRY {
let render_fn = get_render_fn(entry);
if let Some(rendered) = render_fn(error) {
return Some(rendered);
}
}
None
}
pub(crate) fn render_json(
error: &(dyn StdError + 'static),
) -> Option<Result<serde_json::Value, serde_json::Error>> {
render_with(error, |entry| entry.render_json)
}
pub(crate) fn render_debug(error: &(dyn StdError + 'static)) -> Option<String> {
render_with(error, |entry| entry.render_debug)
}
pub(crate) fn render_html(error: &(dyn StdError + 'static)) -> Option<String> {
render_with(error, |entry| entry.render_html)
}
pub(crate) fn render_graphql(
error: &(dyn StdError + 'static),
) -> Option<Result<serde_json::Value, serde_json::Error>> {
render_with(error, |entry| entry.render_graphql)
}
pub(crate) fn render_text(error: &(dyn StdError + 'static)) -> Option<String> {
render_with(error, |entry| entry.render_text)
}
pub(crate) fn http_status(error: &(dyn StdError + 'static)) -> Option<http::StatusCode> {
render_with(error, |entry| entry.http_status)
}
pub(crate) fn render_jsonrpc(
error: &(dyn StdError + 'static),
) -> Option<Result<serde_json::Value, serde_json::Error>> {
render_with(error, |entry| entry.render_jsonrpc)
}
pub(crate) fn http_headers(
error: &(dyn StdError + 'static),
) -> Option<Vec<(http::HeaderName, http::HeaderValue)>> {
render_with(error, |entry| entry.http_headers)
}
pub fn error_metadata() -> &'static [ErrorRegistryEntry] {
&ERROR_REGISTRY
}