use crate::retry::{ErrorKind, ProvideErrorKind};
use std::collections::HashMap;
use std::fmt;
pub trait ProvideErrorMetadata {
fn meta(&self) -> &ErrorMetadata;
fn code(&self) -> Option<&str> {
self.meta().code()
}
fn message(&self) -> Option<&str> {
self.meta().message()
}
}
pub const EMPTY_ERROR_METADATA: ErrorMetadata = ErrorMetadata {
code: None,
message: None,
extras: None,
};
#[derive(Debug, Eq, PartialEq, Default, Clone)]
pub struct ErrorMetadata {
code: Option<String>,
message: Option<String>,
extras: Option<HashMap<&'static str, String>>,
}
impl ProvideErrorMetadata for ErrorMetadata {
fn meta(&self) -> &ErrorMetadata {
self
}
}
#[derive(Debug, Default)]
pub struct Builder {
inner: ErrorMetadata,
}
impl Builder {
pub fn message(mut self, message: impl Into<String>) -> Self {
self.inner.message = Some(message.into());
self
}
pub fn code(mut self, code: impl Into<String>) -> Self {
self.inner.code = Some(code.into());
self
}
pub fn custom(mut self, key: &'static str, value: impl Into<String>) -> Self {
if self.inner.extras.is_none() {
self.inner.extras = Some(HashMap::new());
}
self.inner
.extras
.as_mut()
.unwrap()
.insert(key, value.into());
self
}
pub fn build(self) -> ErrorMetadata {
self.inner
}
}
impl ErrorMetadata {
pub fn code(&self) -> Option<&str> {
self.code.as_deref()
}
pub fn message(&self) -> Option<&str> {
self.message.as_deref()
}
pub fn extra(&self, key: &'static str) -> Option<&str> {
self.extras
.as_ref()
.and_then(|extras| extras.get(key).map(|k| k.as_str()))
}
pub fn builder() -> Builder {
Builder::default()
}
pub fn into_builder(self) -> Builder {
Builder { inner: self }
}
}
impl ProvideErrorKind for ErrorMetadata {
fn retryable_error_kind(&self) -> Option<ErrorKind> {
None
}
fn code(&self) -> Option<&str> {
ErrorMetadata::code(self)
}
}
impl fmt::Display for ErrorMetadata {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut fmt = f.debug_struct("Error");
if let Some(code) = &self.code {
fmt.field("code", code);
}
if let Some(message) = &self.message {
fmt.field("message", message);
}
if let Some(extras) = &self.extras {
for (k, v) in extras {
fmt.field(k, &v);
}
}
fmt.finish()
}
}
impl std::error::Error for ErrorMetadata {}