use anyhow::Result; use smartstring::alias::String; pub type CmdResult = Result; const USER_ERROR_PREFIX: &str = "CVR_ERROR:"; pub fn coded_error(code: &str, detail: impl std::fmt::Display) -> String { format!("{USER_ERROR_PREFIX}{code}\n{detail}").into() } // Command modules pub mod app; pub mod backup; pub mod clash; pub mod lightweight; pub mod listener; pub mod media_unlock_checker; pub mod network; pub mod profile; pub mod proxy; pub mod runtime; pub mod save_profile; pub mod service; pub mod system; pub mod uwp; pub mod validate; pub mod verge; pub mod webdav; // Re-export all command functions for backwards compatibility pub use app::*; pub use backup::*; pub use clash::*; pub use lightweight::*; pub use listener::*; pub use media_unlock_checker::*; pub use network::*; pub use profile::*; pub use proxy::*; pub use runtime::*; pub use save_profile::*; pub use service::*; pub use system::*; pub use uwp::*; pub use validate::*; pub use verge::*; pub use webdav::*; pub trait StringifyErr { fn stringify_err(self) -> CmdResult; fn stringify_err_log(self, log_fn: F) -> CmdResult where F: Fn(&str); } pub trait WithErrorCode { fn with_error_code(self, code: &str) -> CmdResult; } impl StringifyErr for Result { fn stringify_err(self) -> CmdResult { self.map_err(|e| e.to_string().into()) } fn stringify_err_log(self, log_fn: F) -> CmdResult where F: Fn(&str), { self.map_err(|e| { let msg = String::from(e.to_string()); log_fn(&msg); msg }) } } impl WithErrorCode for Result { fn with_error_code(self, code: &str) -> CmdResult { self.map_err(|error| coded_error(code, error)) } } #[cfg(test)] mod tests { use super::coded_error; #[test] fn coded_error_preserves_stable_code_and_diagnostic_detail() { assert_eq!( coded_error("CORE_RESTART_FAILED", "connection refused"), "CVR_ERROR:CORE_RESTART_FAILED\nconnection refused" ); } }