use std::error;
use std::fmt;
struct Source {
prefix: Option<String>,
source: Box<dyn error::Error>,
}
pub struct InternalError {
message: Option<String>,
source: Option<Source>,
}
impl InternalError {
pub fn from_source(source: Box<dyn error::Error>) -> Self {
Self {
message: None,
source: Some(Source {
prefix: None,
source,
}),
}
}
pub fn from_source_with_message(source: Box<dyn error::Error>, message: String) -> Self {
Self {
message: Some(message),
source: Some(Source {
prefix: None,
source,
}),
}
}
pub fn from_source_with_prefix(source: Box<dyn error::Error>, prefix: String) -> Self {
Self {
message: None,
source: Some(Source {
prefix: Some(prefix),
source,
}),
}
}
pub fn with_message(message: String) -> Self {
Self {
message: Some(message),
source: None,
}
}
pub fn reduce_to_string(self) -> String {
if self.source.is_some() {
debug!("{:?}", self);
}
self.to_string()
}
}
impl error::Error for InternalError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
self.source.as_ref().map(|s| s.source.as_ref())
}
}
impl fmt::Display for InternalError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.message {
Some(m) => write!(f, "{}", m),
None => match &self.source {
Some(s) => match &s.prefix {
Some(p) => write!(f, "{}: {}", p, s.source),
None => write!(f, "{}", s.source),
},
None => write!(f, "{}", std::any::type_name::<InternalError>()),
},
}
}
}
impl fmt::Debug for InternalError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut debug_struct = f.debug_struct("InternalError");
if let Some(message) = &self.message {
debug_struct.field("message", message);
}
if let Some(source) = &self.source {
if let Some(prefix) = &source.prefix {
debug_struct.field("prefix", prefix);
}
debug_struct.field("source", &source.source);
}
debug_struct.finish()
}
}
#[cfg(any(feature = "diesel"))]
impl From<diesel::result::Error> for InternalError {
fn from(err: diesel::result::Error) -> Self {
Self::from_source(Box::new(err))
}
}
#[cfg(test)]
pub mod tests {
use super::*;
#[test]
fn test_debug_from_source() {
let msg = "test message";
let debug = "InternalError { source: InternalError { message: \"test message\" } }";
let err =
InternalError::from_source(Box::new(InternalError::with_message(msg.to_string())));
assert_eq!(format!("{:?}", err), debug);
}
#[test]
fn test_debug_from_source_with_message() {
let msg = "test message";
let debug = "InternalError { message: \"test message\", source: InternalError { message: \"unused\" } }";
let err = InternalError::from_source_with_message(
Box::new(InternalError::with_message("unused".to_string())),
msg.to_string(),
);
assert_eq!(format!("{:?}", err), debug);
}
#[test]
fn test_debug_from_source_with_prefix() {
let prefix = "test prefix";
let msg = "test message";
let debug = "InternalError { prefix: \"test prefix\", source: InternalError { message: \"test message\" } }";
let err = InternalError::from_source_with_prefix(
Box::new(InternalError::with_message(msg.to_string())),
prefix.to_string(),
);
assert_eq!(format!("{:?}", err), debug);
}
#[test]
fn test_debug_with_message() {
let msg = "test message";
let debug = "InternalError { message: \"test message\" }";
let err = InternalError::with_message(msg.to_string());
assert_eq!(format!("{:?}", err), debug);
}
#[test]
fn test_display_from_source() {
let msg = "test message";
let err =
InternalError::from_source(Box::new(InternalError::with_message(msg.to_string())));
assert_eq!(format!("{}", err), msg);
}
#[test]
fn test_display_from_source_with_message() {
let msg = "test message";
let err = InternalError::from_source_with_message(
Box::new(InternalError::with_message("unused".to_string())),
msg.to_string(),
);
assert_eq!(format!("{}", err), msg);
}
#[test]
fn test_display_from_source_with_prefix() {
let prefix = "test prefix";
let msg = "test message";
let err = InternalError::from_source_with_prefix(
Box::new(InternalError::with_message(msg.to_string())),
prefix.to_string(),
);
assert_eq!(format!("{}", err), format!("{}: {}", prefix, msg));
}
#[test]
fn test_display_with_message() {
let msg = "test message";
let err = InternalError::with_message(msg.to_string());
assert_eq!(format!("{}", err), msg);
}
}