use std::fmt::Display; pub const GENERAL_ERROR: i32 = 1; pub const FILESYSTEM_ERROR: i32 = 2; pub const DOCKER_ERROR: i32 = 3; pub const CFG_SPEC_VIOLATION: i32 = 4; pub const CFG_RULES_VIOLATION: i32 = 5; pub const NOT_FOUND: i32 = 6; pub const INVALID_BACKUP_PASSWORD: i32 = 7; pub const VERSION_INCOMPATIBLE: i32 = 8; pub const NETWORK_ERROR: i32 = 9; pub const REGISTRY_ERROR: i32 = 10; pub const SERDE_ERROR: i32 = 11; #[derive(Debug, Fail)] #[fail(display = "{}", _0)] pub struct Error { pub failure: failure::Error, pub code: Option, } impl Error { pub fn new>(e: E, code: Option) -> Self { Error { failure: e.into(), code, } } pub fn from>(e: E) -> Self { Error { failure: e.into(), code: None, } } } impl From for Error { fn from(e: failure::Error) -> Self { Error { failure: e, code: None, } } } impl From for Error { fn from(e: std::io::Error) -> Self { Error { failure: e.into(), code: Some(2), } } } pub trait ResultExt where Self: Sized, { fn with_code(self, code: i32) -> Result; fn with_ctx (Option, D), D: Display + Send + Sync + 'static>( self, f: F, ) -> Result; fn no_code(self) -> Result; } impl ResultExt for Result where failure::Error: From, { fn with_code(self, code: i32) -> Result { #[cfg(not(feature = "production"))] assert!(code != 0); self.map_err(|e| Error { failure: e.into(), code: Some(code), }) } fn with_ctx (Option, D), D: Display + Send + Sync + 'static>( self, f: F, ) -> Result { self.map_err(|e| { let (code, ctx) = f(&e); let failure = failure::Error::from(e).context(ctx); Error { code, failure: failure.into(), } }) } fn no_code(self) -> Result { self.map_err(|e| Error { failure: e.into(), code: None, }) } } #[macro_export] macro_rules! ensure_code { ($x:expr, $c:expr, $fmt:expr $(, $arg:expr)*) => { if !($x) { return Err(crate::Error { failure: format_err!($fmt, $($arg, )*), code: Some($c), }); } }; }