diff --git a/Cargo.toml b/Cargo.toml index 20b099ff7..351780c4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,9 @@ repository = "https://github.com/brson/error-chain" license = "MIT/Apache-2.0" [features] -default = ["backtrace", "example_generated"] +default = ["backtrace", "example_generated", "alloc"] example_generated = [] +alloc = [] [dependencies] backtrace = { version = "0.3", optional = true } diff --git a/examples/all.rs b/ex/all.rs similarity index 100% rename from examples/all.rs rename to ex/all.rs diff --git a/examples/doc.rs b/ex/doc.rs similarity index 100% rename from examples/doc.rs rename to ex/doc.rs diff --git a/examples/quickstart.rs b/ex/quickstart.rs similarity index 100% rename from examples/quickstart.rs rename to ex/quickstart.rs diff --git a/examples/size.rs b/ex/size.rs similarity index 100% rename from examples/size.rs rename to ex/size.rs diff --git a/src/error_chain.rs b/src/error_chain.rs index 5555904db..94d88889b 100644 --- a/src/error_chain.rs +++ b/src/error_chain.rs @@ -27,7 +27,7 @@ macro_rules! error_chain_processed { $( $rest )* } /// Convenient wrapper around `std::Result`. - pub type $result_name = ::std::result::Result; + pub type $result_name = $crate::Result; }; // Without `Result` wrapper. ( @@ -109,13 +109,13 @@ macro_rules! error_chain_processed { } } - impl ::std::error::Error for $error_name { + impl $crate::Error for $error_name { fn description(&self) -> &str { self.kind.description() } - fn cause(&self) -> Option<&::std::error::Error> { - match self.state.next_error { + fn cause(&self) -> Option<&$crate::Error> { + match self.state.next_error() { Some(ref c) => Some(&**c), None => { match self.kind { @@ -132,11 +132,7 @@ macro_rules! error_chain_processed { } } - impl ::std::fmt::Display for $error_name { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - ::std::fmt::Display::fmt(&self.kind, f) - } - } + if_alloc!($error_name $error_kind_name); $( $(#[$meta_links])* @@ -179,14 +175,6 @@ macro_rules! error_chain_processed { } } - impl ::std::ops::Deref for $error_name { - type Target = $error_kind_name; - - fn deref(&self) -> &Self::Target { - &self.kind - } - } - // The ErrorKind type // -------------- @@ -213,7 +201,7 @@ macro_rules! error_chain_processed { $( $(#[$meta_foreign_links])* $foreign_link_variant(err: $foreign_link_error_path) { - description(::std::error::Error::description(err)) + description($crate::Error::description(err)) display("{}", err) } ) * @@ -329,7 +317,7 @@ macro_rules! impl_extract_backtrace { ($error_name: ident $error_kind_name: ident $([$link_error_path: path, $(#[$meta_links: meta])*])*) => { - fn extract_backtrace(e: &(::std::error::Error + Send + 'static)) + fn extract_backtrace(e: &($crate::Error + Send + 'static)) -> Option>> { if let Some(e) = e.downcast_ref::<$error_name>() { return Some(e.state.backtrace.clone()); @@ -360,3 +348,31 @@ macro_rules! impl_extract_backtrace { $error_kind_name: ident $([$link_error_path: path, $(#[$meta_links: meta])*])*) => {} } + +#[macro_export] +#[doc(hidden)] +#[cfg(feature = "alloc")] +macro_rules! if_alloc { + ($error_name:ident $error_kind_name: ident) => { + impl ::std::fmt::Display for $error_name { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::std::fmt::Display::fmt(&self.kind, f) + } + } + + impl ::std::ops::Deref for $error_name { + type Target = $error_kind_name; + + fn deref(&self) -> &Self::Target { + &self.kind + } + } + } +} + +#[macro_export] +#[doc(hidden)] +#[cfg(not(feature = "alloc"))] +macro_rules! if_alloc { + ($error_name:ident $error_kind_name: ident) => {} +} diff --git a/src/lib.rs b/src/lib.rs index b1a0de848..0350ac889 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,3 @@ -#![warn(missing_docs)] - //! A library for consistent and reliable error handling //! //! This crate defines an opinionated strategy for error handling in Rust, @@ -251,13 +249,35 @@ //! [error-type]: https://github.com/DanielKeep/rust-error-type //! [quick-error]: https://github.com/tailhook/quick-error +#![warn(missing_docs)] +#![cfg_attr(not(feature = "alloc"), no_std)] + #[cfg(feature = "backtrace")] extern crate backtrace; -use std::error; -use std::iter::Iterator; -#[cfg(feature = "backtrace")] -use std::sync::Arc; +#[cfg(feature = "alloc")] +mod alloc { + pub use std::error; + pub use std::iter::Iterator; + #[cfg(feature = "backtrace")] + pub use std::sync::Arc; + pub use std::result::Result; +} +#[cfg(not(feature = "alloc"))] +mod alloc { + pub use core::iter::Iterator; + pub type Box = ::core::marker::PhantomData; + pub use core::result::Result; + + pub trait Error { + fn description(&self) -> &str; + + fn cause(&self) -> Option<&Error>; + } +} +// For use in the expanded macro. +#[doc(hidden)] +pub use alloc::*; #[cfg(feature = "backtrace")] pub use backtrace::Backtrace; @@ -273,12 +293,12 @@ mod error_chain; pub mod example_generated; /// Iterator over the error chain using the `Error::cause()` method. -pub struct ErrorChainIter<'a>(pub Option<&'a error::Error>); +pub struct ErrorChainIter<'a>(pub Option<&'a Error>); impl<'a> Iterator for ErrorChainIter<'a> { - type Item = &'a error::Error; + type Item = &'a Error; - fn next<'b>(&'b mut self) -> Option<&'a error::Error> { + fn next<'b>(&'b mut self) -> Option<&'a Error> { match self.0.take() { Some(e) => { self.0 = e.cause(); @@ -303,7 +323,7 @@ pub fn make_backtrace() -> Option> { /// This trait is implemented on all the errors generated by the `error_chain` /// macro. -pub trait ChainedError: error::Error + Send + 'static { +pub trait ChainedError: Error + Send + 'static { /// Associated kind type. type ErrorKind; @@ -315,7 +335,7 @@ pub trait ChainedError: error::Error + Send + 'static { /// of the errors from `foreign_links`. #[cfg(feature = "backtrace")] #[doc(hidden)] - fn extract_backtrace(e: &(error::Error + Send + 'static)) + fn extract_backtrace(e: &(Error + Send + 'static)) -> Option>>; } @@ -345,10 +365,12 @@ impl ResultExt for Result where CE: ChainedError, E: I backtrace: backtrace, }) }; - #[cfg(not(feature = "backtrace"))] + #[cfg(all(not(feature = "backtrace"), feature = "alloc"))] let error = CE::new(callback().into(), State { next_error: Some(Box::new(e)), }); + #[cfg(not(feature = "alloc"))] + let error = CE::new(callback().into(), State {}); error }) } @@ -360,10 +382,11 @@ impl ResultExt for Result where CE: ChainedError, E: I #[doc(hidden)] pub struct State { /// Next error in the error chain. - pub next_error: Option>, + #[cfg(feature = "alloc")] + next_error: Option>, /// Backtrace for the current error. #[cfg(feature = "backtrace")] - pub backtrace: Option>, + backtrace: Option>, } impl Default for State { @@ -373,10 +396,12 @@ impl Default for State { next_error: None, backtrace: make_backtrace(), }; - #[cfg(not(feature = "backtrace"))] + #[cfg(all(not(feature = "backtrace"), feature = "alloc"))] let state = State { next_error: None, }; + #[cfg(not(feature = "alloc"))] + let state = State {}; state } } @@ -390,4 +415,12 @@ impl State { let b = None; b } + + pub fn next_error(&self) -> Option> { + #[cfg(feature = "alloc")] + let next = self.next_error; + #[cfg(not(feature = "alloc"))] + let next = None; + next + } }