Skip to content

Commit

Permalink
Try to make StateObj generic
Browse files Browse the repository at this point in the history
Signed-off-by: Dusan Malusev <[email protected]>
  • Loading branch information
CodeLieutenant committed Jun 20, 2024
1 parent f5e5b5e commit 469452b
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 92 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 29 additions & 22 deletions examples/complex/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,15 @@ mod args_bindings;

use std::convert::Infallible;
use std::ffi::CStr;
use std::mem::size_of;

use args_bindings::{arginfo_Complex_say_hello, arginfo_Complex_throw_exception, arginfo_Complex_get_all_ini};
use args_bindings::{
arginfo_Complex_get_all_ini, arginfo_Complex_say_hello, arginfo_Complex_throw_exception,
};

use phper::arrays::ZArray;
use phper::ini::{ini_get, Policy};
use phper::{
modules::Module,
php_get_module,
values::ZVal,
zend_args,
};
use phper::{modules::Module, php_get_module, values::ZVal, zend_args};

fn say_hello(arguments: &mut [ZVal]) -> phper::Result<String> {
let name = &mut arguments[0];
Expand Down Expand Up @@ -59,23 +57,32 @@ pub fn get_module() -> Module {
module.on_request_init(|_info| {});
module.on_request_shutdown(|_info| {});

// register functions
module.add_function(
"Comples\\say_hello",
zend_args!(arginfo_Complex_say_hello),
say_hello,
)
.add_function("Complex\\throw_exception", zend_args!(arginfo_Complex_throw_exception), throw_exception)
.add_function("Comples\\get_all_ini", zend_args!(arginfo_Complex_get_all_ini), |_: &mut [ZVal]| {
let mut arr = ZArray::new();
module
.add_function(
"Comples\\say_hello",
zend_args!(arginfo_Complex_say_hello),
say_hello,
)
.add_function(
"Complex\\throw_exception",
zend_args!(arginfo_Complex_throw_exception),
throw_exception,
)
.add_function(
"Comples\\get_all_ini",
zend_args!(arginfo_Complex_get_all_ini),
|_: &mut [ZVal]| {
let mut arr = ZArray::new();

let complex_enable = ZVal::from(ini_get::<bool>("complex.enable"));
arr.insert("complex.enable", complex_enable);
let complex_enable = ZVal::from(ini_get::<bool>("complex.enable"));
arr.insert("complex.enable", complex_enable);

let complex_description = ZVal::from(ini_get::<Option<&CStr>>("complex.description"));
arr.insert("complex.description", complex_description);
Ok::<_, Infallible>(arr)
});
let complex_description =
ZVal::from(ini_get::<Option<&CStr>>("complex.description"));
arr.insert("complex.description", complex_description);
Ok::<_, Infallible>(arr)
},
);

//
// // register classes
Expand Down
26 changes: 11 additions & 15 deletions phper/src/classes/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use super::{
/// third-party resources.*
pub struct ClassEntity<T> {
class: zend_class_entry,
state_constructor: Rc<StateConstructor>,
state_constructor: Rc<StateConstructor<T>>,
method_entities: SmallVec<[FunctionEntry; 16]>,
property_entities: Vec<PropertyEntity>,
parent: Option<Box<dyn Fn() -> &'static ClassEntry>>,
Expand Down Expand Up @@ -47,12 +47,12 @@ impl<T> ClassEntity<T> {
}
}

pub trait Handler<Z, E> {
fn execute(&self, state: &mut StateObj, args: &mut [ZVal]) -> Result<Z, E>;
pub trait Handler<T, Z, E> {
fn execute(&self, state: &mut StateObj<T>, args: &mut [ZVal]) -> Result<Z, E>;
}

impl<Z, E> Handler<Z, E> for dyn Fn(&mut StateObj, &mut [ZVal]) -> Result<Z, E> + 'static {
fn execute(&self, state: &mut StateObj, args: &mut [ZVal]) -> Result<Z, E> {
impl<T, Z, E> Handler<T, Z, E> for dyn Fn(&mut StateObj<T>, &mut [ZVal]) -> Result<Z, E> + 'static {
fn execute(&self, state: &mut StateObj<T>, args: &mut [ZVal]) -> Result<Z, E> {
self(state, args)
}
}
Expand All @@ -72,11 +72,7 @@ impl<T> ClassEntity<T> {

Self {
class: unsafe { phper_init_class_entry(class_name.as_ptr().cast(), class_name_len) },
state_constructor: Rc::new(move || {
let state = state_constructor();
let boxed = Box::new(state) as Box<dyn Any>;
Box::into_raw(boxed)
}),
state_constructor: Rc::new(state_constructor),
method_entities: SmallVec::default(),
property_entities: Vec::new(),
parent: None,
Expand Down Expand Up @@ -278,11 +274,11 @@ impl<T> crate::modules::Registerer for ClassEntity<T> {
methods.push(FunctionEntry::empty());

{
let mut entry = zeroed::<zend_function_entry>();
let ptr = &mut entry as *mut _ as *mut *const StateConstructor;
let state_constructor = Rc::into_raw(self.state_constructor);
ptr.write(state_constructor);
methods.push(FunctionEntry(entry));
// let mut entry = zeroed::<zend_function_entry>();
// let ptr = &mut entry as *mut _ as *mut *const StateConstructor;
// let state_constructor = Rc::into_raw(self.state_constructor);
// ptr.write(state_constructor);
// methods.push(FunctionEntry(entry));
}

// Store the state constructor pointer to zend_class_entry.
Expand Down
16 changes: 8 additions & 8 deletions phper/src/classes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl<T> StaticStateClass<T> {
///
/// If the `__construct` is private, or protected and the called scope isn't
/// parent class, it will throw PHP Error.
pub fn new_object(&'static self, arguments: impl AsMut<[ZVal]>) -> crate::Result<StateObject> {
pub fn new_object(&'static self, arguments: impl AsMut<[ZVal]>) -> crate::Result<StateObject<T>> {
self.as_class_entry()
.new_object(arguments)
.map(ZObject::into_raw)
Expand All @@ -114,7 +114,7 @@ impl<T> StaticStateClass<T> {
/// Create the object from class, without calling `__construct`.
///
/// **Be careful when `__construct` is necessary.**
pub fn init_object(&'static self) -> crate::Result<StateObject> {
pub fn init_object(&'static self) -> crate::Result<StateObject<T>> {
self.as_class_entry()
.init_object()
.map(ZObject::into_raw)
Expand Down Expand Up @@ -168,7 +168,7 @@ impl StaticInterface {
}
}

pub(crate) type StateConstructor = dyn Fn() -> *mut dyn Any;
pub(crate) type StateConstructor<T> = dyn Fn() -> T;

pub(crate) type StateCloner = dyn Fn(*const dyn Any) -> *mut dyn Any;

Expand Down Expand Up @@ -352,7 +352,7 @@ unsafe extern "C" fn create_object(ce: *mut zend_class_entry) -> *mut zend_objec

// Get state constructor.
func_ptr = func_ptr.offset(1);
let state_constructor = func_ptr as *mut *const StateConstructor;
let state_constructor = func_ptr as *mut *const StateConstructor<()>;
let state_constructor = state_constructor.read().as_ref().unwrap();

// Get state cloner.
Expand Down Expand Up @@ -413,9 +413,9 @@ unsafe fn clone_object_common(object: *mut zend_object) -> *mut zend_object {
(*new_object).handlers = (*object).handlers;

// Call the state cloner and store the state.
let state_object = StateObj::from_mut_object_ptr(object);
let data = (state_cloner)(*state_object.as_mut_any_state());
*new_state_object.as_mut_any_state() = data;
// let state_object = StateObj::from_mut_object_ptr(object);
// let data = (state_cloner)(*state_object.as_mut_any_state());
// *new_state_object.as_mut_any_state() = data;

new_object
}
Expand All @@ -424,7 +424,7 @@ unsafe extern "C" fn free_object(object: *mut zend_object) {
let state_object = StateObj::from_mut_object_ptr(object);

// Drop the state.
state_object.drop_state();
drop(state_object.any_state);

// Original destroy call.
zend_object_std_dtor(object);
Expand Down
88 changes: 41 additions & 47 deletions phper/src/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ impl ZObj {
///
/// Should only call this method for the class of object defined by the
/// extension created by `phper`, otherwise, memory problems will caused.
pub unsafe fn as_state_obj(&self) -> &StateObj {
pub unsafe fn as_state_obj<T>(&self) -> &StateObj<T> {
StateObj::from_object_ptr(self.as_ptr())
}

Expand All @@ -112,8 +112,8 @@ impl ZObj {
/// # Safety
///
/// Should only call this method for the class of object defined by the
/// extension created by `phper`, otherwise, memory problems will caused.
pub unsafe fn as_mut_state_obj(&mut self) -> &mut StateObj {
/// extension created by `phper`, otherwise, memory problems will be caused.
pub unsafe fn as_mut_state_obj<T>(&mut self) -> &mut StateObj<T> {
StateObj::from_mut_object_ptr(self.as_mut_ptr())
}

Expand Down Expand Up @@ -251,8 +251,8 @@ impl ZObj {
}
}

pub(crate) unsafe fn gc_refcount(&self) -> u32 {
phper_zend_object_gc_refcount(self.as_ptr())
pub(crate) fn gc_refcount(&self) -> u32 {
unsafe { phper_zend_object_gc_refcount(self.as_ptr()) }
}
}

Expand Down Expand Up @@ -367,12 +367,12 @@ pub(crate) type AnyState = *mut dyn Any;

/// The object owned state, usually as the parameter of method handler.
#[repr(C)]
pub struct StateObj {
any_state: AnyState,
pub struct StateObj<T> {
pub(crate) any_state: T,
object: ZObj,
}

impl StateObj {
impl<T> StateObj<T> {
/// The `zend_object_alloc` often allocate more memory to hold the state
/// (usually is a pointer), and place it before `zend_object`.
pub(crate) const fn offset() -> usize {
Expand All @@ -398,14 +398,14 @@ impl StateObj {
.unwrap()
}

pub(crate) unsafe fn drop_state(&mut self) {
drop(Box::from_raw(self.any_state));
}

#[inline]
pub(crate) fn as_mut_any_state(&mut self) -> &mut AnyState {
&mut self.any_state
}
// pub(crate) unsafe fn drop_state(&mut self) {
// drop(Box::from_raw(self.any_state));
// }
//
// #[inline]
// pub(crate) fn as_mut_any_state(&mut self) -> &mut AnyState {
// &mut self.any_state
// }

/// Gets object.
#[inline]
Expand All @@ -420,51 +420,47 @@ impl StateObj {
}
}

impl StateObj {
impl<T> StateObj<T> {
/// Gets inner state.
pub fn as_state<T: 'static>(&self) -> &T {
unsafe {
let any_state = self.any_state.as_ref().unwrap();
any_state.downcast_ref().unwrap()
}
#[inline]
pub fn as_state(&self) -> &T {
&self.any_state
}

/// Gets inner mutable state.
pub fn as_mut_state<T: 'static>(&mut self) -> &mut T {
unsafe {
let any_state = self.any_state.as_mut().unwrap();
any_state.downcast_mut().unwrap()
}
#[inline]
pub fn as_mut_state(&mut self) -> &mut T {
&mut self.any_state
}
}

impl Deref for StateObj {
impl<T> Deref for StateObj<T> {
type Target = ZObj;

fn deref(&self) -> &Self::Target {
&self.object
}
}

impl DerefMut for StateObj {
impl<T> DerefMut for StateObj<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.object
}
}

impl Debug for StateObj {
impl<T> Debug for StateObj<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
common_fmt(self, f, "StateObj")
}
}

/// The object owned state, usually crated by
/// [StaticStateClass](crate::classes::StaticStateClass).
pub struct StateObject {
inner: *mut StateObj,
pub struct StateObject<T> {
inner: *mut StateObj<T>,
}

impl StateObject {
impl<T> StateObject<T> {
#[inline]
pub(crate) fn from_raw_object(object: *mut zend_object) -> Self {
unsafe {
Expand All @@ -485,48 +481,46 @@ impl StateObject {
}
}

impl StateObject {
impl<T: 'static> StateObject<T> {
/// Converts into state.
///
/// Because the [zend_object] is refcounted type,
/// therefore, you can only obtain state ownership when the refcount of the
/// [zend_object] is `1`, otherwise, it will return
/// `None`.
pub fn into_state<T: 'static>(mut self) -> Option<T> {
unsafe {
if self.gc_refcount() != 1 {
return None;
}
let null: AnyState = Box::into_raw(Box::new(()));
let ptr = replace(self.as_mut_any_state(), null);
Some(*Box::from_raw(ptr).downcast().unwrap())
pub fn into_state(mut self) -> Option<T> {
if self.gc_refcount() == 1 {
let val = unsafe { std::mem::zeroed::<T>() };
Some(replace(&mut self.any_state, val))
} else {
None
}
}
}

impl Drop for StateObject {
impl<T> Drop for StateObject<T> {
fn drop(&mut self) {
unsafe {
drop(ZObject::from_raw(self.as_mut_ptr()));
}
}
}

impl Deref for StateObject {
type Target = StateObj;
impl<T> Deref for StateObject<T> {
type Target = StateObj<T>;

fn deref(&self) -> &Self::Target {
unsafe { self.inner.as_ref().unwrap() }
}
}

impl DerefMut for StateObject {
impl<T> DerefMut for StateObject<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.inner.as_mut().unwrap() }
}
}

impl Debug for StateObject {
impl<T> Debug for StateObject<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
common_fmt(self, f, "StateObject")
}
Expand Down

0 comments on commit 469452b

Please sign in to comment.