use std::{ffi::CStr, os::raw::c_char, ptr};
use crate::{ffi::zend_ini_entry_def, ffi::zend_register_ini_entries, flags::IniEntryPermission};
pub type IniEntryDef = zend_ini_entry_def;
#[repr(transparent)]
pub struct IniEntryDefs<const N: usize>([IniEntryDef; N]);
unsafe impl<const N: usize> Sync for IniEntryDefs<N> {}
impl<const N: usize> IniEntryDefs<N> {
#[must_use]
pub const fn new(entries: [IniEntryDef; N]) -> Self {
Self(entries)
}
#[must_use]
pub const fn as_slice(&self) -> &[IniEntryDef] {
&self.0
}
}
impl IniEntryDef {
#[must_use]
#[expect(
clippy::needless_pass_by_value,
reason = "IniEntryPermission is Copy and a reference is not const-friendly here"
)]
#[expect(
clippy::cast_possible_truncation,
reason = "lengths are asserted in range above; permission bits fit in u8"
)]
pub const fn new(
name: &'static CStr,
default_value: &'static CStr,
permission: IniEntryPermission,
) -> Self {
let name_length = name.count_bytes();
let value_length = default_value.count_bytes();
assert!(name_length <= u16::MAX as usize, "Invalid name length");
assert!(value_length <= u32::MAX as usize, "Invalid value length");
let mut template = Self::end();
template.name = name.as_ptr();
template.name_length = name_length as u16;
template.value = default_value.as_ptr();
template.value_length = value_length as u32;
template.modifiable = permission.bits() as u8;
template
}
#[must_use]
pub const fn end() -> Self {
Self {
name: ptr::null::<c_char>(),
on_modify: None,
mh_arg1: std::ptr::null_mut(),
mh_arg2: std::ptr::null_mut(),
mh_arg3: std::ptr::null_mut(),
value: std::ptr::null(),
displayer: None,
modifiable: 0,
value_length: 0,
name_length: 0,
}
}
pub fn register(entries: &'static [Self], module_number: i32) {
assert!(
entries.last().is_some_and(|last| last.name.is_null()),
"INI entry tables must be terminated by `IniEntryDef::end()`"
);
unsafe { zend_register_ini_entries(entries.as_ptr(), module_number) };
}
}