@@ -70,6 +70,22 @@ pub enum EnvisionError {
7070 /// Details about the subscription failure.
7171 detail : String ,
7272 } ,
73+
74+ /// A catch-all variant for wrapping arbitrary errors.
75+ ///
76+ /// Use this when an error does not fit into the other structured
77+ /// categories. It wraps any error that implements
78+ /// `std::error::Error + Send + Sync + 'static`.
79+ ///
80+ /// # Example
81+ ///
82+ /// ```rust
83+ /// use envision::error::EnvisionError;
84+ ///
85+ /// let err = EnvisionError::other("something went wrong");
86+ /// assert_eq!(err.to_string(), "other error: something went wrong");
87+ /// ```
88+ Other ( BoxedError ) ,
7389}
7490
7591impl EnvisionError {
@@ -132,6 +148,29 @@ impl EnvisionError {
132148 detail : detail. into ( ) ,
133149 }
134150 }
151+
152+ /// Creates an `Other` error from any error type.
153+ ///
154+ /// This is a convenience constructor that wraps an arbitrary error
155+ /// into the [`Other`](EnvisionError::Other) variant, avoiding the
156+ /// need for manual `.map_err()` calls.
157+ ///
158+ /// # Example
159+ ///
160+ /// ```rust
161+ /// use envision::error::EnvisionError;
162+ ///
163+ /// let err = EnvisionError::other("something went wrong");
164+ /// assert_eq!(err.to_string(), "other error: something went wrong");
165+ ///
166+ /// // Works with any error type
167+ /// let io_err = std::io::Error::other("disk full");
168+ /// let err = EnvisionError::other(io_err);
169+ /// assert!(err.to_string().contains("disk full"));
170+ /// ```
171+ pub fn other ( err : impl Into < BoxedError > ) -> Self {
172+ EnvisionError :: Other ( err. into ( ) )
173+ }
135174}
136175
137176impl fmt:: Display for EnvisionError {
@@ -154,6 +193,7 @@ impl fmt::Display for EnvisionError {
154193 subscription_type, detail
155194 )
156195 }
196+ EnvisionError :: Other ( err) => write ! ( f, "other error: {}" , err) ,
157197 }
158198 }
159199}
@@ -162,6 +202,7 @@ impl std::error::Error for EnvisionError {
162202 fn source ( & self ) -> Option < & ( dyn std:: error:: Error + ' static ) > {
163203 match self {
164204 EnvisionError :: Io ( err) => Some ( err) ,
205+ EnvisionError :: Other ( err) => Some ( err. as_ref ( ) ) ,
165206 EnvisionError :: Render { .. }
166207 | EnvisionError :: Config { .. }
167208 | EnvisionError :: Subscription { .. } => None ,
@@ -316,4 +357,58 @@ mod tests {
316357 _ => panic ! ( "expected Subscription variant" ) ,
317358 }
318359 }
360+
361+ #[ test]
362+ fn other_from_string_error ( ) {
363+ let err = EnvisionError :: Other ( "something went wrong" . into ( ) ) ;
364+ assert ! ( matches!( err, EnvisionError :: Other ( _) ) ) ;
365+ }
366+
367+ #[ test]
368+ fn other_from_custom_error_type ( ) {
369+ #[ derive( Debug ) ]
370+ struct CustomError ;
371+
372+ impl fmt:: Display for CustomError {
373+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
374+ write ! ( f, "custom error occurred" )
375+ }
376+ }
377+
378+ impl std:: error:: Error for CustomError { }
379+
380+ let err = EnvisionError :: Other ( Box :: new ( CustomError ) ) ;
381+ assert ! ( matches!( err, EnvisionError :: Other ( _) ) ) ;
382+ assert_eq ! ( err. to_string( ) , "other error: custom error occurred" ) ;
383+ }
384+
385+ #[ test]
386+ fn other_error_display ( ) {
387+ let err = EnvisionError :: Other ( "unexpected failure" . into ( ) ) ;
388+ assert_eq ! ( err. to_string( ) , "other error: unexpected failure" ) ;
389+ }
390+
391+ #[ test]
392+ fn other_error_source ( ) {
393+ let io_err = std:: io:: Error :: other ( "inner error" ) ;
394+ let err = EnvisionError :: Other ( Box :: new ( io_err) ) ;
395+ let source = std:: error:: Error :: source ( & err) ;
396+ assert ! ( source. is_some( ) ) ;
397+ assert_eq ! ( source. unwrap( ) . to_string( ) , "inner error" ) ;
398+ }
399+
400+ #[ test]
401+ fn other_convenience_constructor ( ) {
402+ let err = EnvisionError :: other ( "convenience test" ) ;
403+ assert ! ( matches!( err, EnvisionError :: Other ( _) ) ) ;
404+ assert_eq ! ( err. to_string( ) , "other error: convenience test" ) ;
405+ }
406+
407+ #[ test]
408+ fn other_convenience_constructor_with_io_error ( ) {
409+ let io_err = std:: io:: Error :: other ( "disk full" ) ;
410+ let err = EnvisionError :: other ( io_err) ;
411+ assert ! ( matches!( err, EnvisionError :: Other ( _) ) ) ;
412+ assert ! ( err. to_string( ) . contains( "disk full" ) ) ;
413+ }
319414}
0 commit comments