hojicha_runtime/
panic_utils.rs

1//! Utilities for consistent panic handling across the runtime
2//!
3//! This module provides reusable panic handling utilities to reduce
4//! code duplication and ensure consistent error reporting.
5
6use hojicha_core::event::Event;
7use std::any::Any;
8use std::panic::AssertUnwindSafe;
9use std::sync::mpsc::SyncSender;
10
11/// Format a panic payload into a readable error message
12pub fn format_panic_message(panic: Box<dyn Any + Send>, context: &str) -> String {
13    let panic_msg = if let Some(s) = panic.downcast_ref::<String>() {
14        s.clone()
15    } else if let Some(s) = panic.downcast_ref::<&str>() {
16        s.to_string()
17    } else {
18        "Unknown panic".to_string()
19    };
20    
21    format!("{}: {}", context, panic_msg)
22}
23
24/// Execute a closure with panic recovery and send the result as an event
25pub fn execute_with_panic_recovery<M, F>(
26    f: F,
27    tx: &SyncSender<Event<M>>,
28    context: &str,
29) where
30    F: FnOnce() -> Option<M> + std::panic::UnwindSafe,
31    M: Send + 'static,
32{
33    let result = std::panic::catch_unwind(f);
34    
35    match result {
36        Ok(Some(msg)) => {
37            let _ = tx.send(Event::User(msg));
38        }
39        Ok(None) => {
40            // No message to send
41        }
42        Err(panic) => {
43            let panic_msg = format_panic_message(panic, context);
44            eprintln!("{}", panic_msg);
45        }
46    }
47}
48
49/// Execute a fallible closure with panic recovery
50pub fn execute_fallible_with_panic_recovery<M, F>(
51    f: F,
52    tx: &SyncSender<Event<M>>,
53    context: &str,
54) where
55    F: FnOnce() -> Result<Option<M>, Box<dyn std::error::Error + Send + Sync>> + std::panic::UnwindSafe,
56    M: Send + 'static,
57{
58    let result = std::panic::catch_unwind(AssertUnwindSafe(f));
59    
60    match result {
61        Ok(Ok(Some(msg))) => {
62            let _ = tx.send(Event::User(msg));
63        }
64        Ok(Ok(None)) => {
65            // No message to send
66        }
67        Ok(Err(error)) => {
68            eprintln!("{}: {}", context, error);
69        }
70        Err(panic) => {
71            let panic_msg = format_panic_message(panic, context);
72            eprintln!("{}", panic_msg);
73        }
74    }
75}