use crate::metadata::{ErrorMetadata, FormatConfig};
use std::any::TypeId;
use std::error::Error as StdError;
pub type JsonRenderFn = fn(
&(dyn StdError + 'static),
FormatConfig,
) -> Option<Result<serde_json::Value, serde_json::Error>>;
pub type HtmlRenderFn = fn(&(dyn StdError + 'static), FormatConfig) -> Option<String>;
pub type GraphqlRenderFn = fn(
&(dyn StdError + 'static),
FormatConfig,
) -> Option<Result<serde_json::Value, serde_json::Error>>;
pub type TextRenderFn = fn(&(dyn StdError + 'static), FormatConfig) -> Option<String>;
pub type HttpStatusFn = fn(&(dyn StdError + 'static)) -> Option<http::StatusCode>;
pub type JsonRpcRenderFn = fn(
&(dyn StdError + 'static),
FormatConfig,
) -> 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_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: impl Fn(&ErrorRegistryEntry) -> Option<T>) -> Option<T> {
for entry in ERROR_REGISTRY {
if let Some(result) = f(entry) {
return Some(result);
}
}
None
}
pub(crate) fn render_json(
error: &(dyn StdError + 'static),
config: FormatConfig,
) -> Option<Result<serde_json::Value, serde_json::Error>> {
render_with(|entry| (entry.render_json)(error, config))
}
pub(crate) fn render_html(
error: &(dyn StdError + 'static),
config: FormatConfig,
) -> Option<String> {
render_with(|entry| (entry.render_html)(error, config))
}
pub(crate) fn render_graphql(
error: &(dyn StdError + 'static),
config: FormatConfig,
) -> Option<Result<serde_json::Value, serde_json::Error>> {
render_with(|entry| (entry.render_graphql)(error, config))
}
pub(crate) fn render_text(
error: &(dyn StdError + 'static),
config: FormatConfig,
) -> Option<String> {
render_with(|entry| (entry.render_text)(error, config))
}
pub(crate) fn http_status(error: &(dyn StdError + 'static)) -> Option<http::StatusCode> {
render_with(|entry| (entry.http_status)(error))
}
pub(crate) fn render_jsonrpc(
error: &(dyn StdError + 'static),
config: FormatConfig,
) -> Option<Result<serde_json::Value, serde_json::Error>> {
render_with(|entry| (entry.render_jsonrpc)(error, config))
}
pub(crate) fn http_headers(
error: &(dyn StdError + 'static),
) -> Option<Vec<(http::HeaderName, http::HeaderValue)>> {
render_with(|entry| (entry.http_headers)(error))
}
pub fn error_metadata() -> &'static [ErrorRegistryEntry] {
&ERROR_REGISTRY
}