22//! allowing users to store Rust data inside a PHP object.
33
44use std:: {
5- alloc:: Layout ,
65 convert:: TryInto ,
76 fmt:: Debug ,
87 marker:: PhantomData ,
98 mem:: { self , MaybeUninit } ,
109 ops:: { Deref , DerefMut } ,
11- ptr,
10+ ptr:: { self , NonNull } ,
1211 sync:: atomic:: { AtomicBool , AtomicPtr , Ordering } ,
1312} ;
1413
@@ -347,31 +346,19 @@ impl<'a, T: RegisteredClass> FromZval<'a> for &'a T {
347346 const TYPE : DataType = DataType :: Object ( Some ( T :: CLASS_NAME ) ) ;
348347
349348 fn from_zval ( zval : & ' a Zval ) -> Option < Self > {
350- let obj = zval. object ( ) ?;
349+ let cobj = ZendClassObject :: < T > :: from_zend_obj_ptr ( zval. object ( ) ? ) ?;
351350
352- if obj. is_instance :: < T > ( ) {
353- // SAFETY: If the zend object is an instance of `T`, we can guarantee that the memory before
354- // it is occupied by an instance of `T`.
355- unsafe { ( ( obj as * mut ZendObject ) as * mut T ) . offset ( -1 ) . as_ref ( ) }
356- } else {
357- None
358- }
351+ Some ( unsafe { & * cobj. obj . as_mut_ptr ( ) } )
359352 }
360353}
361354
362355impl < ' a , T : RegisteredClass > FromZval < ' a > for & ' a mut T {
363356 const TYPE : DataType = DataType :: Object ( Some ( T :: CLASS_NAME ) ) ;
364357
365358 fn from_zval ( zval : & ' a Zval ) -> Option < Self > {
366- let obj = zval. object ( ) ?;
359+ let cobj = ZendClassObject :: < T > :: from_zend_obj_ptr ( zval. object ( ) ? ) ?;
367360
368- if obj. is_instance :: < T > ( ) {
369- // SAFETY: If the zend object is an instance of `T`, we can guarantee that the memory before
370- // it is occupied by an instance of `T`.
371- unsafe { ( ( obj as * mut ZendObject ) as * mut T ) . offset ( -1 ) . as_mut ( ) }
372- } else {
373- None
374- }
361+ Some ( unsafe { & mut * cobj. obj . as_mut_ptr ( ) } )
375362 }
376363}
377364
@@ -439,7 +426,7 @@ where
439426/// Representation of a Zend class object in memory. Usually seen through its managed variant
440427/// of [`ClassObject`].
441428#[ repr( C ) ]
442- pub ( crate ) struct ZendClassObject < T : RegisteredClass > {
429+ pub ( crate ) struct ZendClassObject < T > {
443430 obj : MaybeUninit < T > ,
444431 std : zend_object ,
445432}
@@ -486,13 +473,46 @@ impl<T: RegisteredClass> ZendClassObject<T> {
486473 }
487474 }
488475
476+ /// Returns a reference to the [`ZendClassObject`] of a given zend object `obj`. Returns [`None`]
477+ /// if the given object is not of the type `T`.
478+ ///
479+ /// # Parameters
480+ ///
481+ /// * `obj` - The zend object to get the [`ZendClassObject`] for.
482+ pub ( crate ) fn from_zend_obj_ptr ( obj : & zend_object ) -> Option < & mut Self > {
483+ let ptr = obj as * const zend_object as * const i8 ;
484+ let ptr = unsafe {
485+ let ptr = ptr. offset ( 0 - Self :: std_offset ( ) as isize ) as * const Self ;
486+ ( ptr as * mut Self ) . as_mut ( ) ?
487+ } ;
488+
489+ if ptr. std . is_instance :: < T > ( ) {
490+ Some ( ptr)
491+ } else {
492+ None
493+ }
494+ }
495+
489496 /// Returns a mutable reference to the underlying Zend object.
490497 pub ( crate ) fn get_mut_zend_obj ( & mut self ) -> & mut zend_object {
491498 & mut self . std
492499 }
493500}
494501
495- impl < T : RegisteredClass > Drop for ZendClassObject < T > {
502+ impl < T > ZendClassObject < T > {
503+ /// Returns the offset of the `std` property in the class object.
504+ pub ( crate ) fn std_offset ( ) -> usize {
505+ unsafe {
506+ let null = NonNull :: < Self > :: dangling ( ) ;
507+ let base = null. as_ref ( ) as * const Self ;
508+ let std = & null. as_ref ( ) . std as * const zend_object ;
509+
510+ ( std as usize ) - ( base as usize )
511+ }
512+ }
513+ }
514+
515+ impl < T > Drop for ZendClassObject < T > {
496516 fn drop ( & mut self ) {
497517 // SAFETY: All constructors guarantee that `obj` is valid.
498518 unsafe { std:: ptr:: drop_in_place ( self . obj . as_mut_ptr ( ) ) } ;
@@ -585,8 +605,7 @@ impl ZendObjectHandlers {
585605 /// Caller must guarantee that the `ptr` given is a valid memory location.
586606 pub unsafe fn init < T > ( ptr : * mut ZendObjectHandlers ) {
587607 pub unsafe extern "C" fn free_obj < T > ( object : * mut zend_object ) {
588- let layout = Layout :: new :: < T > ( ) ;
589- let offset = layout. size ( ) ;
608+ let offset = ZendClassObject :: < T > :: std_offset ( ) ;
590609
591610 // Cast to *mut u8 to work in byte offsets
592611 let ptr = ( object as * mut u8 ) . offset ( 0 - offset as isize ) as * mut T ;
@@ -599,7 +618,7 @@ impl ZendObjectHandlers {
599618 }
600619
601620 std:: ptr:: copy_nonoverlapping ( & std_object_handlers, ptr, 1 ) ;
602- let offset = std :: mem :: size_of :: < T > ( ) ;
621+ let offset = ZendClassObject :: < T > :: std_offset ( ) ;
603622 ( * ptr) . offset = offset as _ ;
604623 ( * ptr) . free_obj = Some ( free_obj :: < T > ) ;
605624 }
0 commit comments