report

Macro report 

Source
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>()
);