#[macro_export]
macro_rules! track {
($target:expr) => {
{
use $crate::Trackable;
let mut target = $target;
target.track(|| {
let location = $crate::Location::new(
module_path!(), file!(), line!(), String::new());
From::from(location)
});
target
}
};
($target:expr; $($value:expr),+) => {
$crate::track!($target, $crate::trackable_prepare_values_fmt!($($value),+), $($value),+)
};
($target:expr, $message:expr) => {
{
use $crate::Trackable;
let mut target = $target;
target.track(|| {
let location = $crate::Location::new(module_path!(), file!(), line!(), $message);
From::from(location)
});
target
}
};
($target:expr, $message:expr; $($value:expr),+) => {
$crate::track!($target, concat!($message, "; ", $crate::trackable_prepare_values_fmt!($($value),+)), $($value),+)
};
($target:expr, $($format_arg:tt)+) => {
{
$crate::track!($target, format!($($format_arg)+))
}
};
}
#[macro_export]
macro_rules! track_any_err {
($target:expr) => {
$target.map_err(|e| $crate::track!($crate::error::Failure::from_error(e)))
};
($target:expr; $($arg:tt)*) => {
$target.map_err(|e| $crate::track!($crate::error::Failure::from_error(e); $($arg)*))
};
($target:expr, $($arg:tt)*) => {
$target.map_err(|e| $crate::track!($crate::error::Failure::from_error(e), $($arg)*))
};
}
#[macro_export]
macro_rules! track_err {
($target:expr) => {
$target.map_err(|e| $crate::track!(e))
};
($target:expr; $($arg:tt)*) => {
$target.map_err(|e| $crate::track!(e; $($arg)*))
};
($target:expr, $($arg:tt)*) => {
$target.map_err(|e| $crate::track!(e, $($arg)*))
};
}
#[macro_export]
macro_rules! track_assert {
($cond:expr, $error_kind:expr) => {
if ! $cond {
$crate::track_panic!($error_kind, "assertion failed: `{}`", stringify!($cond))
}
};
($cond:expr, $error_kind:expr; $($value:expr),+) => {
track_assert!($cond, $error_kind, $crate::trackable_prepare_values_fmt!($($value),+), $($value),+)
};
($cond:expr, $error_kind:expr, $message:expr) => {
track_assert!($cond, $error_kind, $message,)
};
($cond:expr, $error_kind:expr, $message:expr; $($value:expr),+) => {
track_assert!($cond, $error_kind,
concat!($message, "; ", $crate::trackable_prepare_values_fmt!($($value),+)), $($value),+)
};
($cond:expr, $error_kind:expr, $fmt:expr, $($arg:tt)*) => {
if ! $cond {
$crate::track_panic!($error_kind,
concat!("assertion failed: `{}`; ", $fmt),
stringify!($cond), $($arg)*)
}
};
}
#[macro_export]
macro_rules! track_assert_eq {
($left:expr, $right:expr, $error_kind:expr) => {
{
let left = &$left;
let right = &$right;
$crate::track_assert!(left == right, $error_kind,
"assertion failed: `(left == right)` (left: `{:?}`, right: `{:?}`)",
left, right)
}
};
($left:expr, $right:expr, $error_kind:expr; $($value:expr),+) => {
track_assert_eq!($left, $right, $error_kind,
$crate::trackable_prepare_values_fmt!($($value),+), $($value),+)
};
($left:expr, $right:expr, $error_kind:expr, $message:expr) => {
track_assert_eq!($left, $right, $error_kind, $message,)
};
($left:expr, $right:expr, $error_kind:expr, $message:expr; $($value:expr),+) => {
track_assert_eq!($left, $right, $error_kind,
concat!($message, "; ", $crate::trackable_prepare_values_fmt!($($value),+)), $($value),+)
};
($left:expr, $right:expr, $error_kind:expr, $fmt:expr, $($arg:tt)*) => {
{
let left = &$left;
let right = &$right;
$crate::track_assert!(
left == right, $error_kind,
concat!("assertion failed: `(left == right)` (left: `{:?}`, right: `{:?}`): ",
$fmt),
left, right, $($arg)*)
}
};
}
#[macro_export]
macro_rules! track_assert_ne {
($left:expr, $right:expr, $error_kind:expr) => {
{
let left = &$left;
let right = &$right;
$crate::track_assert!(left != right, $error_kind,
"assertion failed: `(left != right)` (left: `{:?}`, right: `{:?}`)",
left, right)
}
};
($left:expr, $right:expr, $error_kind:expr; $($value:expr),+) => {
track_assert_ne!($left, $right, $error_kind,
$crate::trackable_prepare_values_fmt!($($value),+), $($value),+)
};
($left:expr, $right:expr, $error_kind:expr, $message:expr) => {
track_assert_ne!($left, $right, $error_kind, $message,)
};
($left:expr, $right:expr, $error_kind:expr, $message:expr; $($value:expr),+) => {
track_assert_ne!($left, $right, $error_kind,
concat!($message, "; ", $crate::trackable_prepare_values_fmt!($($value),+)), $($value),+)
};
($left:expr, $right:expr, $error_kind:expr, $fmt:expr, $($arg:tt)*) => {
{
let left = &$left;
let right = &$right;
$crate::track_assert!(
left != right, $error_kind,
concat!("assertion failed: `(left != right)` (left: `{:?}`, right: `{:?}`): ",
$fmt),
left, right, $($arg)*)
}
};
}
#[macro_export]
macro_rules! track_assert_some {
($expr:expr, $error_kind:expr) => {
if let Some(v) = $expr {
v
} else {
$crate::track_panic!($error_kind, "assertion failed: `{}.is_some()`", stringify!($expr))
}
};
($expr:expr, $error_kind:expr; $($value:expr),+) => {
track_assert_some!($expr, $error_kind,
$crate::trackable_prepare_values_fmt!($($value),+), $($value),+)
};
($expr:expr, $error_kind:expr, $message:expr) => {
track_assert_some!($expr, $error_kind, $message,)
};
($expr:expr, $error_kind:expr, $message:expr; $($value:expr),+) => {
track_assert_some!($expr, $error_kind,
concat!($message, "; ", $crate::trackable_prepare_values_fmt!($($value),+)), $($value),+)
};
($expr:expr, $error_kind:expr, $fmt:expr, $($arg:tt)*) => {
if let Some(v) = $expr {
v
} else {
$crate::track_panic!($error_kind,
concat!("assertion failed: `{}.is_some()`; ", $fmt),
stringify!($expr), $($arg)*)
}
};
}
#[macro_export]
macro_rules! track_panic {
($error:expr) => {
{
let e = $crate::error::TrackableError::from($error);
let e = $crate::track!(e);
return Err(From::from(e));
}
};
($error:expr; $($value:expr),+) => {
track_panic!($error, $crate::trackable_prepare_values_fmt!($($value),+), $($value),+)
};
($error_kind:expr, $message:expr) => {
{
use $crate::error::ErrorKindExt;
track_panic!($error_kind.cause($message))
}
};
($error:expr, $message:expr; $($value:expr),+) => {
track_panic!($error,
concat!($message, "; ", $crate::trackable_prepare_values_fmt!($($value),+)), $($value),+)
};
($error_kind:expr, $($format_arg:tt)+) => {
{
track_panic!($error_kind, format!($($format_arg)+))
}
};
}
#[macro_export]
macro_rules! track_try_unwrap {
($expr:expr) => {
match $crate::track!($expr) {
Err(e) => { panic!("\nEXPRESSION: {}\nERROR: {}\n", stringify!($expr), e) }
Ok(v) => { v }
}
};
($expr:expr, $($format_arg:tt)*) => {
match $crate::track!($expr, $($format_arg)*) {
Err(e) => { panic!("\nEXPRESSION: {}\nERROR: {}\n", stringify!($expr), e) }
Ok(v) => { v }
}
};
}
#[deprecated(
since = "0.2.19",
note = "please use `#[derive(TrackableError)]` instead"
)]
#[macro_export]
macro_rules! derive_traits_for_trackable_error_newtype {
($error:ident, $kind:ty) => {
impl ::std::ops::Deref for $error {
type Target = $crate::error::TrackableError<$kind>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl ::std::fmt::Display for $error {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
self.0.fmt(f)
}
}
impl ::std::error::Error for $error {
fn source(&self) -> Option<&(::std::error::Error + 'static)> {
self.0.source()
}
}
impl $crate::Trackable for $error {
type Event = $crate::Location;
#[inline]
fn history(&self) -> Option<&$crate::History<Self::Event>> {
self.0.history()
}
#[inline]
fn history_mut(&mut self) -> Option<&mut $crate::History<Self::Event>> {
self.0.history_mut()
}
}
impl From<$crate::error::TrackableError<$kind>> for $error {
#[inline]
fn from(f: $crate::error::TrackableError<$kind>) -> Self {
$error(f)
}
}
impl From<$error> for $crate::error::TrackableError<$kind> {
#[inline]
fn from(f: $error) -> Self {
f.0
}
}
impl From<$kind> for $error {
#[inline]
fn from(f: $kind) -> Self {
use $crate::error::ErrorKindExt;
f.error().into()
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! trackable_prepare_values_fmt {
() => {};
($value:expr) => {
concat!(stringify!($value), "={:?}")
};
($value:expr, $($rest:expr),*) => {
concat!(stringify!($value), "={:?}, ", trackable_prepare_values_fmt!($($rest),*))
};
}
#[cfg(test)]
mod test {
use error::{ErrorKindExt, Failed, Failure};
#[test]
fn track_works() {
fn foo(bar: Result<(), Failure>) -> Result<(), Failure> {
struct Baz {
qux: usize,
}
let baz = Baz { qux: 0 };
track!(bar.clone())?;
track!(bar.clone(), "hello")?;
track!(bar.clone(), "baz.qux={}", baz.qux)?;
Ok(())
}
assert!(foo(Ok(())).is_ok());
}
#[test]
fn track_assert_works() {
fn add_positive_f32(a: f32, b: f32) -> Result<f32, Failure> {
track_assert!(a > 0.0 && b > 0.0, Failed);
Ok(a + b)
}
let r = add_positive_f32(3.0, 2.0); assert_eq!(r.ok(), Some(5.0));
let r = add_positive_f32(1.0, -2.0); assert!(r.is_err());
assert_eq!(
format!("\n{}", r.err().unwrap()).replace('\\', "/"),
r#"
Failed (cause; assertion failed: `a > 0.0 && b > 0.0`)
HISTORY:
[0] at src/macros.rs:564
"#
);
}
#[test]
#[should_panic]
fn track_try_unwrap_works() {
track_try_unwrap!(Err(Failed.error()));
}
}