macro_rules! report {
($msg:literal $(,)?) => { ... };
($context:expr $(,)?) => { ... };
($fmt:expr, $($arg:tt)*) => { ... };
}Expand description
Creates a new error report.
This macro provides a convenient way to create Report
instances with automatic type inference for thread-safety markers and error
handlers.
§Two Usage Modes
§Format String Mode
When the first argument is a string literal, the macro works like
format!(), creating a report with a formatted string as context:
use rootcause::prelude::*;
let report: Report = report!("File not found");
let report: Report = report!("Failed to open {}", "config.toml");The resulting report has type Report<Dynamic, Mutable, SendSync>. The
context is typically a String, but when there are no format arguments, it
may be optimized to a &'static str.
§Context Object Mode
When given any other expression, the macro creates a report from that value:
use rootcause::prelude::*;
let error: io::Error = get_io_error();
let report: Report<io::Error> = report!(error);This mode automatically:
- Infers the thread-safety marker based on whether the context type is `Send
- Sync`
- Selects the appropriate handler based on the context type
This is similar to calling Report::new, but with better type inference.
§Examples
§Basic String Reports
use std::{any::TypeId, rc::Rc};
use rootcause::prelude::*;
// Static string (no formatting)
let report: Report<markers::Dynamic, markers::Mutable, markers::SendSync> =
report!("Something broke");
assert_eq!(
report.current_context_type_id(),
TypeId::of::<&'static str>()
);
// Formatted string
let report: Report<markers::Dynamic, markers::Mutable, markers::SendSync> =
report!("Something broke hard: {}", "it was bad");
assert_eq!(report.current_context_type_id(), TypeId::of::<String>());
assert_eq!(
report.current_context_handler_type_id(),
TypeId::of::<handlers::Display>()
);§Error Type Reports
use std::{any::TypeId, io};
use rootcause::prelude::*;
let io_error: std::io::Error = something_that_fails().unwrap_err();
let report: Report<std::io::Error, markers::Mutable, markers::SendSync> = report!(io_error);
assert_eq!(
report.current_context_handler_type_id(),
TypeId::of::<handlers::Error>()
);§Debug-Only Types
When using a type that implements Debug but not
Display, the report uses crate::handlers::Debug
which shows “Context of type TypeName” when displayed:
use std::any::TypeId;
use rootcause::prelude::*;
#[derive(Debug)]
struct InternalState {
value: usize,
}
let state = InternalState { value: 42 };
let report: Report<InternalState> = report!(state);
// Display shows a generic message with the type name
let output = format!("{}", report);
assert!(output.contains("InternalState"));
assert!(!output.contains("value")); // Debug details not shown in Display
assert_eq!(
report.current_context_handler_type_id(),
TypeId::of::<handlers::Debug>()
);§Local (Non-Send) Reports
When using non-thread-safe types like Rc, the macro
automatically infers the Local marker:
use std::{any::TypeId, rc::Rc};
use rootcause::prelude::*;
let local_io_error: Rc<std::io::Error> = something_else_that_fails().unwrap_err();
let report: Report<Rc<std::io::Error>, markers::Mutable, markers::Local> =
report!(local_io_error);
assert_eq!(
report.current_context_handler_type_id(),
TypeId::of::<handlers::Display>()
);