use std::time::Duration;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("factory failed: {message}")]
Factory {
message: String,
},
#[error("factory timed out after {elapsed:?}")]
FactoryTimeout {
elapsed: Duration,
},
#[error("lock acquisition timed out after {elapsed:?}")]
LockTimeout {
elapsed: Duration,
},
#[error("serialization failed: {0}")]
Serialization(String),
#[error("deserialization failed: {0}")]
Deserialization(String),
#[error("distributed cache error: {0}")]
Distributed(String),
#[error("backplane error: {0}")]
Backplane(String),
}
#[derive(Debug, thiserror::Error)]
#[error("{message}")]
pub struct FactoryError {
message: String,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync>>,
}
impl FactoryError {
#[must_use]
pub fn new(message: impl Into<String>) -> Self {
Self {
message: into_nonblank(message.into()),
source: None,
}
}
#[must_use]
pub fn from_source<E>(source: E) -> Self
where
E: std::error::Error + Send + Sync + 'static,
{
Self {
message: source.to_string(),
source: Some(Box::new(source)),
}
}
#[must_use]
pub fn message(&self) -> &str {
&self.message
}
}
fn into_nonblank(message: String) -> String {
if message.trim().is_empty() {
"an error occurred while running the factory".to_owned()
} else {
message
}
}
impl From<FactoryError> for Error {
fn from(err: FactoryError) -> Self {
Error::Factory {
message: err.message,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn blank_factory_message_is_defaulted() {
assert_eq!(
FactoryError::new(" ").message(),
"an error occurred while running the factory"
);
}
#[test]
fn factory_error_preserves_source() {
let io = std::io::Error::other("boom");
let err = FactoryError::from_source(io);
assert_eq!(err.message(), "boom");
assert!(std::error::Error::source(&err).is_some());
}
}