1#![allow(unsafe_code)]
6
7use std::ffi::{CString, c_int};
8
9use ext_php_rs::types::Zval;
10
11unsafe extern "C" {
12 fn folk_zts_thread_init();
13 fn folk_zts_thread_shutdown();
14 fn folk_zts_request_startup() -> c_int;
15 fn folk_zts_request_shutdown();
16 fn folk_zts_execute_script(filename: *const std::ffi::c_char) -> c_int;
17 fn folk_zts_call_dispatch(
18 func_name: *const std::ffi::c_char,
19 method_zval: *mut Zval,
20 params_zval: *mut Zval,
21 retval: *mut Zval,
22 ) -> c_int;
23 fn folk_zts_is_enabled() -> c_int;
24}
25
26pub fn is_zts() -> bool {
28 unsafe { folk_zts_is_enabled() != 0 }
29}
30
31pub struct ZtsThreadGuard {
36 _private: (),
37}
38
39impl ZtsThreadGuard {
40 pub fn new() -> Self {
42 unsafe {
43 folk_zts_thread_init();
44 }
45 Self { _private: () }
46 }
47}
48
49impl Default for ZtsThreadGuard {
50 fn default() -> Self {
51 Self::new()
52 }
53}
54
55impl Drop for ZtsThreadGuard {
56 fn drop(&mut self) {
57 unsafe {
58 folk_zts_thread_shutdown();
59 }
60 }
61}
62
63pub fn request_startup() -> anyhow::Result<()> {
68 let ret = unsafe { folk_zts_request_startup() };
69 if ret == 0 {
70 Ok(())
71 } else {
72 anyhow::bail!("php_request_startup failed (code {ret})")
73 }
74}
75
76pub fn request_shutdown() {
78 unsafe {
79 folk_zts_request_shutdown();
80 }
81}
82
83pub fn execute_script(filename: &str) -> anyhow::Result<()> {
88 let c_filename =
89 CString::new(filename).map_err(|_| anyhow::anyhow!("filename contains null byte"))?;
90 let ret = unsafe { folk_zts_execute_script(c_filename.as_ptr()) };
91 if ret != 0 {
92 Ok(())
93 } else {
94 anyhow::bail!("php_execute_script failed for {filename}")
95 }
96}
97
98pub fn call_dispatch(
106 func_name: &str,
107 method: &str,
108 params: &serde_json::Value,
109) -> anyhow::Result<serde_json::Value> {
110 let c_func =
111 CString::new(func_name).map_err(|_| anyhow::anyhow!("func_name contains null byte"))?;
112
113 let mut method_zval = Zval::new();
115 method_zval
116 .set_string(method, false)
117 .map_err(|e| anyhow::anyhow!("set_string failed: {e}"))?;
118
119 let mut params_zval = crate::zval_convert::value_to_zval(params);
120 let mut retval = Zval::new();
121
122 let ret = unsafe {
123 folk_zts_call_dispatch(
124 c_func.as_ptr(),
125 &raw mut method_zval,
126 &raw mut params_zval,
127 &raw mut retval,
128 )
129 };
130
131 if ret != 0 {
132 anyhow::bail!("call_user_function({func_name}) failed (code {ret})");
133 }
134
135 Ok(crate::zval_convert::zval_to_value(&retval))
136}