use std::{
ffi::{c_void, CString},
mem, ptr,
};
use crate::{
bindings::{
ext_php_rs_php_build_id, zend_module_entry, USING_ZTS, ZEND_DEBUG, ZEND_MODULE_API_NO,
},
errors::Result,
};
use super::function::FunctionEntry;
pub type ModuleEntry = zend_module_entry;
pub type StartupShutdownFunc = extern "C" fn(_type: i32, _module_number: i32) -> i32;
pub type InfoFunc = extern "C" fn(zend_module: *mut ModuleEntry);
#[derive(Debug, Clone)]
pub struct ModuleBuilder {
name: String,
version: String,
module: ModuleEntry,
functions: Vec<FunctionEntry>,
}
impl ModuleBuilder {
pub fn new<T: Into<String>, U: Into<String>>(name: T, version: U) -> Self {
Self {
name: name.into(),
version: version.into(),
module: ModuleEntry {
size: mem::size_of::<ModuleEntry>() as u16,
zend_api: ZEND_MODULE_API_NO,
zend_debug: ZEND_DEBUG as u8,
zts: USING_ZTS as u8,
ini_entry: ptr::null(),
deps: ptr::null(),
name: ptr::null(),
functions: ptr::null(),
module_startup_func: None,
module_shutdown_func: None,
request_startup_func: None,
request_shutdown_func: None,
info_func: None,
version: ptr::null(),
globals_size: 0,
#[cfg(not(php_zts))]
globals_ptr: ptr::null::<c_void>() as *mut c_void,
#[cfg(php_zts)]
globals_id_ptr: ptr::null::<c_void>() as *mut crate::bindings::ts_rsrc_id,
globals_ctor: None,
globals_dtor: None,
post_deactivate_func: None,
module_started: 0,
type_: 0,
handle: ptr::null::<c_void>() as *mut c_void,
module_number: 0,
build_id: unsafe { ext_php_rs_php_build_id() },
},
functions: vec![],
}
}
pub fn startup_function(mut self, func: StartupShutdownFunc) -> Self {
self.module.module_startup_func = Some(func);
self
}
pub fn shutdown_function(mut self, func: StartupShutdownFunc) -> Self {
self.module.module_shutdown_func = Some(func);
self
}
pub fn request_startup_function(mut self, func: StartupShutdownFunc) -> Self {
self.module.module_startup_func = Some(func);
self
}
pub fn request_shutdown_function(mut self, func: StartupShutdownFunc) -> Self {
self.module.module_shutdown_func = Some(func);
self
}
pub fn info_function(mut self, func: InfoFunc) -> Self {
self.module.info_func = Some(func);
self
}
pub fn function(mut self, func: FunctionEntry) -> Self {
self.functions.push(func);
self
}
pub fn build(mut self) -> Result<ModuleEntry> {
self.functions.push(FunctionEntry::end());
self.module.functions =
Box::into_raw(self.functions.into_boxed_slice()) as *const FunctionEntry;
self.module.name = CString::new(self.name)?.into_raw();
self.module.version = CString::new(self.version)?.into_raw();
Ok(self.module)
}
}
impl ModuleEntry {
pub fn into_raw(self) -> *mut Self {
Box::into_raw(Box::new(self))
}
}
#[doc(hidden)]
#[inline(always)]
pub fn ext_php_rs_startup() {
#[cfg(feature = "closure")]
crate::php::types::closure::Closure::build();
}