1use crate::{
14 alloc::EBox,
15 classes::ClassEntry,
16 functions::{ZFunc, call_internal, call_raw_common},
17 sys::*,
18 values::ZVal,
19};
20use phper_alloc::{RefClone, ToRefOwned};
21use std::{
22 any::Any,
23 ffi::c_void,
24 fmt::{self, Debug},
25 marker::PhantomData,
26 mem::{ManuallyDrop, replace, size_of},
27 ops::{Deref, DerefMut},
28 ptr::null_mut,
29};
30
31#[repr(transparent)]
33pub struct ZObj {
34 inner: zend_object,
35 _p: PhantomData<*mut ()>,
36}
37
38impl ZObj {
39 #[inline]
49 pub unsafe fn from_ptr<'a>(ptr: *const zend_object) -> &'a Self {
50 unsafe { (ptr as *const Self).as_ref().expect("ptr should't be null") }
51 }
52
53 #[inline]
59 pub unsafe fn try_from_ptr<'a>(ptr: *const zend_object) -> Option<&'a Self> {
60 unsafe { (ptr as *const Self).as_ref() }
61 }
62
63 #[inline]
73 pub unsafe fn from_mut_ptr<'a>(ptr: *mut zend_object) -> &'a mut Self {
74 unsafe { (ptr as *mut Self).as_mut().expect("ptr should't be null") }
75 }
76
77 #[inline]
83 pub unsafe fn try_from_mut_ptr<'a>(ptr: *mut zend_object) -> Option<&'a mut Self> {
84 unsafe { (ptr as *mut Self).as_mut() }
85 }
86
87 pub const fn as_ptr(&self) -> *const zend_object {
89 &self.inner
90 }
91
92 #[inline]
94 pub fn as_mut_ptr(&mut self) -> *mut zend_object {
95 &mut self.inner
96 }
97
98 pub unsafe fn as_state_obj<T>(&self) -> &StateObj<T> {
105 unsafe { StateObj::from_object_ptr(self.as_ptr()) }
106 }
107
108 pub unsafe fn as_mut_state_obj<T>(&mut self) -> &mut StateObj<T> {
115 unsafe { StateObj::from_mut_object_ptr(self.as_mut_ptr()) }
116 }
117
118 #[inline]
120 pub fn handle(&self) -> u32 {
121 self.inner.handle
122 }
123
124 pub fn get_class(&self) -> &ClassEntry {
126 unsafe { ClassEntry::from_ptr(self.inner.ce) }
127 }
128
129 pub fn get_mut_class(&mut self) -> &mut ClassEntry {
131 unsafe { ClassEntry::from_mut_ptr(self.inner.ce) }
132 }
133
134 pub fn get_property(&self, name: impl AsRef<str>) -> &ZVal {
136 let object = self.as_ptr() as *mut _;
137 let prop = Self::inner_get_property(self.inner.ce, object, name);
138 unsafe { ZVal::from_ptr(prop) }
139 }
140
141 pub fn get_mut_property(&mut self, name: impl AsRef<str>) -> &mut ZVal {
143 let object = self.as_mut_ptr();
144 let prop = Self::inner_get_property(self.inner.ce, object, name);
145 unsafe { ZVal::from_mut_ptr(prop) }
146 }
147
148 #[allow(clippy::useless_conversion)]
149 fn inner_get_property(
150 scope: *mut zend_class_entry, object: *mut zend_object, name: impl AsRef<str>,
151 ) -> *mut zval {
152 let name = name.as_ref();
153
154 unsafe {
155 #[cfg(phper_major_version = "8")]
156 {
157 zend_read_property(
158 scope,
159 object,
160 name.as_ptr().cast(),
161 name.len().try_into().unwrap(),
162 true.into(),
163 null_mut(),
164 )
165 }
166 #[cfg(phper_major_version = "7")]
167 {
168 let mut zv = std::mem::zeroed::<zval>();
169 phper_zval_obj(&mut zv, object);
170 zend_read_property(
171 scope,
172 &mut zv,
173 name.as_ptr().cast(),
174 name.len().try_into().unwrap(),
175 true.into(),
176 null_mut(),
177 )
178 }
179 }
180 }
181
182 #[allow(clippy::useless_conversion)]
184 pub fn set_property(&mut self, name: impl AsRef<str>, val: impl Into<ZVal>) {
185 let name = name.as_ref();
186 let mut val = val.into();
187 unsafe {
188 #[cfg(phper_major_version = "8")]
189 {
190 zend_update_property(
191 self.inner.ce,
192 &mut self.inner,
193 name.as_ptr().cast(),
194 name.len().try_into().unwrap(),
195 val.as_mut_ptr(),
196 )
197 }
198 #[cfg(phper_major_version = "7")]
199 {
200 let mut zv = std::mem::zeroed::<zval>();
201 phper_zval_obj(&mut zv, self.as_mut_ptr());
202 zend_update_property(
203 self.inner.ce,
204 &mut zv,
205 name.as_ptr().cast(),
206 name.len().try_into().unwrap(),
207 val.as_mut_ptr(),
208 )
209 }
210 }
211 }
212
213 pub fn call(
231 &mut self, method_name: &str, arguments: impl AsMut<[ZVal]>,
232 ) -> crate::Result<ZVal> {
233 let mut method = method_name.into();
234 call_internal(&mut method, Some(self), arguments)
235 }
236
237 pub(crate) fn call_construct(&mut self, arguments: impl AsMut<[ZVal]>) -> crate::Result<()> {
238 unsafe {
239 let Some(get_constructor) = (*self.inner.handlers).get_constructor else {
240 return Ok(());
241 };
242
243 let mut val = call_raw_common(|val| {
246 let f = get_constructor(self.as_mut_ptr());
247 if !f.is_null() {
248 phper_zval_func(val.as_mut_ptr(), f);
249 }
250 })?;
251
252 if val.get_type_info().is_null() {
253 return Ok(());
254 }
255
256 let f = phper_z_func_p(val.as_mut_ptr());
257 let zend_fn = ZFunc::from_mut_ptr(f);
258 zend_fn.call(Some(self), arguments)?;
259
260 Ok(())
261 }
262 }
263
264 pub(crate) unsafe fn gc_refcount(&self) -> u32 {
265 unsafe { phper_zend_object_gc_refcount(self.as_ptr()) }
266 }
267}
268
269impl Drop for ZObj {
270 fn drop(&mut self) {
271 unsafe {
272 phper_zend_object_release(self.as_mut_ptr());
273 }
274 }
275}
276
277impl ToRefOwned for ZObj {
278 type Owned = ZObject;
279
280 fn to_ref_owned(&mut self) -> Self::Owned {
281 let mut val = ManuallyDrop::new(ZVal::default());
282 unsafe {
283 phper_zval_obj(val.as_mut_ptr(), self.as_mut_ptr());
284 phper_z_addref_p(val.as_mut_ptr());
285 ZObject::from_raw_cast(val.as_mut_z_obj().unwrap().as_mut_ptr())
286 }
287 }
288}
289
290impl Debug for ZObj {
291 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
292 common_fmt(self, f, "ZObj")
293 }
294}
295
296pub type ZObject = EBox<ZObj>;
302
303impl ZObject {
304 pub fn new(class_entry: &ClassEntry, arguments: impl AsMut<[ZVal]>) -> crate::Result<Self> {
306 class_entry.new_object(arguments)
307 }
308
309 pub fn new_by_class_name(
311 class_name: impl AsRef<str>, arguments: &mut [ZVal],
312 ) -> crate::Result<Self> {
313 let class_entry = ClassEntry::from_globals(class_name)?;
314 Self::new(class_entry, arguments)
315 }
316
317 pub fn new_by_std_class() -> Self {
319 Self::new_by_class_name("stdclass", &mut []).unwrap()
320 }
321}
322
323impl RefClone for ZObject {
324 #[inline]
325 fn ref_clone(&mut self) -> Self {
326 self.to_ref_owned()
327 }
328}
329
330pub(crate) type AnyState = *mut dyn Any;
331
332#[repr(C)]
334pub struct StateObj<T> {
335 any_state: AnyState,
336 object: ZObj,
337 _p: PhantomData<T>,
338}
339
340impl<T> StateObj<T> {
341 pub(crate) const fn offset() -> usize {
344 size_of::<AnyState>()
345 }
346
347 #[inline]
348 pub(crate) unsafe fn from_mut_ptr<'a>(ptr: *mut c_void) -> &'a mut Self {
349 unsafe { (ptr as *mut Self).as_mut().expect("ptr should't be null") }
350 }
351
352 pub(crate) unsafe fn from_object_ptr<'a>(ptr: *const zend_object) -> &'a Self {
353 unsafe {
354 ((ptr as usize - Self::offset()) as *const Self)
355 .as_ref()
356 .unwrap()
357 }
358 }
359
360 pub(crate) unsafe fn from_mut_object_ptr<'a>(ptr: *mut zend_object) -> &'a mut Self {
361 unsafe {
362 ((ptr as usize - Self::offset()) as *mut Self)
363 .as_mut()
364 .unwrap()
365 }
366 }
367
368 pub(crate) unsafe fn drop_state(&mut self) {
369 unsafe {
370 drop(Box::from_raw(self.any_state));
371 }
372 }
373
374 #[inline]
375 pub(crate) fn as_mut_any_state(&mut self) -> &mut AnyState {
376 &mut self.any_state
377 }
378
379 #[inline]
381 pub fn as_object(&self) -> &ZObj {
382 &self.object
383 }
384
385 #[inline]
387 pub fn as_mut_object(&mut self) -> &mut ZObj {
388 &mut self.object
389 }
390}
391
392impl<T: 'static> StateObj<T> {
393 pub fn as_state(&self) -> &T {
395 unsafe {
396 let any_state = self.any_state.as_ref().unwrap();
397 any_state.downcast_ref().unwrap()
398 }
399 }
400
401 pub fn as_mut_state(&mut self) -> &mut T {
403 unsafe {
404 let any_state = self.any_state.as_mut().unwrap();
405 any_state.downcast_mut().unwrap()
406 }
407 }
408}
409
410impl<T> Deref for StateObj<T> {
411 type Target = ZObj;
412
413 fn deref(&self) -> &Self::Target {
414 &self.object
415 }
416}
417
418impl<T> DerefMut for StateObj<T> {
419 fn deref_mut(&mut self) -> &mut Self::Target {
420 &mut self.object
421 }
422}
423
424impl<T> Debug for StateObj<T> {
425 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
426 common_fmt(self, f, "StateObj")
427 }
428}
429
430pub type StateObject<T> = EBox<StateObj<T>>;
436
437impl<T> StateObject<T> {
438 #[inline]
439 pub(crate) fn from_raw_object(object: *mut zend_object) -> Self {
440 unsafe { Self::from_raw(StateObj::from_mut_object_ptr(object)) }
441 }
442
443 #[inline]
444 pub(crate) fn into_raw_object(self) -> *mut zend_object {
445 ManuallyDrop::new(self).as_mut_ptr()
446 }
447
448 pub fn into_z_object(self) -> ZObject {
450 unsafe { ZObject::from_raw_cast(self.into_raw_object()) }
451 }
452}
453
454impl<T: 'static> StateObject<T> {
455 pub fn into_state(mut self) -> Option<T> {
462 unsafe {
463 if self.gc_refcount() != 1 {
464 return None;
465 }
466 let null: AnyState = Box::into_raw(Box::new(()));
467 let ptr = replace(self.as_mut_any_state(), null);
468 Some(*Box::from_raw(ptr).downcast().unwrap())
469 }
470 }
471}
472
473fn common_fmt(this: &ZObj, f: &mut fmt::Formatter<'_>, name: &str) -> fmt::Result {
474 let mut d = f.debug_struct(name);
475 match this.get_class().get_name().to_c_str() {
476 Ok(class_name) => {
477 d.field("class", &class_name);
478 }
479 Err(e) => {
480 d.field("class", &e);
481 }
482 }
483 d.field("handle", &this.handle());
484 d.finish()
485}