@@ -13,10 +13,10 @@ use crate::ffi::{
13
13
zend_stream_init_filename, ZEND_RESULT_CODE_SUCCESS ,
14
14
} ;
15
15
use crate :: types:: { ZendObject , Zval } ;
16
- use crate :: zend:: ExecutorGlobals ;
16
+ use crate :: zend:: { panic_wrapper , ExecutorGlobals } ;
17
17
use parking_lot:: { const_rwlock, RwLock } ;
18
18
use std:: ffi:: { c_char, c_void, CString , NulError } ;
19
- use std:: panic:: { catch_unwind , resume_unwind, RefUnwindSafe } ;
19
+ use std:: panic:: { resume_unwind, RefUnwindSafe } ;
20
20
use std:: path:: Path ;
21
21
use std:: ptr:: null_mut;
22
22
@@ -93,6 +93,12 @@ impl Embed {
93
93
/// Which means subsequent calls to `Embed::eval` or `Embed::run_script` will be able to access
94
94
/// variables defined in previous calls
95
95
///
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
+ ///
96
102
/// # Example
97
103
///
98
104
/// ```
@@ -105,41 +111,36 @@ impl Embed {
105
111
/// assert_eq!(foo.unwrap().string().unwrap(), "foo");
106
112
/// });
107
113
/// ```
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
+ {
109
118
// @TODO handle php thread safe
110
119
//
111
120
// This is to prevent multiple threads from running php at the same time
112
121
// At some point we should detect if php is compiled with thread safety and avoid doing that in this case
113
122
let _guard = RUN_FN_LOCK . write ( ) ;
114
123
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
-
127
124
let panic = unsafe {
128
125
ext_php_rs_embed_callback (
129
126
0 ,
130
127
null_mut ( ) ,
131
- wrapper :: < F > ,
128
+ panic_wrapper :: < R , F > ,
132
129
& func as * const F as * const c_void ,
133
130
)
134
131
} ;
135
132
133
+ // This can happen if there is a bailout
136
134
if panic. is_null ( ) {
137
- return ;
135
+ return R :: default ( ) ;
138
136
}
139
137
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
+ }
143
144
}
144
145
}
145
146
@@ -244,4 +245,13 @@ mod tests {
244
245
panic ! ( "test panic" ) ;
245
246
} ) ;
246
247
}
248
+
249
+ #[ test]
250
+ fn test_return ( ) {
251
+ let foo = Embed :: run ( || {
252
+ return "foo" ;
253
+ } ) ;
254
+
255
+ assert_eq ! ( foo, "foo" ) ;
256
+ }
247
257
}
0 commit comments