From 4f0da29bef69c0d002f7def30dcac31d92b6e8a7 Mon Sep 17 00:00:00 2001 From: Olivier Pinon Date: Wed, 7 Jan 2026 17:49:41 +0100 Subject: [PATCH 1/7] Support for #![no_std] --- exn/src/debug.rs | 8 +++++--- exn/src/display.rs | 2 +- exn/src/impls.rs | 25 ++++++++++++++++--------- exn/src/lib.rs | 7 +++++-- exn/src/result.rs | 6 +++--- 5 files changed, 30 insertions(+), 18 deletions(-) diff --git a/exn/src/debug.rs b/exn/src/debug.rs index e45ea7e..974c6f6 100644 --- a/exn/src/debug.rs +++ b/exn/src/debug.rs @@ -12,8 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::fmt; -use std::fmt::Formatter; +use core::fmt; +use core::fmt::Formatter; + +use alloc::format; use crate::Error; use crate::Exn; @@ -72,8 +74,8 @@ fn write_location(f: &mut Formatter<'_>, exn: &Frame) -> fmt::Result { let location = exn.location(); use std::os::windows::ffi::OsStrExt; use std::path::Component; - use std::path::MAIN_SEPARATOR; use std::path::Path; + use std::path::MAIN_SEPARATOR; let file = location.file(); let path = Path::new(file); diff --git a/exn/src/display.rs b/exn/src/display.rs index 7b839d6..621c618 100644 --- a/exn/src/display.rs +++ b/exn/src/display.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::fmt; +use core::fmt; use crate::Error; use crate::Exn; diff --git a/exn/src/impls.rs b/exn/src/impls.rs index fadf1fb..bd184f9 100644 --- a/exn/src/impls.rs +++ b/exn/src/impls.rs @@ -12,9 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::fmt; -use std::marker::PhantomData; -use std::panic::Location; +use core::fmt; +use core::marker::PhantomData; +use core::panic::Location; + +use alloc::boxed::Box; +use alloc::string::{String, ToString}; +use alloc::vec::Vec; use crate::Error; @@ -57,18 +61,21 @@ impl Exn { } } - impl std::error::Error for SourceError {} + impl core::error::Error for SourceError {} - fn walk(error: &dyn std::error::Error, location: &'static Location<'static>) -> Vec { + fn walk( + error: &dyn core::error::Error, + location: &'static Location<'static>, + ) -> Vec { if let Some(source) = error.source() { - let children = vec![Frame { + let children = alloc::vec![Frame { error: Box::new(SourceError(source.to_string())), location, children: walk(source, location), }]; children } else { - vec![] + alloc::vec![] } } @@ -136,12 +143,12 @@ pub struct Frame { impl Frame { /// Return the error as a reference to [`std::any::Any`]. - pub fn as_any(&self) -> &dyn std::any::Any { + pub fn as_any(&self) -> &dyn core::any::Any { &*self.error } /// Return the error as a reference to [`std::error::Error`]. - pub fn as_error(&self) -> &dyn std::error::Error { + pub fn as_error(&self) -> &dyn core::error::Error { &*self.error } diff --git a/exn/src/lib.rs b/exn/src/lib.rs index c3cc71b..423ae4b 100644 --- a/exn/src/lib.rs +++ b/exn/src/lib.rs @@ -74,6 +74,9 @@ #![cfg_attr(docsrs, feature(doc_cfg))] #![deny(missing_docs)] +#![no_std] + +extern crate alloc; mod debug; mod display; @@ -89,7 +92,7 @@ pub use self::result::Result; pub use self::result::ResultExt; /// A trait bound of the supported error type of [`Exn`]. -pub trait Error: std::error::Error + std::any::Any + Send + Sync + 'static { +pub trait Error: core::error::Error + core::any::Any + Send + Sync + 'static { /// Raise this error as a new exception. #[track_caller] fn raise(self) -> Exn @@ -100,7 +103,7 @@ pub trait Error: std::error::Error + std::any::Any + Send + Sync + 'static { } } -impl Error for T where T: std::error::Error + std::any::Any + Send + Sync + 'static {} +impl Error for T where T: core::error::Error + core::any::Any + Send + Sync + 'static {} /// Equivalent to `Ok::<_, Exn>(value)`. /// diff --git a/exn/src/result.rs b/exn/src/result.rs index 8d58548..c62921b 100644 --- a/exn/src/result.rs +++ b/exn/src/result.rs @@ -16,7 +16,7 @@ use crate::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 { @@ -35,7 +35,7 @@ pub trait ResultExt { F: FnOnce() -> A; } -impl ResultExt for std::result::Result +impl ResultExt for core::result::Result where E: Error, { @@ -55,7 +55,7 @@ where } } -impl ResultExt for std::result::Result> +impl ResultExt for core::result::Result> where E: Error, { From b522503fc40cd19ddfd6f6b983f382f64e17ec82 Mon Sep 17 00:00:00 2001 From: Olivier Pinon Date: Thu, 8 Jan 2026 22:19:31 +0100 Subject: [PATCH 2/7] Replace more std:: usage with core:: --- exn/Cargo.toml | 2 +- exn/src/impls.rs | 6 +++--- exn/src/lib.rs | 18 +++++++++--------- exn/src/macros.rs | 8 ++++---- exn/tests/simple.rs | 6 +++--- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/exn/Cargo.toml b/exn/Cargo.toml index 8380748..233f35f 100644 --- a/exn/Cargo.toml +++ b/exn/Cargo.toml @@ -16,7 +16,7 @@ name = "exn" version = "0.2.1" -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/impls.rs b/exn/src/impls.rs index bd184f9..b14064c 100644 --- a/exn/src/impls.rs +++ b/exn/src/impls.rs @@ -44,7 +44,7 @@ impl Exn { /// /// See also [`Error::raise`] for a fluent way to convert an error into an `Exn` instance. /// - /// [source chain of the error]: std::error::Error::source + /// [source chain of the error]: core::error::Error::source #[track_caller] pub fn new(error: E) -> Self { struct SourceError(String); @@ -142,12 +142,12 @@ pub struct Frame { } impl Frame { - /// Return the error as a reference to [`std::any::Any`]. + /// Return the error as a reference to [`core::any::Any`]. pub fn as_any(&self) -> &dyn core::any::Any { &*self.error } - /// Return the error as a reference to [`std::error::Error`]. + /// Return the error as a reference to [`core::error::Error`]. pub fn as_error(&self) -> &dyn core::error::Error { &*self.error } diff --git a/exn/src/lib.rs b/exn/src/lib.rs index 423ae4b..5440f9b 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 { @@ -113,13 +113,13 @@ impl Error for T where T: core::error::Error + core::any::Any + Send + Sync + /// 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/macros.rs b/exn/src/macros.rs index 0778526..f20cc3e 100644 --- a/exn/src/macros.rs +++ b/exn/src/macros.rs @@ -21,7 +21,7 @@ /// Create an [`Exn`] from [`Error`]: /// /// [`Exn`]: crate::Exn -/// [`Error`]: std::error::Error +/// [`Error`]: core::error::Error /// /// ``` /// use std::fs; @@ -37,7 +37,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 +50,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,7 +58,7 @@ macro_rules! bail { /// # let user = 0; /// # type Resource = u32; /// # let resource = 0; -/// use std::error::Error; +/// use core::error::Error; /// use std::fmt; /// /// use exn::ensure; diff --git a/exn/tests/simple.rs b/exn/tests/simple.rs index 72c9685..b3b6d40 100644 --- a/exn/tests/simple.rs +++ b/exn/tests/simple.rs @@ -20,13 +20,13 @@ use exn::ResultExt; #[derive(Debug)] struct SimpleError(&'static str); -impl std::fmt::Display for SimpleError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl core::fmt::Display for SimpleError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{}", self.0) } } -impl std::error::Error for SimpleError {} +impl core::error::Error for SimpleError {} #[test] fn test_error_straightforward() { From 250923a895d9d78d224ed82885dd0a403c31f554 Mon Sep 17 00:00:00 2001 From: tison Date: Sun, 18 Jan 2026 21:57:20 +0800 Subject: [PATCH 3/7] Revert "Replace more std:: usage with core::" This reverts commit b522503fc40cd19ddfd6f6b983f382f64e17ec82. --- exn/Cargo.toml | 2 +- exn/src/impls.rs | 6 +++--- exn/src/lib.rs | 18 +++++++++--------- exn/src/macros.rs | 8 ++++---- exn/tests/simple.rs | 6 +++--- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/exn/Cargo.toml b/exn/Cargo.toml index 233f35f..8380748 100644 --- a/exn/Cargo.toml +++ b/exn/Cargo.toml @@ -16,7 +16,7 @@ name = "exn" version = "0.2.1" -description = "A context-aware concrete Error type built on `core::error::Error`." +description = "A context-aware concrete Error type built on `std::error::Error`." edition.workspace = true homepage.workspace = true diff --git a/exn/src/impls.rs b/exn/src/impls.rs index b14064c..bd184f9 100644 --- a/exn/src/impls.rs +++ b/exn/src/impls.rs @@ -44,7 +44,7 @@ impl Exn { /// /// See also [`Error::raise`] for a fluent way to convert an error into an `Exn` instance. /// - /// [source chain of the error]: core::error::Error::source + /// [source chain of the error]: std::error::Error::source #[track_caller] pub fn new(error: E) -> Self { struct SourceError(String); @@ -142,12 +142,12 @@ pub struct Frame { } impl Frame { - /// Return the error as a reference to [`core::any::Any`]. + /// Return the error as a reference to [`std::any::Any`]. pub fn as_any(&self) -> &dyn core::any::Any { &*self.error } - /// Return the error as a reference to [`core::error::Error`]. + /// Return the error as a reference to [`std::error::Error`]. pub fn as_error(&self) -> &dyn core::error::Error { &*self.error } diff --git a/exn/src/lib.rs b/exn/src/lib.rs index 5440f9b..423ae4b 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 `core::error::Error` +//! A context-aware concrete Error type built on `std::error::Error` //! //! # Examples //! @@ -25,13 +25,13 @@ //! #[derive(Debug)] //! struct LogicError(String); //! -//! impl core::fmt::Display for LogicError { -//! fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { +//! impl std::fmt::Display for LogicError { +//! fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { //! write!(f, "logic error: {}", self.0) //! } //! } //! -//! impl core::error::Error for LogicError {} +//! impl std::error::Error for LogicError {} //! //! fn do_logic() -> Result<(), LogicError> { //! bail!(LogicError("0 == 1".to_string())); @@ -44,8 +44,8 @@ //! Trivial, //! } //! -//! impl core::fmt::Display for AppError { -//! fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { +//! impl std::fmt::Display for AppError { +//! fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { //! match self { //! AppError::Fatal { consequences } => write!(f, "fatal error: {consequences}"), //! AppError::Trivial => write!(f, "trivial error"), @@ -53,7 +53,7 @@ //! } //! } //! -//! impl core::error::Error for AppError {} +//! impl std::error::Error for AppError {} //! //! fn main() { //! if let Err(err) = do_logic().or_raise(|| AppError::Fatal { @@ -113,13 +113,13 @@ impl Error for T where T: core::error::Error + core::any::Any + Send + Sync + /// One might think that `exn::Result::Ok(value)` would work in such cases, but it does not. /// /// ```console -/// error[E0282]: type annotations needed for `core::result::Result` +/// error[E0282]: type annotations needed for `std::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 `core::result::Result`, where the type parameter `E` is specified +/// | consider giving this pattern the explicit type `std::result::Result`, where the type parameter `E` is specified /// ``` #[expect(non_snake_case)] pub fn Ok(value: T) -> Result { diff --git a/exn/src/macros.rs b/exn/src/macros.rs index f20cc3e..0778526 100644 --- a/exn/src/macros.rs +++ b/exn/src/macros.rs @@ -21,7 +21,7 @@ /// Create an [`Exn`] from [`Error`]: /// /// [`Exn`]: crate::Exn -/// [`Error`]: core::error::Error +/// [`Error`]: std::error::Error /// /// ``` /// use std::fs; @@ -37,7 +37,7 @@ #[macro_export] macro_rules! bail { ($err:expr) => {{ - return ::core::result::Result::Err($crate::Exn::from($err)); + return ::std::result::Result::Err($crate::Exn::from($err)); }}; } @@ -50,7 +50,7 @@ macro_rules! bail { /// Create an [`Exn`] from an [`Error`]: /// /// [`Exn`]: crate::Exn -/// [`Error`]: core::error::Error +/// [`Error`]: std::error::Error /// /// ``` /// # fn has_permission(_: &u32, _: &u32) -> bool { true } @@ -58,7 +58,7 @@ macro_rules! bail { /// # let user = 0; /// # type Resource = u32; /// # let resource = 0; -/// use core::error::Error; +/// use std::error::Error; /// use std::fmt; /// /// use exn::ensure; diff --git a/exn/tests/simple.rs b/exn/tests/simple.rs index b3b6d40..72c9685 100644 --- a/exn/tests/simple.rs +++ b/exn/tests/simple.rs @@ -20,13 +20,13 @@ use exn::ResultExt; #[derive(Debug)] struct SimpleError(&'static str); -impl core::fmt::Display for SimpleError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { +impl std::fmt::Display for SimpleError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } -impl core::error::Error for SimpleError {} +impl std::error::Error for SimpleError {} #[test] fn test_error_straightforward() { From ad47287d87d894523c356fb0e42ecaec8996ef15 Mon Sep 17 00:00:00 2001 From: tison Date: Sun, 18 Jan 2026 21:57:28 +0800 Subject: [PATCH 4/7] Revert "Support for #![no_std]" This reverts commit 4f0da29bef69c0d002f7def30dcac31d92b6e8a7. --- exn/src/debug.rs | 8 +++----- exn/src/display.rs | 2 +- exn/src/impls.rs | 25 +++++++++---------------- exn/src/lib.rs | 7 ++----- exn/src/result.rs | 6 +++--- 5 files changed, 18 insertions(+), 30 deletions(-) diff --git a/exn/src/debug.rs b/exn/src/debug.rs index 974c6f6..e45ea7e 100644 --- a/exn/src/debug.rs +++ b/exn/src/debug.rs @@ -12,10 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use core::fmt; -use core::fmt::Formatter; - -use alloc::format; +use std::fmt; +use std::fmt::Formatter; use crate::Error; use crate::Exn; @@ -74,8 +72,8 @@ fn write_location(f: &mut Formatter<'_>, exn: &Frame) -> fmt::Result { let location = exn.location(); use std::os::windows::ffi::OsStrExt; use std::path::Component; - use std::path::Path; use std::path::MAIN_SEPARATOR; + use std::path::Path; let file = location.file(); let path = Path::new(file); diff --git a/exn/src/display.rs b/exn/src/display.rs index 621c618..7b839d6 100644 --- a/exn/src/display.rs +++ b/exn/src/display.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use core::fmt; +use std::fmt; use crate::Error; use crate::Exn; diff --git a/exn/src/impls.rs b/exn/src/impls.rs index bd184f9..fadf1fb 100644 --- a/exn/src/impls.rs +++ b/exn/src/impls.rs @@ -12,13 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -use core::fmt; -use core::marker::PhantomData; -use core::panic::Location; - -use alloc::boxed::Box; -use alloc::string::{String, ToString}; -use alloc::vec::Vec; +use std::fmt; +use std::marker::PhantomData; +use std::panic::Location; use crate::Error; @@ -61,21 +57,18 @@ impl Exn { } } - impl core::error::Error for SourceError {} + impl std::error::Error for SourceError {} - fn walk( - error: &dyn core::error::Error, - location: &'static Location<'static>, - ) -> Vec { + fn walk(error: &dyn std::error::Error, location: &'static Location<'static>) -> Vec { if let Some(source) = error.source() { - let children = alloc::vec![Frame { + let children = vec![Frame { error: Box::new(SourceError(source.to_string())), location, children: walk(source, location), }]; children } else { - alloc::vec![] + vec![] } } @@ -143,12 +136,12 @@ pub struct Frame { impl Frame { /// Return the error as a reference to [`std::any::Any`]. - pub fn as_any(&self) -> &dyn core::any::Any { + pub fn as_any(&self) -> &dyn std::any::Any { &*self.error } /// Return the error as a reference to [`std::error::Error`]. - pub fn as_error(&self) -> &dyn core::error::Error { + pub fn as_error(&self) -> &dyn std::error::Error { &*self.error } diff --git a/exn/src/lib.rs b/exn/src/lib.rs index 423ae4b..c3cc71b 100644 --- a/exn/src/lib.rs +++ b/exn/src/lib.rs @@ -74,9 +74,6 @@ #![cfg_attr(docsrs, feature(doc_cfg))] #![deny(missing_docs)] -#![no_std] - -extern crate alloc; mod debug; mod display; @@ -92,7 +89,7 @@ pub use self::result::Result; pub use self::result::ResultExt; /// A trait bound of the supported error type of [`Exn`]. -pub trait Error: core::error::Error + core::any::Any + Send + Sync + 'static { +pub trait Error: std::error::Error + std::any::Any + Send + Sync + 'static { /// Raise this error as a new exception. #[track_caller] fn raise(self) -> Exn @@ -103,7 +100,7 @@ pub trait Error: core::error::Error + core::any::Any + Send + Sync + 'static { } } -impl Error for T where T: core::error::Error + core::any::Any + Send + Sync + 'static {} +impl Error for T where T: std::error::Error + std::any::Any + Send + Sync + 'static {} /// Equivalent to `Ok::<_, Exn>(value)`. /// diff --git a/exn/src/result.rs b/exn/src/result.rs index c62921b..8d58548 100644 --- a/exn/src/result.rs +++ b/exn/src/result.rs @@ -16,7 +16,7 @@ use crate::Error; use crate::Exn; /// A reasonable return type to use throughout an application. -pub type Result = core::result::Result>; +pub type Result = std::result::Result>; /// An extension trait for [`Result`] to provide context information on [`Exn`]s. pub trait ResultExt { @@ -35,7 +35,7 @@ pub trait ResultExt { F: FnOnce() -> A; } -impl ResultExt for core::result::Result +impl ResultExt for std::result::Result where E: Error, { @@ -55,7 +55,7 @@ where } } -impl ResultExt for core::result::Result> +impl ResultExt for std::result::Result> where E: Error, { From 282e3dc450de3dfa426b807c5393f6e9d9816711 Mon Sep 17 00:00:00 2001 From: tison Date: Sun, 18 Jan 2026 22:01:05 +0800 Subject: [PATCH 5/7] no_std Signed-off-by: tison --- README.md | 4 ++-- examples/Cargo.toml | 4 ++-- examples/src/{anti-pattern.rs => antipattern.rs} | 6 +++--- examples/src/make-error.rs | 2 +- exn/Cargo.toml | 2 +- exn/src/debug.rs | 4 ++-- exn/src/display.rs | 4 ++-- exn/src/ext.rs | 6 +++--- exn/src/impls.rs | 8 ++++---- exn/src/lib.rs | 14 +++++++------- exn/src/macros.rs | 14 +++++++------- exn/src/option.rs | 2 +- exn/src/result.rs | 8 ++++---- exn/tests/simple.rs | 6 +++--- xtask/src/main.rs | 8 ++++---- 15 files changed, 46 insertions(+), 46 deletions(-) rename examples/src/{anti-pattern.rs => antipattern.rs} (95%) diff --git a/README.md b/README.md index 0f172c8..9c3d6a7 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. 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..e7aa547 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:35:16 // | -// |-> failed to send request, at examples/src/anti-pattern.rs:49:30 +// |-> failed to send request, at examples/src/antipattern: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..dd794ac 100644 --- a/exn/src/debug.rs +++ b/exn/src/debug.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/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..2956b36 100644 --- a/exn/src/impls.rs +++ b/exn/src/impls.rs @@ -12,10 +12,10 @@ // 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 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..9a6ad0e 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 { diff --git a/exn/src/macros.rs b/exn/src/macros.rs index 327cbe7..f9c8e07 100644 --- a/exn/src/macros.rs +++ b/exn/src/macros.rs @@ -21,13 +21,13 @@ /// Create an [`Exn`] from [`Error`]: /// /// [`Exn`]: crate::Exn -/// [`Error`]: std::error::Error +/// [`Error`]: core::error::Error /// /// ``` -/// use std::fs; +/// use core::fs; /// /// use exn::bail; -/// # fn wrapper() -> exn::Result<(), std::io::Error> { +/// # fn wrapper() -> exn::Result<(), core::io::Error> { /// match fs::read_to_string("/path/to/file") { /// Ok(content) => println!("file contents: {content}"), /// Err(err) => bail!(err), @@ -37,7 +37,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 +50,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 +58,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, { diff --git a/exn/tests/simple.rs b/exn/tests/simple.rs index 0c91dae..8233347 100644 --- a/exn/tests/simple.rs +++ b/exn/tests/simple.rs @@ -20,13 +20,13 @@ use exn::ResultExt; #[derive(Debug)] struct SimpleError(&'static str); -impl std::fmt::Display for SimpleError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl core::fmt::Display for SimpleError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{}", self.0) } } -impl std::error::Error for SimpleError {} +impl core::error::Error for SimpleError {} #[test] fn test_error_straightforward() { diff --git a/xtask/src/main.rs b/xtask/src/main.rs index ff47c44..bc5023a 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::fs; -use std::path::PathBuf; -use std::process::Command as StdCommand; +use core::fs; +use core::path::PathBuf; +use core::process::Command as StdCommand; use clap::Parser; use clap::Subcommand; @@ -142,7 +142,7 @@ fn run_example_tests() { eprintln!("\nexample: {}", path.display()); eprintln!("actual stderr:\n{}", actual); } - std::process::exit(1); + core::process::exit(1); } else { println!("all {} example tests passed", total); } From a05cbcd4908252dd6b4a10f90686094c9aab592e Mon Sep 17 00:00:00 2001 From: tison Date: Sun, 18 Jan 2026 22:12:03 +0800 Subject: [PATCH 6/7] Add changelog Signed-off-by: tison --- CHANGELOG.md | 15 +++++++++++++++ examples/src/antipattern.rs | 4 ++-- exn/src/debug.rs | 1 + exn/src/impls.rs | 5 +++++ exn/src/lib.rs | 3 +++ exn/src/macros.rs | 5 +++-- exn/tests/simple.rs | 6 +++--- xtask/src/main.rs | 8 ++++---- 8 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..f0fc267 --- /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 crate still depends on the `alloc` crate for heap allocations. It is worth noting that `no_std` support is a nice-to-have feature now, and can be dropped if it blocks other important features in the future. Before 1.0, once the exn APIs settle down, the decision on whether to keep `no_std` as a promise will be finalized. diff --git a/examples/src/antipattern.rs b/examples/src/antipattern.rs index e7aa547..f4a8516 100644 --- a/examples/src/antipattern.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/antipattern:35:16 +// Error: fatal error occurred in application, at examples/src/antipattern.rs:35:16 // | -// |-> failed to send request, at examples/src/antipattern: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/antipattern.rs:67:9 diff --git a/exn/src/debug.rs b/exn/src/debug.rs index dd794ac..353a2d6 100644 --- a/exn/src/debug.rs +++ b/exn/src/debug.rs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use alloc::format; use core::error::Error; use core::fmt; diff --git a/exn/src/impls.rs b/exn/src/impls.rs index 2956b36..1aa007e 100644 --- a/exn/src/impls.rs +++ b/exn/src/impls.rs @@ -12,6 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +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; diff --git a/exn/src/lib.rs b/exn/src/lib.rs index 9a6ad0e..dfd97ed 100644 --- a/exn/src/lib.rs +++ b/exn/src/lib.rs @@ -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 f9c8e07..2908ad2 100644 --- a/exn/src/macros.rs +++ b/exn/src/macros.rs @@ -24,10 +24,11 @@ /// [`Error`]: core::error::Error /// /// ``` -/// use core::fs; +/// use std::fs; /// /// use exn::bail; -/// # fn wrapper() -> exn::Result<(), core::io::Error> { +/// +/// # fn wrapper() -> exn::Result<(), std::io::Error> { /// match fs::read_to_string("/path/to/file") { /// Ok(content) => println!("file contents: {content}"), /// Err(err) => bail!(err), diff --git a/exn/tests/simple.rs b/exn/tests/simple.rs index 8233347..0c91dae 100644 --- a/exn/tests/simple.rs +++ b/exn/tests/simple.rs @@ -20,13 +20,13 @@ use exn::ResultExt; #[derive(Debug)] struct SimpleError(&'static str); -impl core::fmt::Display for SimpleError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { +impl std::fmt::Display for SimpleError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } -impl core::error::Error for SimpleError {} +impl std::error::Error for SimpleError {} #[test] fn test_error_straightforward() { diff --git a/xtask/src/main.rs b/xtask/src/main.rs index bc5023a..ff47c44 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -use core::fs; -use core::path::PathBuf; -use core::process::Command as StdCommand; +use std::fs; +use std::path::PathBuf; +use std::process::Command as StdCommand; use clap::Parser; use clap::Subcommand; @@ -142,7 +142,7 @@ fn run_example_tests() { eprintln!("\nexample: {}", path.display()); eprintln!("actual stderr:\n{}", actual); } - core::process::exit(1); + std::process::exit(1); } else { println!("all {} example tests passed", total); } From f3d90cce869883c7c61cc3e1db06bf42d90f4537 Mon Sep 17 00:00:00 2001 From: tison Date: Sun, 18 Jan 2026 22:22:56 +0800 Subject: [PATCH 7/7] add docs Signed-off-by: tison --- CHANGELOG.md | 2 +- README.md | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0fc267..43d6f08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,4 +12,4 @@ All significant changes to this project will be documented in this file. ### New Features -* This crate is now `no_std` compatible, while the crate still depends on the `alloc` crate for heap allocations. It is worth noting that `no_std` support is a nice-to-have feature now, and can be dropped if it blocks other important features in the future. Before 1.0, once the exn APIs settle down, the decision on whether to keep `no_std` as a promise will be finalized. +* 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 9c3d6a7..af7a39d 100644 --- a/README.md +++ b/README.md @@ -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).