#[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, $($format_arg:tt)+) => {
{
use $crate::Trackable;
let mut target = $target;
target.track(|| {
let message = format!($($format_arg)+);
let location = $crate::Location::new(module_path!(), file!(), line!(), message);
From::from(location)
});
target
}
};
}
#[macro_export]
macro_rules! track_try {
($expr:expr) => {
match $expr {
Err(e) => {
let e = track!($crate::error::TrackableError::from_cause(e));
Err(e)?
}
Ok(v) => {
v
}
}
};
($expr:expr, $($format_arg:tt)+) => {
match $expr {
Err(e) => {
let e = track!($crate::error::TrackableError::from_cause(e), $($format_arg)+);
Err(e)?
}
Ok(v) => {
v
}
}
};
}
#[macro_export]
macro_rules! track_err {
($expr:expr $(, $arg:tt)*) => {
$expr.map_err(|e| track!($crate::error::TrackableError::from_cause(e) $(, $arg)*))
};
}
#[macro_export]
macro_rules! track_assert {
($cond:expr, $error_kind:expr) => {
track_assert!($cond, $error_kind, "assertion failed: {}", stringify!($cond));
};
($cond:expr, $error_kind:expr, $($format_arg:tt)+) => {
if ! $cond {
track_panic!($error_kind, $($format_arg)+);
}
};
}
#[macro_export]
macro_rules! track_assert_eq {
($left:expr, $right:expr, $error_kind:expr) => {
let left = $left;
let right = $right;
track_assert!(left == right, $error_kind,
"assertion failed: `(left == right)` (left: `{:?}`, right: `{:?}`)",
left, right);
};
($left:expr, $right:expr, $error_kind:expr, $fmt:expr) => {
track_assert_eq!($left, $right, $error_kind, $fmt,);
};
($left:expr, $right:expr, $error_kind:expr, $fmt:expr, $($arg:tt)*) => {
let left = $left;
let right = $right;
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;
track_assert!(left != right, $error_kind,
"assertion failed: `(left != right)` (left: `{:?}`, right: `{:?}`)",
left, right);
};
($left:expr, $right:expr, $error_kind:expr, $fmt:expr) => {
track_assert_ne!($left, $right, $error_kind, $fmt,);
};
($left:expr, $right:expr, $error_kind:expr, $fmt:expr, $($arg:tt)*) => {
let left = $left;
let right = $right;
track_assert!(
left != right, $error_kind,
concat!("assertion failed: `(left != right)` (left: `{:?}`, right: `{:?}`): ", $fmt),
left, right, $($arg)*);
};
}
#[macro_export]
macro_rules! track_panic {
($error:expr) => {
{
let e = $crate::error::TrackableError::from($error);
let e = track!(e);
return Err(From::from(e));
}
};
($error_kind:expr, $($format_arg:tt)+) => {
{
use $crate::error::ErrorKindExt;
let message = format!($($format_arg)+);
track_panic!($error_kind.cause(message));
}
};
}
#[macro_export]
macro_rules! track_try_unwrap {
($expr:expr) => {
match track!($expr) {
Err(e) => { panic!("\nEXPRESSION: {}\nERROR: {}\n", stringify!($expr), e); }
Ok(v) => { v }
}
};
($expr:expr, $($format_arg:tt)*) => {
match track!($expr, $($format_arg)*) {
Err(e) => { panic!("\nEXPRESSION: {}\nERROR: {}\n", stringify!($expr), e); }
Ok(v) => { v }
}
};
}
#[macro_export]
macro_rules! derive_traits_for_trackable_error_newtype {
($error:ty, $kind:ty) => {
impl ::std::ops::Deref for $error {
type Target = $crate::error::TrackableError<$kind>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<TrackableError<$kind>> for $error {
fn from(f: TrackableError<$kind>) -> Self {
Error(f)
}
}
impl From<$error> for TrackableError<$kind> {
fn from(f: $error) -> Self {
f.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 description(&self) -> &str {
self.0.description()
}
fn cause(&self) -> Option<&::std::error::Error> {
self.0.cause()
}
}
impl $crate::Trackable for $error {
type Event = $crate::error::Event;
fn assign_tracking_number(&mut self) {
self.0.assign_tracking_number();
}
fn tracking_number(&self) -> Option<$crate::TrackingNumber> {
self.0.tracking_number()
}
fn enable_tracking(self) -> Self
where Self: Sized
{
From::from(self.0.enable_tracking())
}
fn disable_tracking(self) -> Self
where Self: Sized
{
From::from(self.0.disable_tracking())
}
fn history(&self) -> Option<&$crate::History<Self::Event>> {
self.0.history()
}
fn history_mut(&mut self) -> Option<&mut $crate::History<Self::Event>> {
self.0.history_mut()
}
}
impl $crate::error::IntoTrackableError<$error> for $kind {
fn into_trackable_error(e: $error) -> $crate::error::TrackableError<$kind> {
e.0
}
}
}
}
#[cfg(test)]
mod test {
use error::Failure;
#[test]
fn track_try_works() {
fn foo(bar: Result<(), Failure>) -> Result<(), Failure> {
struct Baz {
qux: usize,
}
let baz = Baz { qux: 0 };
track_try!(bar.clone());
track_try!(bar.clone(), "hello");
track_try!(bar.clone(), "baz.qux={}", baz.qux);
Ok(())
}
assert!(foo(Ok(())).is_ok());
}
}