use std::{error::Error, rc::Rc};
use rootcause::{
Report, bail,
compat::{IntoRootcause, boxed_error::IntoBoxedError},
markers::{Dynamic, Local, SendSync},
prelude::*,
};
fn some_boxed_error_function() -> Result<String, Box<dyn Error + Send + Sync>> {
Err("connection timeout".into())
}
fn another_boxed_error_function() -> Result<i32, Box<dyn Error>> {
Err("parsing failed".into())
}
fn rootcause_calls_boxed_error() -> Result<(), Report> {
let _value = some_boxed_error_function()
.into_rootcause()
.context("Failed to get network data")?;
println!("Got network value");
Ok(())
}
fn rootcause_calls_local_boxed_error() -> Result<(), Box<dyn Error>> {
let _value = another_boxed_error_function()
.into_rootcause()
.into_boxed_error()
.map_err(|e| format!("Failed to parse local data: {}", e))?;
println!("Got local value");
Ok(())
}
fn some_rootcause_function() -> Result<String, Report> {
bail!("validation failed");
}
fn some_local_rootcause_function() -> Result<String, Report<Dynamic, markers::Mutable, Local>> {
let local_data = Rc::new("sensitive data");
let report = report!("local validation failed")
.into_local()
.attach(local_data);
Err(report)
}
fn boxed_error_calls_rootcause() -> Result<(), Box<dyn Error + Send + Sync>> {
let _value = some_rootcause_function().into_boxed_error()?;
println!("Got rootcause value");
Ok(())
}
fn local_boxed_error_calls_rootcause() -> Result<(), Box<dyn Error>> {
let _value = some_local_rootcause_function().into_boxed_error()?;
println!("Got local rootcause value");
Ok(())
}
fn rootcause_function_returning_boxed_error() -> Result<(), Box<dyn Error + Send + Sync>> {
some_rootcause_function()?;
Ok(())
}
fn rootcause_function_returning_local_boxed_error() -> Result<(), Box<dyn Error>> {
some_local_rootcause_function()?;
Ok(())
}
fn demonstrate_thread_safety() {
println!("=== Thread Safety Demonstration ===\n");
let send_sync_report: Report<_, _, SendSync> = report!("network error");
let send_sync_boxed: Box<dyn Error + Send + Sync> = send_sync_report.into_boxed_error();
println!("SendSync report → Box<dyn Error + Send + Sync>");
println!("Error: {}\n", send_sync_boxed);
let local_report: Report<_, _, Local> = report!("local error")
.into_local()
.attach(Rc::new("local data"));
let local_boxed: Box<dyn Error> = local_report.into_boxed_error();
println!("Local report → Box<dyn Error>");
println!("Error: {}\n", local_boxed);
}
fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
println!("Rootcause ↔ Boxed Error Interoperability Examples\n");
println!("===============================================\n");
println!("=== Example 1: Boxed Error → Rootcause ===\n");
if let Err(e) = rootcause_calls_boxed_error() {
println!("Error occurred:");
println!("{}\n", e);
}
if let Err(e) = rootcause_calls_local_boxed_error() {
println!("Local error occurred:");
println!("{}\n", e);
}
println!("=== Example 2: Rootcause → Boxed Error ===\n");
if let Err(e) = boxed_error_calls_rootcause() {
println!("Error occurred:");
println!("{}\n", e);
}
if let Err(e) = local_boxed_error_calls_rootcause() {
println!("Local error occurred:");
println!("{}\n", e);
}
println!("=== Example 3: Automatic Conversion with ? ===\n");
if let Err(e) = rootcause_function_returning_boxed_error() {
println!("Error occurred:");
println!("{}\n", e);
}
if let Err(e) = rootcause_function_returning_local_boxed_error() {
println!("Local error occurred:");
println!("{}\n", e);
}
demonstrate_thread_safety();
println!("===============================================");
println!("\nKey Benefits:");
println!("- Seamless integration with standard Rust error handling");
println!("- Preserves thread safety constraints (SendSync vs Local)");
println!("- Works with existing APIs expecting Box<dyn Error>");
println!("- Automatic conversion via From trait and ? operator");
Ok(())
}