1use std::sync::Arc;
4
5#[derive(Clone, Default)]
7pub struct DynInnerError(
8 pub Option<Arc<dyn std::error::Error + 'static + Send + Sync>>,
9);
10
11impl std::fmt::Debug for DynInnerError {
12 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13 self.0.fmt(f)
14 }
15}
16
17impl std::fmt::Display for DynInnerError {
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 match self.0.as_ref() {
20 None => f.write_str("None"),
21 Some(s) => s.fmt(f),
22 }
23 }
24}
25
26impl std::error::Error for DynInnerError {
27 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
28 self.0.as_ref().map(|s| {
29 let out: &(dyn std::error::Error + 'static) = &**s;
30 out
31 })
32 }
33}
34
35impl DynInnerError {
36 pub fn new<E: std::error::Error + 'static + Send + Sync>(e: E) -> Self {
38 Self(Some(Arc::new(e)))
39 }
40}
41
42#[derive(Debug, Clone, thiserror::Error)]
48pub enum K2Error {
49 #[error("{ctx} (src: {src})")]
51 Other {
52 ctx: Arc<str>,
54
55 #[source]
57 src: DynInnerError,
58 },
59}
60
61impl K2Error {
62 pub fn other_src<
64 C: std::fmt::Display,
65 S: std::error::Error + 'static + Send + Sync,
66 >(
67 ctx: C,
68 src: S,
69 ) -> Self {
70 Self::Other {
71 ctx: ctx.to_string().into_boxed_str().into(),
72 src: DynInnerError::new(src),
73 }
74 }
75
76 pub fn other<C: std::fmt::Display>(ctx: C) -> Self {
78 Self::Other {
79 ctx: ctx.to_string().into_boxed_str().into(),
80 src: DynInnerError::default(),
81 }
82 }
83}
84
85pub type K2Result<T> = Result<T, K2Error>;
87
88#[cfg(test)]
89mod test {
90 use super::*;
91
92 #[test]
93 fn error_display() {
94 assert_eq!(
95 "bla (src: None)",
96 K2Error::other("bla").to_string().as_str(),
97 );
98 assert_eq!(
99 "bla (src: None)",
100 K2Error::other("bla".to_string()).to_string().as_str(),
101 );
102 assert_eq!(
103 "foo (src: bar)",
104 K2Error::other_src("foo", std::io::Error::other("bar"))
105 .to_string()
106 .as_str(),
107 );
108 }
109
110 #[test]
111 fn error_debug() {
112 assert_eq!(
113 "Other { ctx: \"bla\", src: None }",
114 format!("{:?}", K2Error::other("bla")).as_str(),
115 );
116 assert_eq!(
117 "Other { ctx: \"foo\", src: Some(Custom { kind: Other, error: \"bar\" }) }",
118 format!(
119 "{:?}",
120 K2Error::other_src("foo", std::io::Error::other("bar"))
121 )
122 .as_str(),
123 );
124 }
125
126 #[test]
127 fn ensure_k2error_type_is_send_and_sync() {
128 fn ensure<T: std::fmt::Display + Send + Sync>(_t: T) {}
129 ensure(K2Error::other("bla"));
130 }
131}