use std::cell::UnsafeCell;
use std::ffi::CString;
use std::mem::MaybeUninit;
use std::sync::Once;
use crate::args::ArgInfo;
use crate::ffi::zend_module_entry;
use crate::zend::FunctionEntry;
pub type ModuleEntry = zend_module_entry;
pub struct ModuleAllocations {
pub functions: Box<[FunctionEntry]>,
pub arg_info: Box<[Box<[ArgInfo]>]>,
pub name: CString,
pub version: CString,
}
pub struct StaticModuleEntry {
init: Once,
inner: UnsafeCell<MaybeUninit<ModuleEntry>>,
owned: UnsafeCell<MaybeUninit<ModuleAllocations>>,
}
unsafe impl Sync for StaticModuleEntry {}
impl Default for StaticModuleEntry {
fn default() -> Self {
Self::new()
}
}
impl StaticModuleEntry {
#[must_use]
pub const fn new() -> Self {
Self {
init: Once::new(),
inner: UnsafeCell::new(MaybeUninit::uninit()),
owned: UnsafeCell::new(MaybeUninit::uninit()),
}
}
pub fn get_or_init(
&self,
f: impl FnOnce() -> (ModuleEntry, ModuleAllocations),
) -> *mut ModuleEntry {
self.init.call_once(|| {
let (entry, owned) = f();
unsafe {
(*self.owned.get()).write(owned);
(*self.inner.get()).write(entry);
}
});
unsafe { (*self.inner.get()).as_mut_ptr() }
}
}