1use cfg_if::cfg_if;
5
6use crate::ffi::{_efree, _emalloc, _estrdup, ZEND_MM_ALIGNMENT};
7use std::{
8 alloc::Layout,
9 ffi::{CString, c_char, c_void},
10};
11
12#[must_use]
27pub fn emalloc(layout: Layout) -> *mut u8 {
28 if layout.align() > ZEND_MM_ALIGNMENT.unsigned_abs() {
29 return std::ptr::null_mut();
30 }
31 let size = layout.size();
32
33 (unsafe {
34 cfg_if! {
35 if #[cfg(php_debug)] {
36 #[allow(clippy::used_underscore_items)]
37 _emalloc(size as _, std::ptr::null_mut(), 0, std::ptr::null_mut(), 0)
38 } else {
39 #[allow(clippy::used_underscore_items)]
40 _emalloc(size as _)
41 }
42 }
43 })
44 .cast::<u8>()
45}
46
47pub unsafe fn efree(ptr: *mut u8) {
59 cfg_if! {
60 if #[cfg(php_debug)] {
61 #[allow(clippy::used_underscore_items)]
62 unsafe {
63 _efree(
64 ptr.cast::<c_void>(),
65 std::ptr::null_mut(),
66 0,
67 std::ptr::null_mut(),
68 0,
69 );
70 }
71 } else {
72 #[allow(clippy::used_underscore_items)]
73 unsafe {
74 _efree(ptr.cast::<c_void>());
75 }
76 }
77 }
78}
79
80pub fn estrdup(string: impl Into<Vec<u8>>) -> *mut c_char {
91 let string = unsafe { CString::from_vec_unchecked(string.into()) }.into_raw();
92
93 let result = unsafe {
94 cfg_if! {
95 if #[cfg(php_debug)] {
96 #[allow(clippy::used_underscore_items)]
97 _estrdup(string, std::ptr::null_mut(), 0, std::ptr::null_mut(), 0)
98 } else {
99 #[allow(clippy::used_underscore_items)]
100 _estrdup(string)
101 }
102 }
103 };
104
105 drop(unsafe { CString::from_raw(string) });
106 result
107}
108
109#[cfg(test)]
110#[cfg(feature = "embed")]
111mod test {
112 use super::*;
113 use crate::embed::Embed;
114 use std::ffi::CStr;
115
116 #[test]
117 fn test_emalloc() {
118 Embed::run(|| {
119 let layout = Layout::from_size_align(16, 8).expect("should create layout");
120 let ptr = emalloc(layout);
121 assert!(!ptr.is_null());
122 unsafe { efree(ptr) };
123 });
124 }
125
126 #[test]
127 fn test_estrdup() {
128 Embed::run(|| {
129 let original = "Hello, world!";
130 let duplicated = estrdup(original);
131 assert!(!duplicated.is_null());
132
133 let duplicated_str = unsafe { CStr::from_ptr(duplicated) };
134 assert_eq!(
135 duplicated_str.to_str().expect("should convert to str"),
136 original
137 );
138
139 unsafe { efree(duplicated.cast::<u8>()) }
140 });
141 }
142}