@@ -71,45 +71,91 @@ impl From<ApiError> for PyErr {
71
71
}
72
72
}
73
73
74
+ pub struct ResidualErrorData {
75
+ message : String ,
76
+ debug : String ,
77
+ }
78
+
74
79
#[ derive( Clone ) ]
75
- pub struct SharedError {
76
- pub err : Arc < anyhow:: Error > ,
80
+ pub struct ResidualError ( Arc < ResidualErrorData > ) ;
81
+
82
+ impl Display for ResidualError {
83
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
84
+ write ! ( f, "{}" , self . 0 . message)
85
+ }
86
+ }
87
+
88
+ impl Debug for ResidualError {
89
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
90
+ write ! ( f, "{}" , self . 0 . debug)
91
+ }
92
+ }
93
+
94
+ impl Error for ResidualError { }
95
+
96
+ enum SharedErrorState {
97
+ Anyhow ( anyhow:: Error ) ,
98
+ ResidualErrorMessage ( ResidualError ) ,
77
99
}
78
100
101
+ /// SharedError allows to be cloned.
102
+ /// The original `anyhow::Error` can be extracted once, and later it decays to `ResidualError` which preserves the message and debug information.
103
+ #[ derive( Clone ) ]
104
+ pub struct SharedError ( Arc < Mutex < SharedErrorState > > ) ;
105
+
79
106
impl SharedError {
80
107
pub fn new ( err : anyhow:: Error ) -> Self {
81
- Self { err : Arc :: new ( err) }
108
+ Self ( Arc :: new ( Mutex :: new ( SharedErrorState :: Anyhow ( err) ) ) )
109
+ }
110
+
111
+ fn extract_anyhow_error ( & self ) -> anyhow:: Error {
112
+ let mut state = self . 0 . lock ( ) . unwrap ( ) ;
113
+ let mut_state = & mut * state;
114
+
115
+ let residual_err = match mut_state {
116
+ SharedErrorState :: ResidualErrorMessage ( err) => {
117
+ return anyhow:: Error :: from ( err. clone ( ) ) ;
118
+ }
119
+ SharedErrorState :: Anyhow ( err) => ResidualError ( Arc :: new ( ResidualErrorData {
120
+ message : format ! ( "{}" , err) ,
121
+ debug : format ! ( "{:?}" , err) ,
122
+ } ) ) ,
123
+ } ;
124
+ let orig_state = std:: mem:: replace (
125
+ mut_state,
126
+ SharedErrorState :: ResidualErrorMessage ( residual_err) ,
127
+ ) ;
128
+ let SharedErrorState :: Anyhow ( err) = orig_state else {
129
+ panic ! ( "Expected anyhow error" ) ;
130
+ } ;
131
+ err
82
132
}
83
133
}
84
134
impl Debug for SharedError {
85
135
fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
86
- Debug :: fmt ( & self . err , f)
136
+ let state = self . 0 . lock ( ) . unwrap ( ) ;
137
+ match & * state {
138
+ SharedErrorState :: Anyhow ( err) => Debug :: fmt ( err, f) ,
139
+ SharedErrorState :: ResidualErrorMessage ( err) => Debug :: fmt ( err, f) ,
140
+ }
87
141
}
88
142
}
89
143
90
144
impl Display for SharedError {
91
145
fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
92
- Display :: fmt ( & self . err , f)
146
+ let state = self . 0 . lock ( ) . unwrap ( ) ;
147
+ match & * state {
148
+ SharedErrorState :: Anyhow ( err) => Display :: fmt ( err, f) ,
149
+ SharedErrorState :: ResidualErrorMessage ( err) => Display :: fmt ( err, f) ,
150
+ }
93
151
}
94
152
}
95
153
96
154
impl < E : std:: error:: Error + Send + Sync + ' static > From < E > for SharedError {
97
155
fn from ( err : E ) -> Self {
98
- Self {
99
- err : Arc :: new ( anyhow:: Error :: from ( err) ) ,
100
- }
101
- }
102
- }
103
-
104
- impl AsRef < dyn std:: error:: Error > for SharedError {
105
- fn as_ref ( & self ) -> & ( dyn std:: error:: Error + ' static ) {
106
- self . err . as_ref ( ) . as_ref ( )
107
- }
108
- }
109
-
110
- impl AsRef < dyn std:: error:: Error + Send + Sync > for SharedError {
111
- fn as_ref ( & self ) -> & ( dyn std:: error:: Error + Send + Sync + ' static ) {
112
- self . err . as_ref ( ) . as_ref ( )
156
+ Self ( Arc :: new ( Mutex :: new ( SharedErrorState :: Anyhow (
157
+ anyhow:: Error :: from ( err) ,
158
+ ) ) ) )
113
159
}
114
160
}
115
161
@@ -119,48 +165,28 @@ pub fn shared_ok<T>(value: T) -> Result<T, SharedError> {
119
165
120
166
pub type SharedResult < T > = Result < T , SharedError > ;
121
167
122
- pub struct SharedErrorWrapper ( SharedError ) ;
123
-
124
- impl Display for SharedErrorWrapper {
125
- fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
126
- Display :: fmt ( & self . 0 , f)
127
- }
128
- }
129
-
130
- impl Debug for SharedErrorWrapper {
131
- fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
132
- Debug :: fmt ( & self . 0 , f)
133
- }
134
- }
135
-
136
- impl Error for SharedErrorWrapper {
137
- fn source ( & self ) -> Option < & ( dyn Error + ' static ) > {
138
- self . 0 . err . as_ref ( ) . source ( )
139
- }
140
- }
141
-
142
168
pub trait SharedResultExt < T > {
143
- fn std_result ( self ) -> Result < T , SharedErrorWrapper > ;
169
+ fn anyhow_result ( self ) -> Result < T , anyhow :: Error > ;
144
170
}
145
171
146
172
impl < T > SharedResultExt < T > for Result < T , SharedError > {
147
- fn std_result ( self ) -> Result < T , SharedErrorWrapper > {
173
+ fn anyhow_result ( self ) -> Result < T , anyhow :: Error > {
148
174
match self {
149
175
Ok ( value) => Ok ( value) ,
150
- Err ( err) => Err ( SharedErrorWrapper ( err) ) ,
176
+ Err ( err) => Err ( err. extract_anyhow_error ( ) ) ,
151
177
}
152
178
}
153
179
}
154
180
155
181
pub trait SharedResultExtRef < ' a , T > {
156
- fn std_result ( self ) -> Result < & ' a T , SharedErrorWrapper > ;
182
+ fn anyhow_result ( self ) -> Result < & ' a T , anyhow :: Error > ;
157
183
}
158
184
159
185
impl < ' a , T > SharedResultExtRef < ' a , T > for & ' a Result < T , SharedError > {
160
- fn std_result ( self ) -> Result < & ' a T , SharedErrorWrapper > {
186
+ fn anyhow_result ( self ) -> Result < & ' a T , anyhow :: Error > {
161
187
match self {
162
188
Ok ( value) => Ok ( value) ,
163
- Err ( err) => Err ( SharedErrorWrapper ( err. clone ( ) ) ) ,
189
+ Err ( err) => Err ( err. extract_anyhow_error ( ) ) ,
164
190
}
165
191
}
166
192
}
0 commit comments