1#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
2#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/examples/simple.rs"))]
6#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/examples/ext-traits.rs"))]
13pub mod prelude {
19 pub use crate::{GenericErrorExt as _, GenericErrorRefExt as _};
21}
22
23use extension_traits::extension;
24use std::{convert::Infallible, fmt::Display, marker::PhantomData, sync::Arc};
25
26pub type Untyped = Infallible;
29
30#[derive(serde::Serialize, serde::Deserialize)]
36pub struct GenericError<T>
37where
38 T: 'static,
39{
40 display: String,
41 debug: String,
42 source: Option<Arc<GenericError<Untyped>>>,
43 _phantom: PhantomData<T>,
44}
45
46#[extension(pub trait GenericErrorExt)]
47impl<T, E> Result<T, E>
48where
49 E: std::fmt::Display + std::fmt::Debug,
50{
51 fn make_generic(self) -> Result<T, GenericError<E>>
52 where
53 E: core::error::Error,
54 {
55 self.map_err(GenericError::from)
56 }
57
58 fn make_generic_untyped(self) -> Result<T, GenericError<Untyped>>
59 where
60 E: core::error::Error + 'static,
61 {
62 self.make_generic().map_err(GenericError::untyped)
63 }
65}
66
67#[extension(pub trait GenericErrorRefExt)]
68impl<T, E> Result<T, &E>
69where
70 E: Display + std::fmt::Debug + core::error::Error,
71{
72 fn make_generic_ref(self) -> Result<T, GenericError<E>> {
73 self.map_err(|e| GenericError::from_ref(e))
74 }
75
76 fn make_generic_ref_untyped(self) -> Result<T, GenericError<Untyped>>
77 where
78 E: 'static,
79 {
80 self.make_generic_ref().map_err(GenericError::untyped)
81 }
82}
83
84impl<T> core::error::Error for GenericError<T> {}
85
86impl<T> std::fmt::Debug for GenericError<T> {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 write!(f, "{}", self.debug)
89 }
90}
91
92impl<T> std::fmt::Display for GenericError<T> {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 write!(f, "{}", self.display)
95 }
96}
97
98impl<T> Clone for GenericError<T> {
99 fn clone(&self) -> Self {
100 GenericError {
101 display: self.display.clone(),
102 debug: self.debug.clone(),
103 source: self.source.clone(),
104 _phantom: PhantomData,
105 }
106 }
107}
108
109impl<T> GenericError<T> {
110 pub fn untyped(self) -> GenericError<Untyped> {
112 GenericError {
113 display: self.display,
114 debug: self.debug,
115 source: self.source,
116 _phantom: PhantomData,
117 }
118 }
119}
120
121impl GenericError<Untyped> {
122 fn from_dyn(err: &dyn core::error::Error) -> GenericError<Untyped> {
123 GenericError {
124 display: err.to_string(),
125 debug: format!("{:?}", err),
126 source: err
127 .source()
128 .map(|source| Arc::new(GenericError::from_dyn(source))),
129 _phantom: PhantomData,
130 }
131 }
132}
133
134impl<E> GenericError<E>
135where
136 E: std::fmt::Display + std::fmt::Debug + core::error::Error,
137{
138 pub fn from(err: E) -> GenericError<E> {
140 Self {
141 debug: format!("{:?}", err),
142 display: err.to_string(),
143 source: err
144 .source()
145 .map(|source: &dyn core::error::Error| Arc::new(GenericError::from_dyn(source).untyped())),
146 _phantom: PhantomData,
147 }
148 }
149
150 pub fn from_ref(err: &E) -> GenericError<E> {
152 Self {
153 debug: format!("{:?}", err),
154 display: err.to_string(),
155 source: err
156 .source()
157 .map(|err| Arc::new(GenericError::from_dyn(err))),
158 _phantom: PhantomData,
159 }
160 }
161}
162
163impl<E> GenericError<E>
164where
165 E: std::fmt::Display + std::fmt::Debug,
166{
167 pub fn from_non_err(err: E) -> GenericError<E> {
168 Self {
169 debug: format!("{:?}", err),
170 display: err.to_string(),
171 source: None,
172 _phantom: PhantomData,
173 }
174 }
175
176 pub fn from_non_err_ref(err: &E) -> GenericError<E> {
177 Self {
178 debug: format!("{:?}", err),
179 display: err.to_string(),
180 source: None,
181 _phantom: PhantomData,
182 }
183 }
184}