@@ -13,10 +13,10 @@ use crate::ffi::{
1313 zend_stream_init_filename, ZEND_RESULT_CODE_SUCCESS ,
1414} ;
1515use crate :: types:: { ZendObject , Zval } ;
16- use crate :: zend:: ExecutorGlobals ;
16+ use crate :: zend:: { panic_wrapper , ExecutorGlobals } ;
1717use parking_lot:: { const_rwlock, RwLock } ;
1818use std:: ffi:: { c_char, c_void, CString , NulError } ;
19- use std:: panic:: { catch_unwind , resume_unwind, RefUnwindSafe } ;
19+ use std:: panic:: { resume_unwind, RefUnwindSafe } ;
2020use std:: path:: Path ;
2121use std:: ptr:: null_mut;
2222
@@ -93,6 +93,12 @@ impl Embed {
9393 /// Which means subsequent calls to `Embed::eval` or `Embed::run_script` will be able to access
9494 /// variables defined in previous calls
9595 ///
96+ /// # Returns
97+ ///
98+ /// * R - The result of the function passed to this method
99+ ///
100+ /// R must implement [`Default`] so it can be returned in case of a bailout
101+ ///
96102 /// # Example
97103 ///
98104 /// ```
@@ -105,41 +111,36 @@ impl Embed {
105111 /// assert_eq!(foo.unwrap().string().unwrap(), "foo");
106112 /// });
107113 /// ```
108- pub fn run < F : Fn ( ) + RefUnwindSafe > ( func : F ) {
114+ pub fn run < R , F : Fn ( ) -> R + RefUnwindSafe > ( func : F ) -> R
115+ where
116+ R : Default ,
117+ {
109118 // @TODO handle php thread safe
110119 //
111120 // This is to prevent multiple threads from running php at the same time
112121 // At some point we should detect if php is compiled with thread safety and avoid doing that in this case
113122 let _guard = RUN_FN_LOCK . write ( ) ;
114123
115- unsafe extern "C" fn wrapper < F : Fn ( ) + RefUnwindSafe > ( ctx : * const c_void ) -> * mut c_void {
116- // we try to catch panic here so we correctly shutdown php if it happens
117- // mandatory when we do assert on test as other test would not run correctly
118- let panic = catch_unwind ( || {
119- ( * ( ctx as * const F ) ) ( ) ;
120- } ) ;
121-
122- let panic_ptr = Box :: into_raw ( Box :: new ( panic) ) ;
123-
124- panic_ptr as * mut c_void
125- }
126-
127124 let panic = unsafe {
128125 ext_php_rs_embed_callback (
129126 0 ,
130127 null_mut ( ) ,
131- wrapper :: < F > ,
128+ panic_wrapper :: < R , F > ,
132129 & func as * const F as * const c_void ,
133130 )
134131 } ;
135132
133+ // This can happen if there is a bailout
136134 if panic. is_null ( ) {
137- return ;
135+ return R :: default ( ) ;
138136 }
139137
140- if let Err ( err) = unsafe { * Box :: from_raw ( panic as * mut std:: thread:: Result < ( ) > ) } {
141- // we resume the panic here so it can be catched correctly by the test framework
142- resume_unwind ( err) ;
138+ match unsafe { * Box :: from_raw ( panic as * mut std:: thread:: Result < R > ) } {
139+ Ok ( r) => r,
140+ Err ( err) => {
141+ // we resume the panic here so it can be catched correctly by the test framework
142+ resume_unwind ( err) ;
143+ }
143144 }
144145 }
145146
@@ -244,4 +245,13 @@ mod tests {
244245 panic ! ( "test panic" ) ;
245246 } ) ;
246247 }
248+
249+ #[ test]
250+ fn test_return ( ) {
251+ let foo = Embed :: run ( || {
252+ return "foo" ;
253+ } ) ;
254+
255+ assert_eq ! ( foo, "foo" ) ;
256+ }
247257}
0 commit comments