Skip to content

refactor: optimizing extends and implements #193

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 3, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 55 additions & 40 deletions phper/src/classes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -233,6 +232,12 @@ fn find_global_class_entry_ptr(name: impl AsRef<str>) -> *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].
Expand Down Expand Up @@ -273,45 +278,55 @@ fn find_global_class_entry_ptr(name: impl AsRef<str>) -> *mut zend_class_entry {
/// module
/// }
/// ```
pub struct StateClass<T> {
inner: Rc<RefCell<*mut zend_class_entry>>,
name: Option<String>,
pub struct StateClass<T: ?Sized> {
inner: Rc<RefCell<InnerClassEntry>>,
_p: PhantomData<T>,
}

impl StateClass<()> {
impl StateClass<[()]> {
/// Create from name, which will be looked up from globals.
pub fn from_name(name: impl Into<String>) -> 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<T> StateClass<T> {
impl<T: ?Sized> StateClass<T> {
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<T: 'static> StateClass<T> {
/// Create the object from class and call `__construct` with arguments.
///
/// If the `__construct` is private, or protected and the called scope isn't
Expand All @@ -338,7 +353,6 @@ impl<T> Clone for StateClass<T> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
name: self.name.clone(),
_p: self._p,
}
}
Expand Down Expand Up @@ -381,39 +395,44 @@ impl<T> Clone for StateClass<T> {
/// ```
#[derive(Clone)]
pub struct Interface {
inner: Rc<RefCell<*mut zend_class_entry>>,
name: Option<String>,
inner: Rc<RefCell<InnerClassEntry>>,
}

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<String>) -> 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) {

This comment was marked as duplicate.

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
}
}
}
}
Expand All @@ -433,7 +452,7 @@ pub struct ClassEntity<T: 'static> {
state_constructor: Rc<StateConstructor>,
method_entities: Vec<MethodEntity>,
property_entities: Vec<PropertyEntity>,
parent: Option<StateClass<()>>,
parent: Option<StateClass<[()]>>,
interfaces: Vec<Interface>,
constants: Vec<ConstantEntity>,
bound_class: StateClass<T>,
Expand Down Expand Up @@ -588,8 +607,8 @@ impl<T: 'static> ClassEntity<T> {
/// module
/// }
/// ```
pub fn extends<S: 'static>(&mut self, parent: StateClass<S>) {
self.parent = Some(unsafe { transmute::<StateClass<S>, StateClass<()>>(parent) });
pub fn extends<S: ?Sized>(&mut self, parent: StateClass<S>) {
self.parent = Some(unsafe { transmute::<StateClass<S>, StateClass<[()]>>(parent) });
}

/// Register class to `implements` the interface, due to the class can
Expand Down Expand Up @@ -793,7 +812,7 @@ pub struct InterfaceEntity {
interface_name: CString,
method_entities: Vec<MethodEntity>,
constants: Vec<ConstantEntity>,
extends: Vec<Box<dyn Fn() -> &'static ClassEntry>>,
extends: Vec<Interface>,
bound_interface: Interface,
}

Expand Down Expand Up @@ -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)]
Expand All @@ -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);
}

Expand Down
Loading