diff --git a/serde/src/de/mod.rs b/serde/src/de/mod.rs index 4c8f65aa..f1b8b312 100644 --- a/serde/src/de/mod.rs +++ b/serde/src/de/mod.rs @@ -125,6 +125,13 @@ mod utf8; pub use self::ignored_any::IgnoredAny; +#[cfg(feature = "std")] +#[doc(no_inline)] +pub use std::error::Error as StdError; +#[cfg(not(feature = "std"))] +#[doc(no_inline)] +pub use std_error::Error as StdError; + //////////////////////////////////////////////////////////////////////////////// macro_rules! declare_error_trait { @@ -288,7 +295,7 @@ macro_rules! declare_error_trait { } #[cfg(feature = "std")] -declare_error_trait!(Error: Sized + error::Error); +declare_error_trait!(Error: Sized + StdError); #[cfg(not(feature = "std"))] declare_error_trait!(Error: Sized + Debug + Display); diff --git a/serde/src/lib.rs b/serde/src/lib.rs index 927138af..e270fc9d 100644 --- a/serde/src/lib.rs +++ b/serde/src/lib.rs @@ -250,6 +250,9 @@ pub mod export; #[doc(hidden)] pub mod private; +#[cfg(not(feature = "std"))] +mod std_error; + // Re-export #[derive(Serialize, Deserialize)]. // // The reason re-exporting is not enabled by default is that disabling it would diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs index 318b3799..8fb2434f 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -114,6 +114,13 @@ mod impossible; pub use self::impossible::Impossible; +#[cfg(feature = "std")] +#[doc(no_inline)] +pub use std::error::Error as StdError; +#[cfg(not(feature = "std"))] +#[doc(no_inline)] +pub use std_error::Error as StdError; + //////////////////////////////////////////////////////////////////////////////// macro_rules! declare_error_trait { @@ -172,7 +179,7 @@ macro_rules! declare_error_trait { } #[cfg(feature = "std")] -declare_error_trait!(Error: Sized + error::Error); +declare_error_trait!(Error: Sized + StdError); #[cfg(not(feature = "std"))] declare_error_trait!(Error: Sized + Debug + Display); diff --git a/serde/src/std_error.rs b/serde/src/std_error.rs new file mode 100644 index 00000000..1055e0ff --- /dev/null +++ b/serde/src/std_error.rs @@ -0,0 +1,48 @@ +use lib::{Debug, Display}; + +/// Either a re-export of std::error::Error or a new identical trait, depending +/// on whether Serde's "std" feature is enabled. +/// +/// Serde's error traits [`serde::ser::Error`] and [`serde::de::Error`] require +/// [`std::error::Error`] as a supertrait, but only when Serde is built with +/// "std" enabled. Data formats that don't care about no\_std support should +/// generally provide their error types with a `std::error::Error` impl +/// directly: +/// +/// ```edition2018 +/// #[derive(Debug)] +/// struct MySerError {...} +/// +/// impl serde::ser::Error for MySerError {...} +/// +/// impl std::fmt::Display for MySerError {...} +/// +/// // We don't support no_std! +/// impl std::error::Error for MySerError {} +/// ``` +/// +/// Data formats that *do* support no\_std may either have a "std" feature of +/// their own: +/// +/// ```toml +/// [features] +/// std = ["serde/std"] +/// ``` +/// +/// ```edition2018 +/// #[cfg(feature = "std")] +/// impl std::error::Error for MySerError {} +/// ``` +/// +/// ... or else provide the std Error impl unconditionally via Serde's +/// re-export: +/// +/// ```edition2018 +/// impl serde::ser::StdError for MySerError {} +/// ``` +pub trait Error: Debug + Display { + /// The underlying cause of this error, if any. + fn source(&self) -> Option<&(Error + 'static)> { + None + } +}