1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-31 13:07:46 +00:00

uucore: remove distinction between common and custom errors

As custom errors are prefered over wrapping around common errors, the
distinction between UCommonError and UCustomError is removed. This
reduces the number of types and makes the error handling easier to
understand.
This commit is contained in:
Terts Diepraam 2021-08-10 15:37:57 +02:00
parent ca0bae0dfd
commit 1649217116
11 changed files with 84 additions and 252 deletions

View file

@ -14,7 +14,7 @@ use uucore::fs::resolve_relative_path;
use uucore::libc::{gid_t, uid_t}; use uucore::libc::{gid_t, uid_t};
use uucore::perms::{wrap_chown, Verbosity}; 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}; use clap::{crate_version, App, Arg};
@ -324,7 +324,7 @@ impl Chowner {
ret |= self.traverse(f); ret |= self.traverse(f);
} }
if ret != 0 { if ret != 0 {
return Err(UError::from(ret)); return Err(ret.into());
} }
Ok(()) Ok(())
} }

View file

@ -8,7 +8,7 @@
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use uucore::error::UCustomError; use uucore::error::UError;
use uucore::error::UResult; use uucore::error::UResult;
#[cfg(unix)] #[cfg(unix)]
use uucore::fsext::statfs_fn; use uucore::fsext::statfs_fn;
@ -274,7 +274,7 @@ impl Display for DfError {
impl Error for DfError {} impl Error for DfError {}
impl UCustomError for DfError { impl UError for DfError {
fn code(&self) -> i32 { fn code(&self) -> i32 {
match self { match self {
DfError::InvalidBaseValue(_) => 1, DfError::InvalidBaseValue(_) => 1,

View file

@ -32,7 +32,7 @@ use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use std::time::{Duration, UNIX_EPOCH}; use std::time::{Duration, UNIX_EPOCH};
use std::{error::Error, fmt::Display}; 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::parse_size::{parse_size, ParseSizeError};
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
#[cfg(windows)] #[cfg(windows)]
@ -438,7 +438,7 @@ Try '{} --help' for more information.",
impl Error for DuError {} impl Error for DuError {}
impl UCustomError for DuError { impl UError for DuError {
fn code(&self) -> i32 { fn code(&self) -> i32 {
match self { match self {
Self::InvalidMaxDepthArg(_) => 1, Self::InvalidMaxDepthArg(_) => 1,

View file

@ -9,13 +9,12 @@
extern crate uucore; extern crate uucore;
use clap::App; use clap::App;
use uucore::error::{UError, UResult}; use uucore::{error::UResult, executable};
use uucore::executable;
#[uucore_procs::gen_uumain] #[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uumain(args: impl uucore::Args) -> UResult<()> {
uu_app().get_matches_from(args); uu_app().get_matches_from(args);
Err(UError::from(1)) Err(1.into())
} }
pub fn uu_app() -> App<'static, 'static> { pub fn uu_app() -> App<'static, 'static> {

View file

@ -17,7 +17,7 @@ use file_diff::diff;
use filetime::{set_file_times, FileTime}; use filetime::{set_file_times, FileTime};
use uucore::backup_control::{self, BackupMode}; use uucore::backup_control::{self, BackupMode};
use uucore::entries::{grp2gid, usr2uid}; 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 uucore::perms::{wrap_chgrp, wrap_chown, Verbosity};
use libc::{getegid, geteuid}; use libc::{getegid, geteuid};
@ -66,7 +66,7 @@ enum InstallError {
OmittingDirectory(PathBuf), OmittingDirectory(PathBuf),
} }
impl UCustomError for InstallError { impl UError for InstallError {
fn code(&self) -> i32 { fn code(&self) -> i32 {
match self { match self {
InstallError::Unimplemented(_) => 2, InstallError::Unimplemented(_) => 2,

View file

@ -11,7 +11,7 @@
extern crate uucore; extern crate uucore;
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
use uucore::error::{UCustomError, UResult}; use uucore::error::{UError, UResult};
use std::borrow::Cow; use std::borrow::Cow;
use std::error::Error; use std::error::Error;
@ -79,7 +79,7 @@ impl Display for LnError {
impl Error for LnError {} impl Error for LnError {}
impl UCustomError for LnError { impl UError for LnError {
fn code(&self) -> i32 { fn code(&self) -> i32 {
match self { match self {
Self::TargetIsDirectory(_) => 1, Self::TargetIsDirectory(_) => 1,

View file

@ -39,7 +39,7 @@ use std::{
time::Duration, time::Duration,
}; };
use term_grid::{Cell, Direction, Filling, Grid, GridOptions}; 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; use unicode_width::UnicodeWidthStr;
#[cfg(unix)] #[cfg(unix)]
@ -133,7 +133,7 @@ enum LsError {
NoMetadata(PathBuf), NoMetadata(PathBuf),
} }
impl UCustomError for LsError { impl UError for LsError {
fn code(&self) -> i32 { fn code(&self) -> i32 {
match self { match self {
LsError::InvalidLineWidth(_) => 2, LsError::InvalidLineWidth(_) => 2,

View file

@ -12,7 +12,7 @@
extern crate uucore; extern crate uucore;
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
use uucore::error::{FromIo, UCustomError, UResult}; use uucore::error::{FromIo, UError, UResult};
use std::env; use std::env;
use std::error::Error; use std::error::Error;
@ -49,7 +49,7 @@ enum MkTempError {
InvalidTemplate(String), InvalidTemplate(String),
} }
impl UCustomError for MkTempError {} impl UError for MkTempError {}
impl Error for MkTempError {} impl Error for MkTempError {}

View file

@ -45,7 +45,7 @@ use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::Utf8Error; use std::str::Utf8Error;
use unicode_width::UnicodeWidthStr; 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::parse_size::{parse_size, ParseSizeError};
use uucore::version_cmp::version_cmp; use uucore::version_cmp::version_cmp;
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
@ -164,7 +164,7 @@ enum SortError {
impl Error for SortError {} impl Error for SortError {}
impl UCustomError for SortError { impl UError for SortError {
fn code(&self) -> i32 { fn code(&self) -> i32 {
match self { match self {
SortError::Disorder { .. } => 1, SortError::Disorder { .. } => 1,

View file

@ -17,7 +17,7 @@ use clap::{crate_version, App, Arg, ArgGroup};
use filetime::*; use filetime::*;
use std::fs::{self, File}; use std::fs::{self, File};
use std::path::Path; 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."; static ABOUT: &str = "Update the access and modification times of each FILE to the current time.";
pub mod options { pub mod options {

View file

@ -6,11 +6,11 @@
//! This module provides types to reconcile these exit codes with idiomatic Rust error //! 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`]: //! 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 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. The error messages are largely standardized across utils.
//! 1. Standardized error messages can be created from external result types //! 1. Standardized error messages can be created from external result types
//! (i.e. [`std::io::Result`] & `clap::ClapResult`). //! (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 //! # Usage
//! The signature of a typical util should be: //! 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 //! 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`: //! 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 //! * 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. //! [`set_exit_code`]. See the documentation on that function for more information.
//! //!
//! # Guidelines //! # Guidelines
//! * Use common errors where possible. //! * Use error types from `uucore` where possible.
//! * Add variants to [`UCommonError`] if an error appears in multiple utils. //! * Add error types to `uucore` if an error appears in multiple utils.
//! * Prefer proper custom error types over [`ExitCode`] and [`USimpleError`]. //! * Prefer proper custom error types over [`ExitCode`] and [`USimpleError`].
//! * [`USimpleError`] may be used in small utils with simple error handling. //! * [`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 //! * 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); EXIT_CODE.store(code, Ordering::SeqCst);
} }
/// Should be returned by all utils. /// Result type that should be returned by all utils.
/// pub type UResult<T> = Result<T, Box<dyn UError>>;
/// 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<T> = Result<T, UError>;
trait UResultTrait<T> { /// Custom errors defined by the utils and `uucore`.
fn map_err_code(self, mapper: fn(&UCommonError) -> Option<i32>) -> Self;
fn map_err_code_and_message(self, mapper: fn(&UCommonError) -> Option<(i32, String)>) -> Self;
}
impl<T> UResultTrait<T> for UResult<T> {
fn map_err_code(self, mapper: fn(&UCommonError) -> Option<i32>) -> 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<dyn UCustomError>),
}
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<UCommonError> for UError {
fn from(v: UCommonError) -> Self {
UError::Common(v)
}
}
impl From<i32> for UError {
fn from(v: i32) -> Self {
UError::Custom(Box::new(ExitCode(v)))
}
}
impl<E: UCustomError + 'static> From<E> for UError {
fn from(v: E) -> Self {
UError::Custom(Box::new(v) as Box<dyn UCustomError>)
}
}
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.
/// ///
/// All errors should implement [`std::error::Error`], [`std::fmt::Display`] and /// All errors should implement [`std::error::Error`], [`std::fmt::Display`] and
/// [`std::fmt::Debug`] and have an additional `code` method that specifies the /// [`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`: /// An example of a custom error from `ls`:
/// ///
/// ``` /// ```
/// use uucore::error::{UCustomError, UResult}; /// use uucore::error::{UError, UResult};
/// use std::{ /// use std::{
/// error::Error, /// error::Error,
/// fmt::{Display, Debug}, /// fmt::{Display, Debug},
@ -217,7 +112,7 @@ impl Display for UError {
/// NoMetadata(PathBuf), /// NoMetadata(PathBuf),
/// } /// }
/// ///
/// impl UCustomError for LsError { /// impl UError for LsError {
/// fn code(&self) -> i32 { /// fn code(&self) -> i32 {
/// match self { /// match self {
/// LsError::InvalidLineWidth(_) => 2, /// LsError::InvalidLineWidth(_) => 2,
@ -248,12 +143,12 @@ impl Display for UError {
/// } /// }
/// ``` /// ```
/// ///
/// The call to `into()` is required to convert the [`UCustomError`] to an /// The call to `into()` is required to convert the `LsError` to
/// instance of [`UError`]. /// [`Box<dyn UError>`]. The implementation for `From` is provided automatically.
/// ///
/// A crate like [`quick_error`](https://crates.io/crates/quick-error) might /// 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. /// 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. /// Error code of a custom error.
/// ///
/// Set a return value for each variant of an enum-type to associate an /// Set a return value for each variant of an enum-type to associate an
@ -263,7 +158,7 @@ pub trait UCustomError: Error + Send {
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use uucore::error::{UCustomError}; /// use uucore::error::{UError};
/// use std::{ /// use std::{
/// error::Error, /// error::Error,
/// fmt::{Display, Debug}, /// fmt::{Display, Debug},
@ -277,7 +172,7 @@ pub trait UCustomError: Error + Send {
/// Bing(), /// Bing(),
/// } /// }
/// ///
/// impl UCustomError for MyError { /// impl UError for MyError {
/// fn code(&self) -> i32 { /// fn code(&self) -> i32 {
/// match self { /// match self {
/// MyError::Foo(_) => 2, /// MyError::Foo(_) => 2,
@ -314,7 +209,7 @@ pub trait UCustomError: Error + Send {
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use uucore::error::{UCustomError}; /// use uucore::error::{UError};
/// use std::{ /// use std::{
/// error::Error, /// error::Error,
/// fmt::{Display, Debug}, /// fmt::{Display, Debug},
@ -328,7 +223,7 @@ pub trait UCustomError: Error + Send {
/// Bing(), /// Bing(),
/// } /// }
/// ///
/// impl UCustomError for MyError { /// impl UError for MyError {
/// fn usage(&self) -> bool { /// fn usage(&self) -> bool {
/// match self { /// match self {
/// // This will have a short usage help appended /// // This will have a short usage help appended
@ -357,41 +252,17 @@ pub trait UCustomError: Error + Send {
} }
} }
impl From<Box<dyn UCustomError>> for i32 { impl<T> From<T> for Box<dyn UError>
fn from(e: Box<dyn UCustomError>) -> i32 { where
e.code() T: UError + 'static,
{
fn from(t: T) -> Box<dyn UError> {
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}; /// use uucore::error::{UResult, USimpleError};
/// let err = USimpleError { code: 1, message: "error!".into()}; /// let err = USimpleError { code: 1, message: "error!".into()};
@ -407,8 +278,8 @@ pub struct USimpleError {
impl USimpleError { impl USimpleError {
#[allow(clippy::new_ret_no_self)] #[allow(clippy::new_ret_no_self)]
pub fn new(code: i32, message: String) -> UError { pub fn new(code: i32, message: String) -> Box<dyn UError> {
UError::Custom(Box::new(Self { code, message })) Box::new(Self { code, message })
} }
} }
@ -420,7 +291,7 @@ impl Display for USimpleError {
} }
} }
impl UCustomError for USimpleError { impl UError for USimpleError {
fn code(&self) -> i32 { fn code(&self) -> i32 {
self.code self.code
} }
@ -434,8 +305,8 @@ pub struct UUsageError {
impl UUsageError { impl UUsageError {
#[allow(clippy::new_ret_no_self)] #[allow(clippy::new_ret_no_self)]
pub fn new(code: i32, message: String) -> UError { pub fn new(code: i32, message: String) -> Box<dyn UError> {
UError::Custom(Box::new(Self { code, message })) Box::new(Self { code, message })
} }
} }
@ -447,7 +318,7 @@ impl Display for UUsageError {
} }
} }
impl UCustomError for UUsageError { impl UError for UUsageError {
fn code(&self) -> i32 { fn code(&self) -> i32 {
self.code self.code
} }
@ -465,13 +336,13 @@ impl UCustomError for UUsageError {
/// There are two ways to construct this type: with [`UIoError::new`] or by calling the /// 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`]. /// [`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::fs::File;
/// use std::path::Path; /// use std::path::Path;
/// let path = Path::new("test.txt"); /// let path = Path::new("test.txt");
/// ///
/// // Manual construction /// // Manual construction
/// let e: UIoError = UIoError::new( /// let e: Box<dyn UError> = UIoError::new(
/// std::io::ErrorKind::NotFound, /// std::io::ErrorKind::NotFound,
/// format!("cannot access '{}'", path.display()) /// format!("cannot access '{}'", path.display())
/// ); /// );
@ -487,18 +358,21 @@ pub struct UIoError {
} }
impl UIoError { impl UIoError {
pub fn new(kind: std::io::ErrorKind, context: String) -> Self { #[allow(clippy::new_ret_no_self)]
Self { pub fn new(kind: std::io::ErrorKind, context: String) -> Box<dyn UError> {
Box::new(Self {
context, context,
inner: std::io::Error::new(kind, ""), inner: std::io::Error::new(kind, ""),
} })
} }
}
pub fn code(&self) -> i32 { impl UError for UIoError {
fn code(&self) -> i32 {
1 1
} }
pub fn usage(&self) -> bool { fn usage(&self) -> bool {
false false
} }
} }
@ -537,46 +411,33 @@ impl Display for UIoError {
} }
} }
/// Enables the conversion from `std::io::Error` to `UError` and from `std::io::Result` to /// Enables the conversion from [`std::io::Error`] to [`UError`] and from [`std::io::Result`] to
/// `UResult`. /// [`UResult`].
pub trait FromIo<T> { pub trait FromIo<T> {
fn map_err_context(self, context: impl FnOnce() -> String) -> T; fn map_err_context(self, context: impl FnOnce() -> String) -> T;
} }
impl FromIo<UIoError> for std::io::Error { impl FromIo<Box<UIoError>> for std::io::Error {
fn map_err_context(self, context: impl FnOnce() -> String) -> UIoError { fn map_err_context(self, context: impl FnOnce() -> String) -> Box<UIoError> {
UIoError { Box::new(UIoError {
context: (context)(), context: (context)(),
inner: self, inner: self,
} })
} }
} }
impl<T> FromIo<UResult<T>> for std::io::Result<T> { impl<T> FromIo<UResult<T>> for std::io::Result<T> {
fn map_err_context(self, context: impl FnOnce() -> String) -> UResult<T> { fn map_err_context(self, context: impl FnOnce() -> String) -> UResult<T> {
self.map_err(|e| UError::Common(UCommonError::Io(e.map_err_context(context)))) self.map_err(|e| e.map_err_context(context) as Box<dyn UError>)
} }
} }
impl FromIo<UIoError> for std::io::ErrorKind { impl FromIo<Box<UIoError>> for std::io::ErrorKind {
fn map_err_context(self, context: impl FnOnce() -> String) -> UIoError { fn map_err_context(self, context: impl FnOnce() -> String) -> Box<UIoError> {
UIoError { Box::new(UIoError {
context: (context)(), context: (context)(),
inner: std::io::Error::new(self, ""), inner: std::io::Error::new(self, ""),
} })
}
}
impl From<UIoError> for UCommonError {
fn from(e: UIoError) -> UCommonError {
UCommonError::Io(e)
}
}
impl From<UIoError> for UError {
fn from(e: UIoError) -> UError {
let common: UCommonError = e.into();
common.into()
} }
} }
@ -647,47 +508,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<UCommonError> 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 /// A special error type that does not print any message when returned from
/// `uumain`. Especially useful for porting utilities to using [`UResult`]. /// `uumain`. Especially useful for porting utilities to using [`UResult`].
/// ///
@ -705,6 +525,13 @@ impl Display for UCommonError {
#[derive(Debug)] #[derive(Debug)]
pub struct ExitCode(pub i32); pub struct ExitCode(pub i32);
impl ExitCode {
#[allow(clippy::new_ret_no_self)]
pub fn new(code: i32) -> Box<dyn UError> {
Box::new(Self(code))
}
}
impl Error for ExitCode {} impl Error for ExitCode {}
impl Display for ExitCode { impl Display for ExitCode {
@ -713,8 +540,14 @@ impl Display for ExitCode {
} }
} }
impl UCustomError for ExitCode { impl UError for ExitCode {
fn code(&self) -> i32 { fn code(&self) -> i32 {
self.0 self.0
} }
} }
impl From<i32> for Box<dyn UError> {
fn from(i: i32) -> Self {
ExitCode::new(i)
}
}