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>(f: F, tx: &SyncSender<Event<M>>, context: &str)
26where
27    F: FnOnce() -> Option<M> + std::panic::UnwindSafe,
28    M: Send + 'static,
29{
30    let result = std::panic::catch_unwind(f);
31
32    match result {
33        Ok(Some(msg)) => {
34            let _ = tx.send(Event::User(msg));
35        }
36        Ok(None) => {
37            // No message to send
38        }
39        Err(panic) => {
40            let panic_msg = format_panic_message(panic, context);
41            eprintln!("{}", panic_msg);
42        }
43    }
44}
45
46/// Execute a fallible closure with panic recovery
47pub fn execute_fallible_with_panic_recovery<M, F>(f: F, tx: &SyncSender<Event<M>>, context: &str)
48where
49    F: FnOnce() -> Result<Option<M>, Box<dyn std::error::Error + Send + Sync>>
50        + std::panic::UnwindSafe,
51    M: Send + 'static,
52{
53    let result = std::panic::catch_unwind(AssertUnwindSafe(f));
54
55    match result {
56        Ok(Ok(Some(msg))) => {
57            let _ = tx.send(Event::User(msg));
58        }
59        Ok(Ok(None)) => {
60            // No message to send
61        }
62        Ok(Err(error)) => {
63            eprintln!("{}: {}", context, error);
64        }
65        Err(panic) => {
66            let panic_msg = format_panic_message(panic, context);
67            eprintln!("{}", panic_msg);
68        }
69    }
70}