diff --git a/phper/src/classes.rs b/phper/src/classes.rs index ff8df16d..dc5a103a 100644 --- a/phper/src/classes.rs +++ b/phper/src/classes.rs @@ -30,8 +30,7 @@ use std::{ marker::PhantomData, mem::{ManuallyDrop, replace, size_of, transmute, zeroed}, os::raw::c_int, - ptr, - ptr::null_mut, + ptr::{self, null, null_mut}, rc::Rc, slice, }; @@ -233,6 +232,12 @@ fn find_global_class_entry_ptr(name: impl AsRef) -> *mut zend_class_entry { } } +#[derive(Clone)] +enum InnerClassEntry { + Ptr(*const zend_class_entry), + Name(String), +} + /// The [StateClass] holds [zend_class_entry] and inner state, created by /// [Module::add_class](crate::modules::Module::add_class) or /// [ClassEntity::bound_class]. @@ -273,45 +278,55 @@ fn find_global_class_entry_ptr(name: impl AsRef) -> *mut zend_class_entry { /// module /// } /// ``` -pub struct StateClass { - inner: Rc>, - name: Option, +pub struct StateClass { + inner: Rc>, _p: PhantomData, } -impl StateClass<()> { +impl StateClass<[()]> { /// Create from name, which will be looked up from globals. pub fn from_name(name: impl Into) -> Self { Self { - inner: Rc::new(RefCell::new(null_mut())), - name: Some(name.into()), + inner: Rc::new(RefCell::new(InnerClassEntry::Name(name.into()))), _p: PhantomData, } } } -impl StateClass { +impl StateClass { fn null() -> Self { Self { - inner: Rc::new(RefCell::new(null_mut())), - name: None, + inner: Rc::new(RefCell::new(InnerClassEntry::Ptr(null()))), _p: PhantomData, } } fn bind(&self, ptr: *mut zend_class_entry) { - *self.inner.borrow_mut() = ptr; + match &mut *self.inner.borrow_mut() { + InnerClassEntry::Ptr(p) => { + *p = ptr; + } + InnerClassEntry::Name(_) => { + unreachable!("Cannot bind() an StateClass created with from_name()"); + } + } } /// Converts to class entry. pub fn as_class_entry(&self) -> &ClassEntry { - if let Some(name) = &self.name { - ClassEntry::from_globals(name).unwrap() - } else { - unsafe { ClassEntry::from_mut_ptr(*self.inner.borrow()) } + let inner = self.inner.borrow().clone(); + match inner { + InnerClassEntry::Ptr(ptr) => unsafe { ClassEntry::from_ptr(ptr) }, + InnerClassEntry::Name(name) => { + let entry = ClassEntry::from_globals(name).unwrap(); + *self.inner.borrow_mut() = InnerClassEntry::Ptr(entry.as_ptr()); + entry + } } } +} +impl StateClass { /// Create the object from class and call `__construct` with arguments. /// /// If the `__construct` is private, or protected and the called scope isn't @@ -338,7 +353,6 @@ impl Clone for StateClass { fn clone(&self) -> Self { Self { inner: self.inner.clone(), - name: self.name.clone(), _p: self._p, } } @@ -381,39 +395,44 @@ impl Clone for StateClass { /// ``` #[derive(Clone)] pub struct Interface { - inner: Rc>, - name: Option, + inner: Rc>, } impl Interface { fn null() -> Self { Self { - inner: Rc::new(RefCell::new(null_mut())), - name: None, + inner: Rc::new(RefCell::new(InnerClassEntry::Ptr(null()))), } } /// Create a new interface from global name (eg "Stringable", "ArrayAccess") pub fn from_name(name: impl Into) -> Self { Self { - inner: Rc::new(RefCell::new(null_mut())), - name: Some(name.into()), + inner: Rc::new(RefCell::new(InnerClassEntry::Name(name.into()))), } } fn bind(&self, ptr: *mut zend_class_entry) { - if self.name.is_some() { - panic!("Cannot bind() an Interface created with from_name()"); + match &mut *self.inner.borrow_mut() { + InnerClassEntry::Ptr(p) => { + *p = ptr; + } + InnerClassEntry::Name(_) => { + unreachable!("Cannot bind() an Interface created with from_name()"); + } } - *self.inner.borrow_mut() = ptr; } /// Converts to class entry. pub fn as_class_entry(&self) -> &ClassEntry { - if let Some(name) = &self.name { - ClassEntry::from_globals(name).unwrap() - } else { - unsafe { ClassEntry::from_mut_ptr(*self.inner.borrow()) } + let inner = self.inner.borrow().clone(); + match inner { + InnerClassEntry::Ptr(ptr) => unsafe { ClassEntry::from_ptr(ptr) }, + InnerClassEntry::Name(name) => { + let entry = ClassEntry::from_globals(name).unwrap(); + *self.inner.borrow_mut() = InnerClassEntry::Ptr(entry.as_ptr()); + entry + } } } } @@ -433,7 +452,7 @@ pub struct ClassEntity { state_constructor: Rc, method_entities: Vec, property_entities: Vec, - parent: Option>, + parent: Option>, interfaces: Vec, constants: Vec, bound_class: StateClass, @@ -588,8 +607,8 @@ impl ClassEntity { /// module /// } /// ``` - pub fn extends(&mut self, parent: StateClass) { - self.parent = Some(unsafe { transmute::, StateClass<()>>(parent) }); + pub fn extends(&mut self, parent: StateClass) { + self.parent = Some(unsafe { transmute::, StateClass<[()]>>(parent) }); } /// Register class to `implements` the interface, due to the class can @@ -793,7 +812,7 @@ pub struct InterfaceEntity { interface_name: CString, method_entities: Vec, constants: Vec, - extends: Vec &'static ClassEntry>>, + extends: Vec, bound_interface: Interface, } @@ -840,11 +859,7 @@ impl InterfaceEntity { /// interface.extends(Interface::from_name("Stringable")); /// ``` pub fn extends(&mut self, interface: Interface) { - self.extends.push(Box::new(move || { - let entry: &'static ClassEntry = - unsafe { std::mem::transmute(interface.as_class_entry()) }; - entry - })); + self.extends.push(interface); } #[allow(clippy::useless_conversion)] @@ -861,7 +876,7 @@ impl InterfaceEntity { self.bound_interface.bind(class_ce); for interface in &self.extends { - let interface_ce = interface().as_ptr(); + let interface_ce = interface.as_class_entry().as_ptr(); zend_class_implements(class_ce, 1, interface_ce); }