diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..43d6f08 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,15 @@ +# CHANGELOG + +All significant changes to this project will be documented in this file. + +## Unreleased + +### Breaking Changes + +* `Exn::from_iter` has been renamed to `Exn::raise_all` +* `exn::Error` trait bound has been removed in favor of inlined `StdError + Send + Sync + 'static` bounds. +* `err.raise()` has been moved to the `exn::ErrorExt` extension trait. + +### New Features + +* This crate is now `no_std` compatible, while the `alloc` crate is still required for heap allocations. It is worth noting that `no_std` support is a nice-to-have feature, and can be dropped if it blocks other important features in the future. Before 1.0, once `exn` APIs settle down, the decision on whether to keep `no_std` as a promise will be finalized. diff --git a/README.md b/README.md index 0f172c8..af7a39d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# A context-aware concrete Error type built on `std::error::Error` +# A context-aware concrete Error type built on `core::error::Error` [![Crates.io][crates-badge]][crates-url] [![Documentation][docs-badge]][docs-url] @@ -16,7 +16,7 @@ ## Overview -`exn` provides the missing context APIs for `std::error::Error`. +`exn` provides the missing context APIs for `core::error::Error`. It organizes errors as a tree structure, allowing you to easily access the root cause and all related errors with their context. @@ -24,6 +24,12 @@ It organizes errors as a tree structure, allowing you to easily access the root Read the online documents at https://docs.rs/exn. +## `no_std` crates + +This crate is `no_std` compatible, while the `alloc` crate is still required for heap allocations. + +It is worth noting that `no_std` support is a nice-to-have feature, and can be dropped if it blocks other important features in the future. Before 1.0, once `exn` APIs settle down, the decision on whether to keep `no_std` as a promise will be finalized. + ## License This project is licensed under [Apache License, Version 2.0](LICENSE). diff --git a/examples/Cargo.toml b/examples/Cargo.toml index e1d4a81..9285df6 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -19,8 +19,8 @@ publish = false edition.workspace = true [[example]] -name = "anti-pattern" -path = "src/anti-pattern.rs" +name = "antipattern" +path = "src/antipattern.rs" [[example]] name = "basic" diff --git a/examples/src/anti-pattern.rs b/examples/src/antipattern.rs similarity index 95% rename from examples/src/anti-pattern.rs rename to examples/src/antipattern.rs index a3529fb..f4a8516 100644 --- a/examples/src/anti-pattern.rs +++ b/examples/src/antipattern.rs @@ -80,8 +80,8 @@ mod http { // Output when running `cargo run --example anti_pattern`. // Notice "failed to send request" appears twice with no new information! // -// Error: fatal error occurred in application, at examples/src/anti-pattern.rs:35:16 +// Error: fatal error occurred in application, at examples/src/antipattern.rs:35:16 // | -// |-> failed to send request, at examples/src/anti-pattern.rs:49:30 +// |-> failed to send request, at examples/src/antipattern.rs:49:30 // | -// |-> failed to send request to server: https://anti-pattern.com, at examples/src/anti-pattern.rs:67:9 +// |-> failed to send request to server: https://anti-pattern.com, at examples/src/antipattern.rs:67:9 diff --git a/examples/src/make-error.rs b/examples/src/make-error.rs index 217bb1e..1d0bfa2 100644 --- a/examples/src/make-error.rs +++ b/examples/src/make-error.rs @@ -17,7 +17,7 @@ //! When a function has several fallible calls, it's common to want one *function-level* context //! string for all of them. //! -//! This reduces boilerplate and avoids the anti-pattern of writing per-callsite context that +//! This reduces boilerplate and avoids the antipattern of writing per-caller-site context that //! simply repeats what the child error already says. use std::error::Error; diff --git a/exn/Cargo.toml b/exn/Cargo.toml index 26ad0e1..54c8597 100644 --- a/exn/Cargo.toml +++ b/exn/Cargo.toml @@ -16,7 +16,7 @@ name = "exn" version = "0.3.0-rc.2" -description = "A context-aware concrete Error type built on `std::error::Error`." +description = "A context-aware concrete Error type built on `core::error::Error`." edition.workspace = true homepage.workspace = true diff --git a/exn/src/debug.rs b/exn/src/debug.rs index 2fa364f..353a2d6 100644 --- a/exn/src/debug.rs +++ b/exn/src/debug.rs @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::error::Error; -use std::fmt; +use alloc::format; +use core::error::Error; +use core::fmt; use crate::Exn; use crate::Frame; diff --git a/exn/src/display.rs b/exn/src/display.rs index 9b10e91..d0c6380 100644 --- a/exn/src/display.rs +++ b/exn/src/display.rs @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::error::Error; -use std::fmt; +use core::error::Error; +use core::fmt; use crate::Exn; use crate::Frame; diff --git a/exn/src/ext.rs b/exn/src/ext.rs index fd61228..c5f47d8 100644 --- a/exn/src/ext.rs +++ b/exn/src/ext.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::error::Error; +use core::error::Error; use crate::Exn; use crate::Result; @@ -25,13 +25,13 @@ use crate::Result; /// One might think that `exn::Result::Ok(value)` would work in such cases, but it does not. /// /// ```console -/// error[E0282]: type annotations needed for `std::result::Result` +/// error[E0282]: type annotations needed for `core::result::Result` /// --> src/main.rs:11:13 /// | /// 11 | let _ = exn::Result::Ok(1); /// | - ^^^^^^^^^^^^^^^ cannot infer type for type parameter `E` declared on the enum `Result` /// | | -/// | consider giving this pattern the explicit type `std::result::Result`, where the type parameter `E` is specified +/// | consider giving this pattern the explicit type `core::result::Result`, where the type parameter `E` is specified /// ``` #[expect(non_snake_case)] pub fn Ok(value: T) -> Result { diff --git a/exn/src/impls.rs b/exn/src/impls.rs index b815129..1aa007e 100644 --- a/exn/src/impls.rs +++ b/exn/src/impls.rs @@ -12,10 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::error::Error; -use std::fmt; -use std::marker::PhantomData; -use std::panic::Location; +use alloc::boxed::Box; +use alloc::string::String; +use alloc::string::ToString; +use alloc::vec; +use alloc::vec::Vec; +use core::error::Error; +use core::fmt; +use core::marker::PhantomData; +use core::panic::Location; /// An exception type that can hold an error tree and additional context. pub struct Exn { diff --git a/exn/src/lib.rs b/exn/src/lib.rs index 6896ab1..dfd97ed 100644 --- a/exn/src/lib.rs +++ b/exn/src/lib.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! A context-aware concrete Error type built on `std::error::Error` +//! A context-aware concrete Error type built on `core::error::Error` //! //! # Examples //! @@ -25,13 +25,13 @@ //! #[derive(Debug)] //! struct LogicError(String); //! -//! impl std::fmt::Display for LogicError { -//! fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +//! impl core::fmt::Display for LogicError { +//! fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { //! write!(f, "logic error: {}", self.0) //! } //! } //! -//! impl std::error::Error for LogicError {} +//! impl core::error::Error for LogicError {} //! //! fn do_logic() -> Result<(), LogicError> { //! bail!(LogicError("0 == 1".to_string())); @@ -44,8 +44,8 @@ //! Trivial, //! } //! -//! impl std::fmt::Display for AppError { -//! fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +//! impl core::fmt::Display for AppError { +//! fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { //! match self { //! AppError::Fatal { consequences } => write!(f, "fatal error: {consequences}"), //! AppError::Trivial => write!(f, "trivial error"), @@ -53,7 +53,7 @@ //! } //! } //! -//! impl std::error::Error for AppError {} +//! impl core::error::Error for AppError {} //! //! fn main() { //! if let Err(err) = do_logic().or_raise(|| AppError::Fatal { @@ -74,6 +74,9 @@ #![cfg_attr(docsrs, feature(doc_cfg))] #![deny(missing_docs)] +#![no_std] + +extern crate alloc; mod debug; mod display; diff --git a/exn/src/macros.rs b/exn/src/macros.rs index 327cbe7..2908ad2 100644 --- a/exn/src/macros.rs +++ b/exn/src/macros.rs @@ -21,12 +21,13 @@ /// Create an [`Exn`] from [`Error`]: /// /// [`Exn`]: crate::Exn -/// [`Error`]: std::error::Error +/// [`Error`]: core::error::Error /// /// ``` /// use std::fs; /// /// use exn::bail; +/// /// # fn wrapper() -> exn::Result<(), std::io::Error> { /// match fs::read_to_string("/path/to/file") { /// Ok(content) => println!("file contents: {content}"), @@ -37,7 +38,7 @@ #[macro_export] macro_rules! bail { ($err:expr) => {{ - return ::std::result::Result::Err($crate::Exn::from($err)); + return ::core::result::Result::Err($crate::Exn::from($err)); }}; } @@ -50,7 +51,7 @@ macro_rules! bail { /// Create an [`Exn`] from an [`Error`]: /// /// [`Exn`]: crate::Exn -/// [`Error`]: std::error::Error +/// [`Error`]: core::error::Error /// /// ``` /// # fn has_permission(_: &u32, _: &u32) -> bool { true } @@ -58,8 +59,8 @@ macro_rules! bail { /// # let user = 0; /// # type Resource = u32; /// # let resource = 0; -/// use std::error::Error; -/// use std::fmt; +/// use core::error::Error; +/// use core::fmt; /// /// use exn::ensure; /// diff --git a/exn/src/option.rs b/exn/src/option.rs index d4450ca..72daf85 100644 --- a/exn/src/option.rs +++ b/exn/src/option.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::error::Error; +use core::error::Error; use crate::Exn; use crate::Result; diff --git a/exn/src/result.rs b/exn/src/result.rs index 9a01714..a52403c 100644 --- a/exn/src/result.rs +++ b/exn/src/result.rs @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::error::Error; +use core::error::Error; use crate::Exn; /// A reasonable return type to use throughout an application. -pub type Result = std::result::Result>; +pub type Result = core::result::Result>; /// An extension trait for [`Result`] to provide context information on [`Exn`]s. pub trait ResultExt { @@ -36,7 +36,7 @@ pub trait ResultExt { F: FnOnce() -> A; } -impl ResultExt for std::result::Result +impl ResultExt for core::result::Result where E: Error + Send + Sync + 'static, { @@ -56,7 +56,7 @@ where } } -impl ResultExt for std::result::Result> +impl ResultExt for core::result::Result> where E: Error + Send + Sync + 'static, {