#![allow(unsafe_code)]
use std::ffi::{CString, c_int};
use ext_php_rs::types::Zval;
unsafe extern "C" {
fn folk_zts_thread_init();
fn folk_zts_thread_shutdown();
fn folk_zts_request_startup() -> c_int;
fn folk_zts_request_shutdown();
fn folk_zts_execute_script(filename: *const std::ffi::c_char) -> c_int;
fn folk_zts_call_dispatch(
func_name: *const std::ffi::c_char,
method_zval: *mut Zval,
params_zval: *mut Zval,
retval: *mut Zval,
) -> c_int;
fn folk_zts_is_enabled() -> c_int;
}
pub fn is_zts() -> bool {
unsafe { folk_zts_is_enabled() != 0 }
}
pub struct ZtsThreadGuard {
_private: (),
}
impl ZtsThreadGuard {
pub fn new() -> Self {
unsafe {
folk_zts_thread_init();
}
Self { _private: () }
}
}
impl Default for ZtsThreadGuard {
fn default() -> Self {
Self::new()
}
}
impl Drop for ZtsThreadGuard {
fn drop(&mut self) {
unsafe {
folk_zts_thread_shutdown();
}
}
}
pub fn request_startup() -> anyhow::Result<()> {
let ret = unsafe { folk_zts_request_startup() };
if ret == 0 {
Ok(())
} else {
anyhow::bail!("php_request_startup failed (code {ret})")
}
}
pub fn request_shutdown() {
unsafe {
folk_zts_request_shutdown();
}
}
pub fn execute_script(filename: &str) -> anyhow::Result<()> {
let c_filename =
CString::new(filename).map_err(|_| anyhow::anyhow!("filename contains null byte"))?;
let ret = unsafe { folk_zts_execute_script(c_filename.as_ptr()) };
if ret != 0 {
Ok(())
} else {
anyhow::bail!("php_execute_script failed for {filename}")
}
}
pub fn call_dispatch(
func_name: &str,
method: &str,
params: &serde_json::Value,
) -> anyhow::Result<serde_json::Value> {
let c_func =
CString::new(func_name).map_err(|_| anyhow::anyhow!("func_name contains null byte"))?;
let mut method_zval = Zval::new();
method_zval
.set_string(method, false)
.map_err(|e| anyhow::anyhow!("set_string failed: {e}"))?;
let mut params_zval = crate::zval_convert::value_to_zval(params);
let mut retval = Zval::new();
let ret = unsafe {
folk_zts_call_dispatch(
c_func.as_ptr(),
&raw mut method_zval,
&raw mut params_zval,
&raw mut retval,
)
};
if ret != 0 {
anyhow::bail!("call_user_function({func_name}) failed (code {ret})");
}
Ok(crate::zval_convert::zval_to_value(&retval))
}