@@ -13,7 +13,7 @@ use std::sync::atomic;
1313use sys:: Global ;
1414
1515use crate :: global:: godot_error;
16- use crate :: meta:: error:: CallError ;
16+ use crate :: meta:: error:: { CallError , CallResult } ;
1717use crate :: meta:: CallContext ;
1818use crate :: obj:: Gd ;
1919use crate :: { classes, sys} ;
@@ -417,7 +417,7 @@ impl PanicPayload {
417417///
418418/// Returns `Err(message)` if a panic occurred, and `Ok(result)` with the result of `code` otherwise.
419419///
420- /// In contrast to [`handle_varcall_panic `] and [`handle_ptrcall_panic `], this function is not intended for use in `try_` functions,
420+ /// In contrast to [`handle_fallible_varcall `] and [`handle_fallible_ptrcall `], this function is not intended for use in `try_` functions,
421421/// where the error is propagated as a `CallError` in a global variable.
422422pub fn handle_panic < E , F , R > ( error_context : E , code : F ) -> Result < R , PanicPayload >
423423where
@@ -440,59 +440,57 @@ where
440440 result
441441}
442442
443- // TODO(bromeon): make call_ctx lazy-evaluated (like error_ctx) everywhere;
444- // or make it eager everywhere and ensure it's cheaply constructed in the call sites.
445- pub fn handle_varcall_panic < F , R > (
443+ /// Invokes a function with the _varcall_ calling convention, handling both expected errors and user panics.
444+ pub fn handle_fallible_varcall < F , R > (
446445 call_ctx : & CallContext ,
447446 out_err : & mut sys:: GDExtensionCallError ,
448447 code : F ,
449448) where
450- F : FnOnce ( ) -> Result < R , CallError > + std:: panic:: UnwindSafe ,
449+ F : FnOnce ( ) -> CallResult < R > + std:: panic:: UnwindSafe ,
451450{
452- let outcome: Result < Result < R , CallError > , PanicPayload > =
453- handle_panic ( || call_ctx. to_string ( ) , code) ;
454-
455- let call_error = match outcome {
456- // All good.
457- Ok ( Ok ( _result) ) => return ,
458-
459- // Call error signalled by Godot's or gdext's validation.
460- Ok ( Err ( err) ) => err,
461-
462- // Panic occurred (typically through user): forward message.
463- Err ( panic_msg) => CallError :: failed_by_user_panic ( call_ctx, panic_msg) ,
464- } ;
465-
466- let error_id = report_call_error ( call_error, true ) ;
467-
468- // Abuse 'argument' field to store our ID.
469- * out_err = sys:: GDExtensionCallError {
470- error : sys:: GODOT_RUST_CUSTOM_CALL_ERROR ,
471- argument : error_id,
472- expected : 0 ,
451+ if let Some ( error_id) = handle_fallible_call ( call_ctx, code, true ) {
452+ // Abuse 'argument' field to store our ID.
453+ * out_err = sys:: GDExtensionCallError {
454+ error : sys:: GODOT_RUST_CUSTOM_CALL_ERROR ,
455+ argument : error_id,
456+ expected : 0 ,
457+ } ;
473458 } ;
474459
475460 //sys::interface_fn!(variant_new_nil)(sys::AsUninit::as_uninit(ret));
476461}
477462
478- pub fn handle_ptrcall_panic < F , R > ( call_ctx : & CallContext , code : F )
463+ /// Invokes a function with the _ptrcall_ calling convention, handling both expected errors and user panics.
464+ pub fn handle_fallible_ptrcall < F > ( call_ctx : & CallContext , code : F )
479465where
480- F : FnOnce ( ) -> R + std:: panic:: UnwindSafe ,
466+ F : FnOnce ( ) -> CallResult < ( ) > + std:: panic:: UnwindSafe ,
481467{
482- let outcome: Result < R , PanicPayload > = handle_panic ( || call_ctx. to_string ( ) , code) ;
468+ handle_fallible_call ( call_ctx, code, false ) ;
469+ }
470+
471+ /// Common error handling for fallible calls, handling detectable errors and user panics.
472+ ///
473+ /// Returns `None` if the call succeeded, or `Some(error_id)` if it failed.
474+ ///
475+ /// `track_globally` indicates whether the error should be stored as an index in the global error database (for varcall calls), to convey
476+ /// out-of-band, godot-rust specific error information to the caller.
477+ fn handle_fallible_call < F , R > ( call_ctx : & CallContext , code : F , track_globally : bool ) -> Option < i32 >
478+ where
479+ F : FnOnce ( ) -> CallResult < R > + std:: panic:: UnwindSafe ,
480+ {
481+ let outcome: Result < CallResult < R > , PanicPayload > = handle_panic ( || call_ctx. to_string ( ) , code) ;
483482
484483 let call_error = match outcome {
485484 // All good.
486- Ok ( _result) => return ,
485+ Ok ( Ok ( _result) ) => return None ,
487486
488- // Panic occurred (typically through user): forward message.
489- Err ( payload) => CallError :: failed_by_user_panic ( call_ctx, payload) ,
490- } ;
487+ // Error from Godot or godot-rust validation (e.g. parameter conversion).
488+ Ok ( Err ( err) ) => err,
491489
492- let _id = report_call_error ( call_error, false ) ;
493- }
490+ // User panic occurred: forward message.
491+ Err ( panic_msg) => CallError :: failed_by_user_panic ( call_ctx, panic_msg) ,
492+ } ;
494493
495- fn report_call_error ( call_error : CallError , track_globally : bool ) -> i32 {
496494 // Print failed calls to Godot's console.
497495 // TODO Level 1 is not yet set, so this will always print if level != 0. Needs better logic to recognize try_* calls and avoid printing.
498496 // But a bit tricky with multiple threads and re-entrancy; maybe pass in info in error struct.
@@ -501,11 +499,13 @@ fn report_call_error(call_error: CallError, track_globally: bool) -> i32 {
501499 }
502500
503501 // Once there is a way to auto-remove added errors, this could be always true.
504- if track_globally {
502+ let error_id = if track_globally {
505503 call_error_insert ( call_error)
506504 } else {
507505 0
508- }
506+ } ;
507+
508+ Some ( error_id)
509509}
510510
511511// Currently unused; implemented due to temporary need and may come in handy.
0 commit comments