@@ -218,7 +218,7 @@ pub fn is_class_runtime(is_tool: bool) -> bool {
218
218
}
219
219
220
220
// ----------------------------------------------------------------------------------------------------------------------------------------------
221
- // Panic handling
221
+ // Panic *hook* management
222
222
223
223
pub fn extract_panic_message ( err : & ( dyn Send + std:: any:: Any ) ) -> String {
224
224
if let Some ( s) = err. downcast_ref :: < & ' static str > ( ) {
@@ -370,13 +370,31 @@ pub fn get_gdext_panic_context() -> Option<String> {
370
370
None
371
371
}
372
372
373
+ // ----------------------------------------------------------------------------------------------------------------------------------------------
374
+ // Panic unwinding and catching
375
+
376
+ pub struct PanicPayload {
377
+ payload : Box < dyn std:: any:: Any + Send + ' static > ,
378
+ }
379
+
380
+ impl PanicPayload {
381
+ pub fn new ( payload : Box < dyn std:: any:: Any + Send + ' static > ) -> Self {
382
+ Self { payload }
383
+ }
384
+
385
+ // While this could be `&self`, it's usually good practice to pass panic payloads around linearly and have only 1 representation at a time.
386
+ pub fn into_panic_message ( self ) -> String {
387
+ extract_panic_message ( self . payload . as_ref ( ) )
388
+ }
389
+ }
390
+
373
391
/// Executes `code`. If a panic is thrown, it is caught and an error message is printed to Godot.
374
392
///
375
393
/// Returns `Err(message)` if a panic occurred, and `Ok(result)` with the result of `code` otherwise.
376
394
///
377
395
/// In contrast to [`handle_varcall_panic`] and [`handle_ptrcall_panic`], this function is not intended for use in `try_` functions,
378
396
/// where the error is propagated as a `CallError` in a global variable.
379
- pub fn handle_panic < E , F , R > ( error_context : E , code : F ) -> Result < R , String >
397
+ pub fn handle_panic < E , F , R > ( error_context : E , code : F ) -> Result < R , PanicPayload >
380
398
where
381
399
E : Fn ( ) -> String ,
382
400
F : FnOnce ( ) -> R + std:: panic:: UnwindSafe ,
@@ -390,8 +408,7 @@ where
390
408
cell. borrow_mut ( ) . push_function ( & error_context)
391
409
} ) ;
392
410
393
- let result =
394
- std:: panic:: catch_unwind ( code) . map_err ( |payload| extract_panic_message ( payload. as_ref ( ) ) ) ;
411
+ let result = std:: panic:: catch_unwind ( code) . map_err ( PanicPayload :: new) ;
395
412
396
413
#[ cfg( debug_assertions) ]
397
414
ERROR_CONTEXT_STACK . with ( |cell| cell. borrow_mut ( ) . pop_function ( ) ) ;
@@ -407,8 +424,8 @@ pub fn handle_varcall_panic<F, R>(
407
424
) where
408
425
F : FnOnce ( ) -> Result < R , CallError > + std:: panic:: UnwindSafe ,
409
426
{
410
- let outcome: Result < Result < R , CallError > , String > =
411
- handle_panic ( || format ! ( "{ call_ctx}" ) , code) ;
427
+ let outcome: Result < Result < R , CallError > , PanicPayload > =
428
+ handle_panic ( || call_ctx. to_string ( ) , code) ;
412
429
413
430
let call_error = match outcome {
414
431
// All good.
@@ -437,14 +454,14 @@ pub fn handle_ptrcall_panic<F, R>(call_ctx: &CallContext, code: F)
437
454
where
438
455
F : FnOnce ( ) -> R + std:: panic:: UnwindSafe ,
439
456
{
440
- let outcome: Result < R , String > = handle_panic ( || format ! ( "{ call_ctx}" ) , code) ;
457
+ let outcome: Result < R , PanicPayload > = handle_panic ( || call_ctx. to_string ( ) , code) ;
441
458
442
459
let call_error = match outcome {
443
460
// All good.
444
461
Ok ( _result) => return ,
445
462
446
463
// Panic occurred (typically through user): forward message.
447
- Err ( panic_msg ) => CallError :: failed_by_user_panic ( call_ctx, panic_msg ) ,
464
+ Err ( payload ) => CallError :: failed_by_user_panic ( call_ctx, payload ) ,
448
465
} ;
449
466
450
467
let _id = report_call_error ( call_error, false ) ;
0 commit comments