use std::sync::Arc;
#[derive(Clone, Default)]
pub struct DynInnerError(
pub Option<Arc<dyn std::error::Error + 'static + Send + Sync>>,
);
impl std::fmt::Debug for DynInnerError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl std::fmt::Display for DynInnerError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0.as_ref() {
None => f.write_str("None"),
Some(s) => s.fmt(f),
}
}
}
impl std::error::Error for DynInnerError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.0.as_ref().map(|s| {
let out: &(dyn std::error::Error + 'static) = &**s;
out
})
}
}
impl DynInnerError {
pub fn new<E: std::error::Error + 'static + Send + Sync>(e: E) -> Self {
Self(Some(Arc::new(e)))
}
}
#[derive(Debug, Clone, thiserror::Error)]
pub enum K2Error {
#[error("{ctx} (src: {src})")]
Other {
ctx: Arc<str>,
#[source]
src: DynInnerError,
},
#[error("No local agent has joined a space during preflight")]
NoLocalAgentsDuringPreflight,
}
impl K2Error {
pub fn other_src<
C: std::fmt::Display,
S: std::error::Error + 'static + Send + Sync,
>(
ctx: C,
src: S,
) -> Self {
Self::Other {
ctx: ctx.to_string().into_boxed_str().into(),
src: DynInnerError::new(src),
}
}
pub fn other<C: std::fmt::Display>(ctx: C) -> Self {
Self::Other {
ctx: ctx.to_string().into_boxed_str().into(),
src: DynInnerError::default(),
}
}
}
pub type K2Result<T> = Result<T, K2Error>;
#[cfg(test)]
mod test {
use super::*;
#[test]
fn error_display() {
assert_eq!(
"bla (src: None)",
K2Error::other("bla").to_string().as_str(),
);
assert_eq!(
"bla (src: None)",
K2Error::other("bla".to_string()).to_string().as_str(),
);
assert_eq!(
"foo (src: bar)",
K2Error::other_src("foo", std::io::Error::other("bar"))
.to_string()
.as_str(),
);
}
#[test]
fn error_debug() {
assert_eq!(
"Other { ctx: \"bla\", src: None }",
format!("{:?}", K2Error::other("bla")).as_str(),
);
assert_eq!(
"Other { ctx: \"foo\", src: Some(Custom { kind: Other, error: \"bar\" }) }",
format!(
"{:?}",
K2Error::other_src("foo", std::io::Error::other("bar"))
)
.as_str(),
);
}
#[test]
fn ensure_k2error_type_is_send_and_sync() {
fn ensure<T: std::fmt::Display + Send + Sync>(_t: T) {}
ensure(K2Error::other("bla"));
}
}