Skip to content
This repository was archived by the owner on Aug 16, 2021. It is now read-only.

Commit f83806d

Browse files
committed
[WIP] Core support
Fixes #37.
1 parent 8058642 commit f83806d

File tree

5 files changed

+160
-71
lines changed

5 files changed

+160
-71
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ repository = "https://github.com/brson/error-chain"
1414
license = "MIT OR Apache-2.0"
1515

1616
[features]
17-
default = ["backtrace"]
17+
default = ["backtrace", "alloc"]
18+
alloc = []
1819

1920
[dependencies]
2021
backtrace = {version = "0.2.1", optional = true}

examples/size.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ fn main() {
3030
println!(" State.next_error: {}", size_of_val(&state.next_error));
3131
println!(" State.backtrace: {}", size_of_val(&state.backtrace));
3232
}
33-
#[cfg(not(feature = "backtrace"))]
33+
#[cfg(all(not(feature = "backtrace"), feature = "alloc"))]
3434
{
3535
let state = error_chain::State {
3636
next_error: None,

src/error_chain.rs

Lines changed: 82 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ macro_rules! error_chain_processed {
2626
$( $rest )*
2727
}
2828
/// Convenient wrapper around `std::Result`.
29-
pub type $result_name<T> = ::std::result::Result<T, $error_name>;
29+
pub type $result_name<T> = $crate::std::result::Result<T, $error_name>;
3030
};
3131
(
3232
types {
@@ -81,26 +81,16 @@ macro_rules! error_chain_processed {
8181
}
8282
}
8383

84-
impl ::std::error::Error for $error_name {
84+
impl $crate::Error for $error_name {
8585
fn description(&self) -> &str {
8686
self.kind.description()
8787
}
8888

89-
fn cause(&self) -> Option<&::std::error::Error> {
90-
match self.state.next_error {
91-
Some(ref c) => Some(&**c),
92-
None => {
93-
match self.kind {
94-
$(
95-
$(#[$meta_foreign_links])*
96-
$error_kind_name::$foreign_link_variant(ref foreign_err) => {
97-
foreign_err.cause()
98-
}
99-
) *
100-
_ => None
101-
}
102-
}
103-
}
89+
impl_cause! {
90+
$error_kind_name
91+
$( $foreign_link_error_path,
92+
$foreign_link_variant
93+
$(, #[$meta_foreign_links])*; )*
10494
}
10595
}
10696

@@ -168,11 +158,7 @@ macro_rules! error_chain_processed {
168158
#[derive(Debug)]
169159
pub enum $error_kind_name {
170160

171-
/// A convenient variant for String.
172-
Msg(s: String) {
173-
description(&s)
174-
display("{}", s)
175-
}
161+
variant_string! {}
176162

177163
$(
178164
$(#[$meta_links])*
@@ -185,7 +171,7 @@ macro_rules! error_chain_processed {
185171
$(
186172
$(#[$meta_foreign_links])*
187173
$foreign_link_variant(err: $foreign_link_error_path) {
188-
description(::std::error::Error::description(err))
174+
description($crate::Error::description(err))
189175
display("{}", err)
190176
}
191177
) *
@@ -360,3 +346,76 @@ macro_rules! impl_error {
360346
}
361347
}
362348
}
349+
350+
#[macro_export]
351+
#[doc(hidden)]
352+
#[cfg(feature = "alloc")]
353+
macro_rules! impl_cause {
354+
(
355+
$error_kind_name: ident
356+
$( $foreign_link_error_path:path,
357+
$foreign_link_variant:ident
358+
$(, #[$meta_foreign_links:meta])*; )*
359+
) => {
360+
fn cause(&self) -> Option<&$crate::Error> {
361+
match self.state.next_error {
362+
Some(ref c) => Some(&**c),
363+
None => {
364+
match self.kind {
365+
$(
366+
$(#[$meta_foreign_links])*
367+
$error_kind_name::$foreign_link_variant(ref foreign_err) => {
368+
foreign_err.cause()
369+
}
370+
) *
371+
_ => None
372+
}
373+
}
374+
}
375+
}
376+
}
377+
}
378+
379+
#[macro_export]
380+
#[doc(hidden)]
381+
#[cfg(not(feature = "alloc"))]
382+
macro_rules! impl_cause {
383+
(
384+
$error_kind_name: ident
385+
$( $foreign_link_error_path:path,
386+
$foreign_link_variant:ident
387+
$(, #[$meta_foreign_links:meta])*; )*
388+
) => {
389+
fn cause(&self) -> Option<&$crate::Error> {
390+
match self.kind {
391+
$(
392+
$(#[$meta_foreign_links])*
393+
$error_kind_name::$foreign_link_variant(ref foreign_err) => {
394+
foreign_err.cause()
395+
}
396+
) *
397+
_ => None
398+
}
399+
}
400+
}
401+
}
402+
403+
#[macro_export]
404+
#[doc(hidden)]
405+
#[cfg(feature = "alloc")]
406+
macro_rules! variant_string {
407+
() => {
408+
/// A convenient variant for String.
409+
Msg(s: String) {
410+
description(&s)
411+
display("{}", s)
412+
}
413+
}
414+
}
415+
416+
#[macro_export]
417+
#[doc(hidden)]
418+
#[cfg(not(feature = "alloc"))]
419+
macro_rules! variant_string {
420+
() => {}
421+
}

src/lib.rs

Lines changed: 70 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![warn(missing_docs)]
2+
#![cfg_attr(not(feature = "alloc"), no_std)]
23

34
//! A library for consistent and reliable error handling
45
//!
@@ -28,12 +29,12 @@
2829
//! * Instead of defining the custom `Error` type as an enum, it is a
2930
//! struct containing an `ErrorKind` (which defines the
3031
//! `description` and `display` methods for the error), an opaque,
31-
//! optional, boxed `std::error::Error + Send + 'static` object
32+
//! optional, boxed `self::std::error::Error + Send + 'static` object
3233
//! (which defines the `cause`, and establishes the links in the
3334
//! error chain), and a `Backtrace`.
3435
//! * This crate additionally defines the trait `ResultExt`
3536
//! that defines a `chain_err` method. This method
36-
//! on all `std::error::Error + Send + 'static` types extends
37+
//! on all `self::std::error::Error + Send + 'static` types extends
3738
//! the error chain by boxing the current error into an opaque
3839
//! object and putting it inside a new concrete error.
3940
//! * It provides automatic `From` conversions between other error types
@@ -53,7 +54,7 @@
5354
//! errors, requiring an `Into` or `From` conversion; as well as
5455
//! slightly more cumbersome to match on errors with another layer
5556
//! of types to match.
56-
//! * Because the error type contains `std::error::Error + Send + 'static` objects,
57+
//! * Because the error type contains `self::std::error::Error + Send + 'static` objects,
5758
//! it can't implement `PartialEq` for easy comparisons.
5859
//!
5960
//! ## Quick start
@@ -182,8 +183,8 @@
182183
//! following:
183184
//!
184185
//! ```ignore
185-
//! use std::error::Error as StdError;
186-
//! use std::sync::Arc;
186+
//! use self::std::error::Error as StdError;
187+
//! use self::std::sync::Arc;
187188
//!
188189
//! #[derive(Debug)]
189190
//! pub struct Error(pub ErrorKind,
@@ -248,7 +249,7 @@
248249
//!
249250
//! Note that the return type is the typedef `Result`, which is
250251
//! defined by the macro as `pub type Result<T> =
251-
//! ::std::result::Result<T, Error>`. Note that in both cases
252+
//! ::self::std::result::Result<T, Error>`. Note that in both cases
252253
//! `.into()` is called to convert a type into the `Error` type; both
253254
//! strings and `ErrorKind` have `From` conversions to turn them into
254255
//! `Error`.
@@ -278,7 +279,7 @@
278279
//! ```
279280
//!
280281
//! `chain_err` can be called on any `Result` type where the contained
281-
//! error type implements `std::error::Error + Send + 'static`. If
282+
//! error type implements `self::std::error::Error + Send + 'static`. If
282283
//! the `Result` is an `Err` then `chain_err` evaluates the closure,
283284
//! which returns *some type that can be converted to `ErrorKind`*,
284285
//! boxes the original error to store as the cause, then returns a new
@@ -324,10 +325,14 @@
324325
#[cfg(feature = "backtrace")]
325326
extern crate backtrace;
326327

327-
use std::error;
328-
use std::iter::Iterator;
328+
#[cfg(feature = "alloc")]
329+
pub use std;
330+
#[cfg(not(feature = "alloc"))]
331+
pub extern crate core as std;
332+
333+
use self::std::iter::Iterator;
329334
#[cfg(feature = "backtrace")]
330-
use std::sync::Arc;
335+
use self::std::sync::Arc;
331336

332337
#[cfg(feature = "backtrace")]
333338
pub use backtrace::Backtrace;
@@ -336,12 +341,12 @@ mod quick_error;
336341
mod error_chain;
337342

338343
/// Iterator over the error chain.
339-
pub struct ErrorChainIter<'a>(pub Option<&'a error::Error>);
344+
pub struct ErrorChainIter<'a>(pub Option<&'a Error>);
340345

341346
impl<'a> Iterator for ErrorChainIter<'a> {
342-
type Item = &'a error::Error;
347+
type Item = &'a Error;
343348

344-
fn next<'b>(&'b mut self) -> Option<&'a error::Error> {
349+
fn next<'b>(&'b mut self) -> Option<&'a Error> {
345350
match self.0.take() {
346351
Some(e) => {
347352
self.0 = e.cause();
@@ -358,65 +363,81 @@ impl<'a> Iterator for ErrorChainIter<'a> {
358363
#[cfg(feature = "backtrace")]
359364
#[doc(hidden)]
360365
pub fn make_backtrace() -> Option<Arc<Backtrace>> {
361-
match std::env::var_os("RUST_BACKTRACE") {
366+
match self::std::env::var_os("RUST_BACKTRACE") {
362367
Some(ref val) if val != "0" => Some(Arc::new(Backtrace::new())),
363368
_ => None
364369
}
365370
}
366371

367372
/// This trait is implemented on all the errors generated by the `error_chain`
368373
/// macro.
369-
pub trait ChainedError: error::Error + Send + 'static {
374+
pub trait ChainedError: Error + Send + 'static {
370375
/// Associated kind type.
371376
type ErrorKind;
372377
/// Creates an error from it's parts.
373378
fn new(kind: Self::ErrorKind, state: State) -> Self;
374379
/// Returns the first known backtrace, either from it's State or from one
375380
/// of the errors from `foreign_links`.
376381
#[cfg(feature = "backtrace")]
377-
fn extract_backtrace(e: &(error::Error + Send + 'static))
382+
fn extract_backtrace(e: &(Error + Send + 'static))
378383
-> Option<Option<Arc<Backtrace>>>;
379384
}
380385

381-
/// Additionnal methods for `Result`, for easy interaction with this crate.
382-
pub trait ResultExt<T, E: ChainedError> {
383-
/// If the `Result` is an `Err` then `chain_err` evaluates the closure,
384-
/// which returns *some type that can be converted to `ErrorKind`*, boxes
385-
/// the original error to store as the cause, then returns a new error
386-
/// containing the original error.
387-
fn chain_err<F, EK>(self, callback: F) -> Result<T, E>
388-
where F: FnOnce() -> EK,
389-
EK: Into<E::ErrorKind>;
390-
}
386+
pub use alloc::*;
387+
388+
#[cfg(feature = "alloc")]
389+
mod alloc {
390+
pub use std::error::Error;
391391

392-
impl<T, E> ResultExt<T, E> for Result<T, E> where E: ChainedError {
393-
fn chain_err<F, EK>(self, callback: F) -> Result<T, E>
394-
where F: FnOnce() -> EK,
395-
EK: Into<E::ErrorKind> {
396-
self.map_err(move |e| {
397-
#[cfg(feature = "backtrace")]
398-
let error = {
399-
let backtrace = E::extract_backtrace(&e)
400-
.unwrap_or_else(make_backtrace);
401-
E::new(callback().into(), State {
402-
next_error: Some(Box::new(e)),
403-
backtrace: backtrace,
392+
/// Additionnal methods for `Result`, for easy interaction with this crate.
393+
pub trait ResultExt<T, E: ChainedError> {
394+
/// If the `Result` is an `Err` then `chain_err` evaluates the closure,
395+
/// which returns *some type that can be converted to `ErrorKind`*, boxes
396+
/// the original error to store as the cause, then returns a new error
397+
/// containing the original error.
398+
fn chain_err<F, EK>(self, callback: F) -> Result<T, E>
399+
where F: FnOnce() -> EK,
400+
EK: Into<E::ErrorKind>;
401+
}
402+
403+
impl<T, E> ResultExt<T, E> for Result<T, E> where E: ChainedError {
404+
fn chain_err<F, EK>(self, callback: F) -> Result<T, E>
405+
where F: FnOnce() -> EK,
406+
EK: Into<E::ErrorKind> {
407+
self.map_err(move |e| {
408+
#[cfg(feature = "backtrace")]
409+
let error = {
410+
let backtrace = E::extract_backtrace(&e)
411+
.unwrap_or_else(make_backtrace);
412+
E::new(callback().into(), State {
413+
next_error: Some(Box::new(e)),
414+
backtrace: backtrace,
415+
})
416+
};
417+
#[cfg(not(feature = "backtrace"))]
418+
let error = E::new(callback().into(), State {
419+
next_error: Some(Box::new(e)),
420+
});
421+
error
404422
})
405-
};
406-
#[cfg(not(feature = "backtrace"))]
407-
let error = E::new(callback().into(), State {
408-
next_error: Some(Box::new(e)),
409-
});
410-
error
411-
})
423+
}
412424
}
413425
}
414426

427+
#[cfg(not(feature = "alloc"))]
428+
mod alloc {
429+
pub trait Error {
430+
fn description(&self) -> &str;
431+
432+
fn cause(&self) -> Option<&Error> { None }
433+
}
434+
}
415435

416436
/// Common state between errors.
417437
#[derive(Debug)]
418438
pub struct State {
419439
/// Next error in the error chain.
440+
#[cfg(feature = "alloc")]
420441
pub next_error: Option<Box<error::Error + Send>>,
421442
/// Backtrace for the current error.
422443
#[cfg(feature = "backtrace")]
@@ -430,10 +451,13 @@ impl Default for State {
430451
next_error: None,
431452
backtrace: make_backtrace(),
432453
};
433-
#[cfg(not(feature = "backtrace"))]
454+
#[cfg(all(not(feature = "backtrace"), feature = "alloc"))]
434455
let state = State {
435456
next_error: None,
436457
};
458+
#[cfg(not(feature = "alloc"))]
459+
let state = State {
460+
};
437461
state
438462
}
439463
}

0 commit comments

Comments
 (0)