use parking_lot::{Mutex, const_mutex};
use crate::builders::ModuleStartup;
pub mod class;
pub mod function;
pub mod property;
pub type ModuleStartupMutex = Mutex<Option<ModuleStartup>>;
#[allow(clippy::declare_interior_mutable_const)]
pub const MODULE_STARTUP_INIT: ModuleStartupMutex = const_mutex(None);
#[allow(clippy::inline_always)]
#[inline(always)]
pub fn ext_php_rs_startup() {
#[cfg(feature = "closure")]
crate::closure::Closure::build();
}
#[must_use]
pub fn startup_guard(func: impl FnOnce() -> crate::error::Result<()>) -> i32 {
let outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(func));
let failure = match outcome {
Ok(Ok(())) => return crate::ffi::ZEND_RESULT_CODE_SUCCESS,
Ok(Err(err)) => format!("module startup failed: {err}"),
Err(payload) => {
let message = payload
.downcast_ref::<&str>()
.map(|s| (*s).to_owned())
.or_else(|| payload.downcast_ref::<String>().cloned())
.unwrap_or_else(|| "non-string panic payload".to_owned());
format!("module startup panicked: {message}")
}
};
crate::error::php_error(&crate::flags::ErrorType::CoreWarning, &failure);
crate::ffi::ZEND_RESULT_CODE_FAILURE
}
#[cfg(all(test, feature = "embed"))]
mod tests {
use super::startup_guard;
use crate::embed::Embed;
use crate::error::Error;
use crate::ffi::{ZEND_RESULT_CODE_FAILURE, ZEND_RESULT_CODE_SUCCESS};
#[test]
fn startup_guard_maps_success_to_zero() {
let code = Embed::run(|| startup_guard(|| Ok(())));
assert_eq!(code, ZEND_RESULT_CODE_SUCCESS);
}
#[test]
fn startup_guard_maps_an_error_to_failure() {
let code = Embed::run(|| startup_guard(|| Err(Error::InvalidScope)));
assert_eq!(code, ZEND_RESULT_CODE_FAILURE);
}
#[test]
fn startup_guard_maps_a_panic_to_failure() {
let code = Embed::run(|| startup_guard(|| panic!("registration exploded")));
assert_eq!(code, ZEND_RESULT_CODE_FAILURE);
}
}
#[must_use]
pub fn failed_module_startup(reason: &str) -> i32 {
crate::error::php_error(
&crate::flags::ErrorType::CoreWarning,
&format!("module could not be built: {reason}"),
);
crate::ffi::ZEND_RESULT_CODE_FAILURE
}