diff --git a/src/uu/chown/src/chown.rs b/src/uu/chown/src/chown.rs index 53cf61e83..7df263c5d 100644 --- a/src/uu/chown/src/chown.rs +++ b/src/uu/chown/src/chown.rs @@ -14,7 +14,7 @@ use uucore::fs::resolve_relative_path; use uucore::libc::{gid_t, uid_t}; use uucore::perms::{wrap_chown, Verbosity}; -use uucore::error::{FromIo, UError, UResult, USimpleError}; +use uucore::error::{FromIo, UResult, USimpleError}; use clap::{crate_version, App, Arg}; @@ -107,10 +107,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if recursive { if bit_flag == FTS_PHYSICAL { if derefer == 1 { - return Err(USimpleError::new( - 1, - "-R --dereference requires -H or -L".to_string(), - )); + return Err(USimpleError::new(1, "-R --dereference requires -H or -L")); } derefer = 0; } @@ -324,7 +321,7 @@ impl Chowner { ret |= self.traverse(f); } if ret != 0 { - return Err(UError::from(ret)); + return Err(ret.into()); } Ok(()) } diff --git a/src/uu/df/src/df.rs b/src/uu/df/src/df.rs index baa5fe292..cdfdf0b2d 100644 --- a/src/uu/df/src/df.rs +++ b/src/uu/df/src/df.rs @@ -8,7 +8,7 @@ #[macro_use] extern crate uucore; -use uucore::error::UCustomError; +use uucore::error::UError; use uucore::error::UResult; #[cfg(unix)] use uucore::fsext::statfs_fn; @@ -274,7 +274,7 @@ impl Display for DfError { impl Error for DfError {} -impl UCustomError for DfError { +impl UError for DfError { fn code(&self) -> i32 { match self { DfError::InvalidBaseValue(_) => 1, diff --git a/src/uu/dirname/src/dirname.rs b/src/uu/dirname/src/dirname.rs index 63ee57272..e7dcc2195 100644 --- a/src/uu/dirname/src/dirname.rs +++ b/src/uu/dirname/src/dirname.rs @@ -79,7 +79,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { print!("{}", separator); } } else { - return Err(UUsageError::new(1, "missing operand".to_string())); + return Err(UUsageError::new(1, "missing operand")); } Ok(()) diff --git a/src/uu/du/src/du.rs b/src/uu/du/src/du.rs index 9c05eb982..d85cc941c 100644 --- a/src/uu/du/src/du.rs +++ b/src/uu/du/src/du.rs @@ -32,7 +32,7 @@ use std::path::PathBuf; use std::str::FromStr; use std::time::{Duration, UNIX_EPOCH}; use std::{error::Error, fmt::Display}; -use uucore::error::{UCustomError, UResult}; +use uucore::error::{UError, UResult}; use uucore::parse_size::{parse_size, ParseSizeError}; use uucore::InvalidEncodingHandling; #[cfg(windows)] @@ -438,7 +438,7 @@ Try '{} --help' for more information.", impl Error for DuError {} -impl UCustomError for DuError { +impl UError for DuError { fn code(&self) -> i32 { match self { Self::InvalidMaxDepthArg(_) => 1, diff --git a/src/uu/false/src/false.rs b/src/uu/false/src/false.rs index 2d64c8376..170788898 100644 --- a/src/uu/false/src/false.rs +++ b/src/uu/false/src/false.rs @@ -9,13 +9,12 @@ extern crate uucore; use clap::App; -use uucore::error::{UError, UResult}; -use uucore::executable; +use uucore::{error::UResult, executable}; #[uucore_procs::gen_uumain] pub fn uumain(args: impl uucore::Args) -> UResult<()> { uu_app().get_matches_from(args); - Err(UError::from(1)) + Err(1.into()) } pub fn uu_app() -> App<'static, 'static> { diff --git a/src/uu/id/src/id.rs b/src/uu/id/src/id.rs index 61684c829..16c665273 100644 --- a/src/uu/id/src/id.rs +++ b/src/uu/id/src/id.rs @@ -171,20 +171,20 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if (state.nflag || state.rflag) && default_format && !state.cflag { return Err(USimpleError::new( 1, - "cannot print only names or real IDs in default format".to_string(), + "cannot print only names or real IDs in default format", )); } if state.zflag && default_format && !state.cflag { // NOTE: GNU test suite "id/zero.sh" needs this stderr output: return Err(USimpleError::new( 1, - "option --zero not permitted in default format".to_string(), + "option --zero not permitted in default format", )); } if state.user_specified && state.cflag { return Err(USimpleError::new( 1, - "cannot print security context when user specified".to_string(), + "cannot print security context when user specified", )); } @@ -218,7 +218,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } else { return Err(USimpleError::new( 1, - "--context (-Z) works only on an SELinux-enabled kernel".to_string(), + "--context (-Z) works only on an SELinux-enabled kernel", )); } } diff --git a/src/uu/install/src/install.rs b/src/uu/install/src/install.rs index df273405f..cbbe9c18b 100644 --- a/src/uu/install/src/install.rs +++ b/src/uu/install/src/install.rs @@ -17,7 +17,7 @@ use file_diff::diff; use filetime::{set_file_times, FileTime}; use uucore::backup_control::{self, BackupMode}; use uucore::entries::{grp2gid, usr2uid}; -use uucore::error::{FromIo, UCustomError, UIoError, UResult, USimpleError}; +use uucore::error::{FromIo, UError, UIoError, UResult, USimpleError}; use uucore::perms::{wrap_chgrp, wrap_chown, Verbosity}; use libc::{getegid, geteuid}; @@ -66,7 +66,7 @@ enum InstallError { OmittingDirectory(PathBuf), } -impl UCustomError for InstallError { +impl UError for InstallError { fn code(&self) -> i32 { match self { InstallError::Unimplemented(_) => 2, diff --git a/src/uu/ln/src/ln.rs b/src/uu/ln/src/ln.rs index 65bdcf36c..7010ff5e4 100644 --- a/src/uu/ln/src/ln.rs +++ b/src/uu/ln/src/ln.rs @@ -11,7 +11,7 @@ extern crate uucore; use clap::{crate_version, App, Arg}; -use uucore::error::{UCustomError, UResult}; +use uucore::error::{UError, UResult}; use std::borrow::Cow; use std::error::Error; @@ -79,7 +79,7 @@ impl Display for LnError { impl Error for LnError {} -impl UCustomError for LnError { +impl UError for LnError { fn code(&self) -> i32 { match self { Self::TargetIsDirectory(_) => 1, diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 5c58bac7c..450acf8cd 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -39,7 +39,7 @@ use std::{ time::Duration, }; use term_grid::{Cell, Direction, Filling, Grid, GridOptions}; -use uucore::error::{set_exit_code, FromIo, UCustomError, UResult}; +use uucore::error::{set_exit_code, FromIo, UError, UResult}; use unicode_width::UnicodeWidthStr; #[cfg(unix)] @@ -135,7 +135,7 @@ enum LsError { NoMetadata(PathBuf), } -impl UCustomError for LsError { +impl UError for LsError { fn code(&self) -> i32 { match self { LsError::InvalidLineWidth(_) => 2, diff --git a/src/uu/mktemp/src/mktemp.rs b/src/uu/mktemp/src/mktemp.rs index 8a4b472aa..e1dd604a0 100644 --- a/src/uu/mktemp/src/mktemp.rs +++ b/src/uu/mktemp/src/mktemp.rs @@ -12,7 +12,7 @@ extern crate uucore; use clap::{crate_version, App, Arg}; -use uucore::error::{FromIo, UCustomError, UResult}; +use uucore::error::{FromIo, UError, UResult}; use std::env; use std::error::Error; @@ -49,7 +49,7 @@ enum MkTempError { InvalidTemplate(String), } -impl UCustomError for MkTempError {} +impl UError for MkTempError {} impl Error for MkTempError {} diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index ae869ba49..e0b445782 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -45,7 +45,7 @@ use std::path::Path; use std::path::PathBuf; use std::str::Utf8Error; use unicode_width::UnicodeWidthStr; -use uucore::error::{set_exit_code, UCustomError, UResult, USimpleError, UUsageError}; +use uucore::error::{set_exit_code, UError, UResult, USimpleError, UUsageError}; use uucore::parse_size::{parse_size, ParseSizeError}; use uucore::version_cmp::version_cmp; use uucore::InvalidEncodingHandling; @@ -164,7 +164,7 @@ enum SortError { impl Error for SortError {} -impl UCustomError for SortError { +impl UError for SortError { fn code(&self) -> i32 { match self { SortError::Disorder { .. } => 1, @@ -1238,7 +1238,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if separator.len() != 1 { return Err(UUsageError::new( 2, - "separator must be exactly one character long".into(), + "separator must be exactly one character long", )); } settings.separator = Some(separator.chars().next().unwrap()) @@ -1517,7 +1517,7 @@ fn exec( file_merger.write_all(settings, output) } else if settings.check { if files.len() > 1 { - Err(UUsageError::new(2, "only one file allowed with -c".into())) + Err(UUsageError::new(2, "only one file allowed with -c")) } else { check::check(files.first().unwrap(), settings) } diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index dd2b05d0e..49efa676a 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -17,7 +17,7 @@ use clap::{crate_version, App, Arg, ArgGroup}; use filetime::*; use std::fs::{self, File}; use std::path::Path; -use uucore::error::{FromIo, UResult, USimpleError}; +use uucore::error::{FromIo, UError, UResult, USimpleError}; static ABOUT: &str = "Update the access and modification times of each FILE to the current time."; pub mod options { diff --git a/src/uucore/src/lib/mods/error.rs b/src/uucore/src/lib/mods/error.rs index c6120672f..664fc9841 100644 --- a/src/uucore/src/lib/mods/error.rs +++ b/src/uucore/src/lib/mods/error.rs @@ -6,11 +6,11 @@ //! This module provides types to reconcile these exit codes with idiomatic Rust error //! handling. This has a couple advantages over manually using [`std::process::exit`]: //! 1. It enables the use of `?`, `map_err`, `unwrap_or`, etc. in `uumain`. -//! 1. It encourages the use of `UResult`/`Result` in functions in the utils. +//! 1. It encourages the use of [`UResult`]/[`Result`] in functions in the utils. //! 1. The error messages are largely standardized across utils. //! 1. Standardized error messages can be created from external result types //! (i.e. [`std::io::Result`] & `clap::ClapResult`). -//! 1. `set_exit_code` takes away the burden of manually tracking exit codes for non-fatal errors. +//! 1. [`set_exit_code`] takes away the burden of manually tracking exit codes for non-fatal errors. //! //! # Usage //! The signature of a typical util should be: @@ -19,7 +19,7 @@ //! ... //! } //! ``` -//! [`UResult`] is a simple wrapper around [`Result`] with a custom error type: [`UError`]. The +//! [`UResult`] is a simple wrapper around [`Result`] with a custom error trait: [`UError`]. The //! most important difference with types implementing [`std::error::Error`] is that [`UError`]s //! can specify the exit code of the program when they are returned from `uumain`: //! * When `Ok` is returned, the code set with [`set_exit_code`] is used as exit code. If @@ -41,8 +41,8 @@ //! [`set_exit_code`]. See the documentation on that function for more information. //! //! # Guidelines -//! * Use common errors where possible. -//! * Add variants to [`UCommonError`] if an error appears in multiple utils. +//! * Use error types from `uucore` where possible. +//! * Add error types to `uucore` if an error appears in multiple utils. //! * Prefer proper custom error types over [`ExitCode`] and [`USimpleError`]. //! * [`USimpleError`] may be used in small utils with simple error handling. //! * Using [`ExitCode`] is not recommended but can be useful for converting utils to use @@ -87,115 +87,10 @@ pub fn set_exit_code(code: i32) { EXIT_CODE.store(code, Ordering::SeqCst); } -/// Should be returned by all utils. -/// -/// Two additional methods are implemented on [`UResult`] on top of the normal [`Result`] methods: -/// `map_err_code` & `map_err_code_message`. -/// -/// These methods are used to convert [`UCommonError`]s into errors with a custom error code and -/// message. -pub type UResult = Result; +/// Result type that should be returned by all utils. +pub type UResult = Result>; -trait UResultTrait { - fn map_err_code(self, mapper: fn(&UCommonError) -> Option) -> Self; - fn map_err_code_and_message(self, mapper: fn(&UCommonError) -> Option<(i32, String)>) -> Self; -} - -impl UResultTrait for UResult { - fn map_err_code(self, mapper: fn(&UCommonError) -> Option) -> Self { - if let Err(UError::Common(error)) = self { - if let Some(code) = mapper(&error) { - Err(UCommonErrorWithCode { code, error }.into()) - } else { - Err(error.into()) - } - } else { - self - } - } - - fn map_err_code_and_message(self, mapper: fn(&UCommonError) -> Option<(i32, String)>) -> Self { - if let Err(UError::Common(ref error)) = self { - if let Some((code, message)) = mapper(error) { - return Err(USimpleError { code, message }.into()); - } - } - self - } -} - -/// The error type of [`UResult`]. -/// -/// `UError::Common` errors are defined in [`uucore`](crate) while `UError::Custom` errors are -/// defined by the utils. -/// ``` -/// use uucore::error::USimpleError; -/// let err = USimpleError::new(1, "Error!!".into()); -/// assert_eq!(1, err.code()); -/// assert_eq!(String::from("Error!!"), format!("{}", err)); -/// ``` -pub enum UError { - Common(UCommonError), - Custom(Box), -} - -impl UError { - /// The error code of [`UResult`] - /// - /// This function defines the error code associated with an instance of - /// [`UResult`]. To associate error codes for self-defined instances of - /// `UResult::Custom` (i.e. [`UCustomError`]), implement the - /// [`code`-function there](UCustomError::code). - pub fn code(&self) -> i32 { - match self { - UError::Common(e) => e.code(), - UError::Custom(e) => e.code(), - } - } - - /// Whether to print usage help for a [`UResult`] - /// - /// Defines if a variant of [`UResult`] should print a short usage message - /// below the error. The usage message is printed when this function returns - /// `true`. To do this for self-defined instances of `UResult::Custom` (i.e. - /// [`UCustomError`]), implement the [`usage`-function - /// there](UCustomError::usage). - pub fn usage(&self) -> bool { - match self { - UError::Common(e) => e.usage(), - UError::Custom(e) => e.usage(), - } - } -} - -impl From for UError { - fn from(v: UCommonError) -> Self { - UError::Common(v) - } -} - -impl From for UError { - fn from(v: i32) -> Self { - UError::Custom(Box::new(ExitCode(v))) - } -} - -impl From for UError { - fn from(v: E) -> Self { - UError::Custom(Box::new(v) as Box) - } -} - -impl Display for UError { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - UError::Common(e) => e.fmt(f), - UError::Custom(e) => e.fmt(f), - } - } -} - -/// Custom errors defined by the utils. +/// Custom errors defined by the utils and `uucore`. /// /// All errors should implement [`std::error::Error`], [`std::fmt::Display`] and /// [`std::fmt::Debug`] and have an additional `code` method that specifies the @@ -204,7 +99,7 @@ impl Display for UError { /// An example of a custom error from `ls`: /// /// ``` -/// use uucore::error::{UCustomError, UResult}; +/// use uucore::error::{UError, UResult}; /// use std::{ /// error::Error, /// fmt::{Display, Debug}, @@ -217,7 +112,7 @@ impl Display for UError { /// NoMetadata(PathBuf), /// } /// -/// impl UCustomError for LsError { +/// impl UError for LsError { /// fn code(&self) -> i32 { /// match self { /// LsError::InvalidLineWidth(_) => 2, @@ -248,12 +143,12 @@ impl Display for UError { /// } /// ``` /// -/// The call to `into()` is required to convert the [`UCustomError`] to an -/// instance of [`UError`]. +/// The call to `into()` is required to convert the `LsError` to +/// [`Box`]. The implementation for `From` is provided automatically. /// /// A crate like [`quick_error`](https://crates.io/crates/quick-error) might /// also be used, but will still require an `impl` for the `code` method. -pub trait UCustomError: Error + Send { +pub trait UError: Error + Send { /// Error code of a custom error. /// /// Set a return value for each variant of an enum-type to associate an @@ -263,7 +158,7 @@ pub trait UCustomError: Error + Send { /// # Example /// /// ``` - /// use uucore::error::{UCustomError}; + /// use uucore::error::{UError}; /// use std::{ /// error::Error, /// fmt::{Display, Debug}, @@ -277,7 +172,7 @@ pub trait UCustomError: Error + Send { /// Bing(), /// } /// - /// impl UCustomError for MyError { + /// impl UError for MyError { /// fn code(&self) -> i32 { /// match self { /// MyError::Foo(_) => 2, @@ -314,7 +209,7 @@ pub trait UCustomError: Error + Send { /// # Example /// /// ``` - /// use uucore::error::{UCustomError}; + /// use uucore::error::{UError}; /// use std::{ /// error::Error, /// fmt::{Display, Debug}, @@ -328,7 +223,7 @@ pub trait UCustomError: Error + Send { /// Bing(), /// } /// - /// impl UCustomError for MyError { + /// impl UError for MyError { /// fn usage(&self) -> bool { /// match self { /// // This will have a short usage help appended @@ -357,47 +252,23 @@ pub trait UCustomError: Error + Send { } } -impl From> for i32 { - fn from(e: Box) -> i32 { - e.code() +impl From for Box +where + T: UError + 'static, +{ + fn from(t: T) -> Box { + Box::new(t) } } -/// A [`UCommonError`] with an overridden exit code. +/// A simple error type with an exit code and a message that implements [`UError`]. /// -/// This exit code is returned instead of the default exit code for the [`UCommonError`]. This is -/// typically created with the either the `UResult::map_err_code` or `UCommonError::with_code` -/// method. -#[derive(Debug)] -pub struct UCommonErrorWithCode { - code: i32, - error: UCommonError, -} - -impl Error for UCommonErrorWithCode {} - -impl Display for UCommonErrorWithCode { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - self.error.fmt(f) - } -} - -impl UCustomError for UCommonErrorWithCode { - fn code(&self) -> i32 { - self.code - } -} - -/// A simple error type with an exit code and a message that implements [`UCustomError`]. -/// -/// It is typically created with the `UResult::map_err_code_and_message` method. Alternatively, it -/// can be constructed by manually: /// ``` /// use uucore::error::{UResult, USimpleError}; /// let err = USimpleError { code: 1, message: "error!".into()}; /// let res: UResult<()> = Err(err.into()); /// // or using the `new` method: -/// let res: UResult<()> = Err(USimpleError::new(1, "error!".into())); +/// let res: UResult<()> = Err(USimpleError::new(1, "error!")); /// ``` #[derive(Debug)] pub struct USimpleError { @@ -407,8 +278,11 @@ pub struct USimpleError { impl USimpleError { #[allow(clippy::new_ret_no_self)] - pub fn new(code: i32, message: String) -> UError { - UError::Custom(Box::new(Self { code, message })) + pub fn new>(code: i32, message: S) -> Box { + Box::new(Self { + code, + message: message.into(), + }) } } @@ -420,7 +294,7 @@ impl Display for USimpleError { } } -impl UCustomError for USimpleError { +impl UError for USimpleError { fn code(&self) -> i32 { self.code } @@ -434,8 +308,11 @@ pub struct UUsageError { impl UUsageError { #[allow(clippy::new_ret_no_self)] - pub fn new(code: i32, message: String) -> UError { - UError::Custom(Box::new(Self { code, message })) + pub fn new>(code: i32, message: S) -> Box { + Box::new(Self { + code, + message: message.into(), + }) } } @@ -447,7 +324,7 @@ impl Display for UUsageError { } } -impl UCustomError for UUsageError { +impl UError for UUsageError { fn code(&self) -> i32 { self.code } @@ -465,13 +342,13 @@ impl UCustomError for UUsageError { /// There are two ways to construct this type: with [`UIoError::new`] or by calling the /// [`FromIo::map_err_context`] method on a [`std::io::Result`] or [`std::io::Error`]. /// ``` -/// use uucore::error::{FromIo, UResult, UIoError, UCommonError}; +/// use uucore::error::{FromIo, UResult, UIoError, UError}; /// use std::fs::File; /// use std::path::Path; /// let path = Path::new("test.txt"); /// /// // Manual construction -/// let e: UIoError = UIoError::new( +/// let e: Box = UIoError::new( /// std::io::ErrorKind::NotFound, /// format!("cannot access '{}'", path.display()) /// ); @@ -487,22 +364,17 @@ pub struct UIoError { } impl UIoError { - pub fn new(kind: std::io::ErrorKind, context: String) -> Self { - Self { - context, + #[allow(clippy::new_ret_no_self)] + pub fn new>(kind: std::io::ErrorKind, context: S) -> Box { + Box::new(Self { + context: context.into(), inner: std::io::Error::new(kind, ""), - } - } - - pub fn code(&self) -> i32 { - 1 - } - - pub fn usage(&self) -> bool { - false + }) } } +impl UError for UIoError {} + impl Error for UIoError {} impl Display for UIoError { @@ -537,46 +409,33 @@ impl Display for UIoError { } } -/// Enables the conversion from `std::io::Error` to `UError` and from `std::io::Result` to -/// `UResult`. +/// Enables the conversion from [`std::io::Error`] to [`UError`] and from [`std::io::Result`] to +/// [`UResult`]. pub trait FromIo { fn map_err_context(self, context: impl FnOnce() -> String) -> T; } -impl FromIo for std::io::Error { - fn map_err_context(self, context: impl FnOnce() -> String) -> UIoError { - UIoError { +impl FromIo> for std::io::Error { + fn map_err_context(self, context: impl FnOnce() -> String) -> Box { + Box::new(UIoError { context: (context)(), inner: self, - } + }) } } impl FromIo> for std::io::Result { fn map_err_context(self, context: impl FnOnce() -> String) -> UResult { - self.map_err(|e| UError::Common(UCommonError::Io(e.map_err_context(context)))) + self.map_err(|e| e.map_err_context(context) as Box) } } -impl FromIo for std::io::ErrorKind { - fn map_err_context(self, context: impl FnOnce() -> String) -> UIoError { - UIoError { +impl FromIo> for std::io::ErrorKind { + fn map_err_context(self, context: impl FnOnce() -> String) -> Box { + Box::new(UIoError { context: (context)(), inner: std::io::Error::new(self, ""), - } - } -} - -impl From for UCommonError { - fn from(e: UIoError) -> UCommonError { - UCommonError::Io(e) - } -} - -impl From for UError { - fn from(e: UIoError) -> UError { - let common: UCommonError = e.into(); - common.into() + }) } } @@ -647,47 +506,6 @@ macro_rules! uio_error( }) ); -/// Common errors for utilities. -/// -/// If identical errors appear across multiple utilities, they should be added here. -#[derive(Debug)] -pub enum UCommonError { - Io(UIoError), - // Clap(UClapError), -} - -impl UCommonError { - pub fn with_code(self, code: i32) -> UCommonErrorWithCode { - UCommonErrorWithCode { code, error: self } - } - - pub fn code(&self) -> i32 { - 1 - } - - pub fn usage(&self) -> bool { - false - } -} - -impl From for i32 { - fn from(common: UCommonError) -> i32 { - match common { - UCommonError::Io(e) => e.code(), - } - } -} - -impl Error for UCommonError {} - -impl Display for UCommonError { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - match self { - UCommonError::Io(e) => e.fmt(f), - } - } -} - /// A special error type that does not print any message when returned from /// `uumain`. Especially useful for porting utilities to using [`UResult`]. /// @@ -705,6 +523,13 @@ impl Display for UCommonError { #[derive(Debug)] pub struct ExitCode(pub i32); +impl ExitCode { + #[allow(clippy::new_ret_no_self)] + pub fn new(code: i32) -> Box { + Box::new(Self(code)) + } +} + impl Error for ExitCode {} impl Display for ExitCode { @@ -713,8 +538,14 @@ impl Display for ExitCode { } } -impl UCustomError for ExitCode { +impl UError for ExitCode { fn code(&self) -> i32 { self.0 } } + +impl From for Box { + fn from(i: i32) -> Self { + ExitCode::new(i) + } +}