Index: Cargo.toml ================================================================== --- Cargo.toml +++ Cargo.toml @@ -1,8 +1,8 @@ [package] name = "apperr" -version = "0.1.0" +version = "0.2.0" license = "0BSD" keywords = [ "any", "error", "callback" ] repository = "https://repos.qrnch.tech/pub/apperr" description = "A thin special-purpose wrapper around Any." rust-version = "1.0" @@ -12,10 +12,8 @@ ".fslckout", "www", "rustfmt.toml" ] -[dependencies] - [package.metadata.docs.rs] rustdoc-args = ["--generate-link-to-definition"] Index: src/lib.rs ================================================================== --- src/lib.rs +++ src/lib.rs @@ -3,19 +3,28 @@ //! The archetypal use-case is to allow applications that call library //! runtimes which call application callbacks to allow the application //! callbacks to return application-specific errors back to itself through the //! runtime. //! +//! In order to lessen the risk of wrapping an unintended type, the [`AppErr`] +//! constructor only take in types that implement [`apperr::Blessed`](Blessed) +//! (which is a subtrait of [`std::error::Error`]). +//! //! # Alternatives //! There are other ways to solve the same problem, but they are not always //! feasible. //! - Traits can use associated types to declare the application-specific error //! types. //! - A generic parameter can be used to declare the application-specific error //! type. +//! - Global variables can be used to store error information. use std::any::Any; + +/// Marker trait used to bless a type so that it can be used as a +/// application-specific error. +pub trait Blessed: std::error::Error {} /// An error type used to pass an application-specific error through a library /// runtime. /// /// Application callbacks can return this type for the `Err()` case in order @@ -28,32 +37,60 @@ impl AppErr { /// Create a new application callback error object that can be converted back /// into to its original type (as long as it is [`Any`] compatible). /// /// ``` - /// use apperr::AppErr; + /// use std::fmt; + /// use apperr::{AppErr, Blessed}; /// + /// #[derive(Debug)] /// enum MyErr { /// Something(String) /// } + /// impl fmt::Display for MyErr { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// match self { + /// MyErr::Something(s) => { + /// write!(f, "Some error; {}", s) + /// } + /// } + /// } + /// } + /// impl std::error::Error for MyErr { } + /// impl Blessed for MyErr { } + /// /// let apperr = AppErr::new(MyErr::Something("hello".into())); /// ``` pub fn new(e: E) -> Self where - E: Send + 'static + E: Blessed + Send + 'static { Self(Box::new(e)) } /// Inspect error type wrapped by the `AppErr`. /// /// ``` - /// use apperr::AppErr; + /// use std::fmt; + /// use apperr::{AppErr, Blessed}; /// + /// #[derive(Debug)] /// enum MyErr { /// Something(String) /// } + /// impl fmt::Display for MyErr { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// match self { + /// MyErr::Something(s) => { + /// write!(f, "Some error; {}", s) + /// } + /// } + /// } + /// } + /// impl std::error::Error for MyErr { } + /// impl Blessed for MyErr { } + /// /// let apperr = AppErr::new(MyErr::Something("hello".into())); /// /// assert!(apperr.is::()); /// assert_eq!(apperr.is::(), false); /// ``` @@ -68,15 +105,29 @@ /// /// If it can't be downcast to `E`, the `AppErr` will be returned back to the /// caller in the `Err()` case. /// /// ``` - /// use apperr::AppErr; + /// use std::fmt; + /// use apperr::{AppErr, Blessed}; /// + /// #[derive(Debug)] /// enum MyErr { /// Something(String) /// } + /// impl fmt::Display for MyErr { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// match self { + /// MyErr::Something(s) => { + /// write!(f, "Some error; {}", s) + /// } + /// } + /// } + /// } + /// impl std::error::Error for MyErr { } + /// impl Blessed for MyErr { } + /// /// let apperr = AppErr::new(MyErr::Something("hello".into())); /// /// let Ok(e) = apperr.try_into_inner::() else { /// panic!("Unexpectedly not MyErr"); /// }; @@ -89,15 +140,29 @@ } /// Unwrap application-specific error. /// /// ``` - /// use apperr::AppErr; + /// use std::fmt; + /// use apperr::{AppErr, Blessed}; /// + /// #[derive(Debug)] /// enum MyErr { /// Something(String) /// } + /// impl fmt::Display for MyErr { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// match self { + /// MyErr::Something(s) => { + /// write!(f, "Some error; {}", s) + /// } + /// } + /// } + /// } + /// impl std::error::Error for MyErr { } + /// impl Blessed for MyErr { } + /// /// let apperr = AppErr::new(MyErr::Something("hello".into())); /// /// let MyErr::Something(e) = apperr.unwrap_inner::() else { /// panic!("Unexpectedly not MyErr::Something"); /// }; Index: www/changelog.md ================================================================== --- www/changelog.md +++ www/changelog.md @@ -2,14 +2,40 @@ ## [Unreleased] ### Added +- Add a `Blessed` trait used to mark types as allowed to be wrapped by + `AppErr`. + ### Changed + +- The `AppErr::new()` constructor's input now must implement + `std::error::Error` and `apperr::Blessed` to lessen the risk that wrong type + is passed by accident (avoid things like the `Result` being passed instead of + the error type). ### Removed +--- + +## [0.2.0] - 2024-01-14 + +[Details](/vdiff?from=apperr-0.1.0&to=apperr-0.2.0) + +### Added + +- Add a `Blessed` trait used to mark types as allowed to be wrapped by + `AppErr`. + +### Changed + +- The `AppErr::new()` constructor's input now must implement + `std::error::Error` and `apperr::Blessed` to lessen the risk that wrong type + is passed by accident (avoid things like the `Result` being passed instead of + the error type). + --- ## [0.1.0] - 2023-12-12 - Initial release. Index: www/index.md ================================================================== --- www/index.md +++ www/index.md @@ -1,9 +1,8 @@ # AppErr -A very thin `Any` wrapper which does nothing more than state its intended -use-case. +A very thin `Any` wrapper which is meant to store an error. ## Change log The details of changes can always be found in the timeline, but for a