Created derive macro for ZendObjectHandler (#19)

* Initialize handlers on first touch

In the process of turning the two macros into one derive proc macro

* Changed the object handler macros into derive
This commit is contained in:
David 2021-04-05 01:43:08 +12:00 committed by GitHub
parent ec87e0453a
commit 860ffb3587
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 71 additions and 55 deletions

View File

@ -10,12 +10,10 @@ authors = ["David Cole <david.cole1340@gmail.com>"]
edition = "2018"
categories = ["api-bindings"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libc = "0.2.88"
bitflags = "1.2.1"
paste = "1.0"
ext-php-rs-derive = { path = "./ext-php-rs-derive" }
[build-dependencies]
bindgen = "0.53.1"

View File

@ -1,6 +1,5 @@
use ext_php_rs::{
call_user_func, info_table_end, info_table_row, info_table_start, object_handlers_init,
object_override_handler,
call_user_func, info_table_end, info_table_row, info_table_start,
php::{
args::{Arg, ArgParser},
class::ClassBuilder,
@ -11,6 +10,7 @@ use ext_php_rs::{
module::{ModuleBuilder, ModuleEntry},
types::{array::ZendHashTable, long::ZendLong, object::ZendClassObject, zval::Zval},
},
ZendObjectHandler,
};
#[no_mangle]
@ -20,18 +20,16 @@ pub extern "C" fn php_module_info(_module: *mut ModuleEntry) {
info_table_end!();
}
#[derive(Debug)]
#[derive(Debug, ZendObjectHandler)]
struct Test {
a: u32,
b: u32,
}
object_override_handler!(Test);
#[derive(Debug, Default)]
#[derive(Debug, Default, ZendObjectHandler)]
struct AnotherTest {
x: u32,
}
object_override_handler!(AnotherTest);
impl Test {
pub extern "C" fn constructor(execute_data: &mut ExecutionData, _retval: &mut Zval) {
@ -40,7 +38,7 @@ impl Test {
if x.is_none() {
eprintln!("Object was none");
} else {
let obj = x.unwrap();
// let obj = x.unwrap();
println!("Object not none");
}
}
@ -81,7 +79,7 @@ impl Default for Test {
#[no_mangle]
pub extern "C" fn module_init(_type: i32, _module_number: i32) -> i32 {
object_handlers_init!(Test);
// object_handlers_init!(Test);
ClassBuilder::new("TestClass")
.method(

View File

@ -0,0 +1,17 @@
[package]
name = "ext-php-rs-derive"
description = "Derive macros for ext-php-rs."
repository = "https://github.com/davidcole1340/ext-php-rs"
homepage = "https://github.com/davidcole1340/ext-php-rs"
license = "MIT"
version = "0.0.2"
authors = ["David Cole <david.cole1340@gmail.com>"]
edition = "2018"
[lib]
proc-macro = true
[dependencies]
syn = "1.0.68"
quote = "1.0.9"
proc-macro2 = "1.0.26"

View File

@ -0,0 +1,45 @@
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
extern crate proc_macro;
/// Derives the implementation of `ZendObjectOverride` for the given structure.
#[proc_macro_derive(ZendObjectHandler)]
pub fn object_handler_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let handlers = Ident::new(
format!("__{}_OBJECT_HANDLERS", name).as_str(),
Span::call_site(),
);
let output = quote! {
static mut #handlers: Option<
*mut ::ext_php_rs::php::types::object::ZendObjectHandlers
> = None;
impl ::ext_php_rs::php::types::object::ZendObjectOverride for #name {
extern "C" fn create_object(
ce: *mut ::ext_php_rs::php::class::ClassEntry,
) -> *mut ::ext_php_rs::php::types::object::ZendObject {
// SAFETY: The handlers are only modified once, when they are first accessed.
// At the moment we only support single-threaded PHP installations therefore the pointer contained
// inside the option can be passed around.
unsafe {
if #handlers.is_none() {
#handlers = Some(::ext_php_rs::php::types::object::ZendObjectHandlers::init::<#name>());
}
::ext_php_rs::php::types::object::ZendClassObject::<#name>::new_ptr(
ce,
#handlers.unwrap()
)
}
}
}
};
TokenStream::from(output)
}

View File

@ -7,3 +7,5 @@ pub mod macros;
pub mod bindings;
pub mod functions;
pub mod php;
pub use ext_php_rs_derive::ZendObjectHandler;

View File

@ -1,43 +0,0 @@
pub use paste::paste;
/// Implements the [`ZendObjectOverride`] trait for the given type.
/// Also defines the static mutable object handlers for the type.
/// **MUST** be called in conjunction with the [`object_handlers_init`] macro.
///
/// # Parameters
///
/// * `$class` - The type to implement the trait for.
#[macro_export]
macro_rules! object_override_handler {
($class: ident) => {
$crate::php::types::macros::paste! {
static mut [<$class _OBJECT_HANDLERS>]: *mut $crate::php::types::object::ZendObjectHandlers = ::std::ptr::null_mut();
impl $crate::php::types::object::ZendObjectOverride for $class {
extern "C" fn create_object(
ce: *mut $crate::php::class::ClassEntry,
) -> *mut $crate::php::types::object::ZendObject {
unsafe {
$crate::php::types::object::ZendClassObject::<$class>::new_ptr(ce, [<$class _OBJECT_HANDLERS>])
}
}
}
}
};
}
/// Initializes a types object handlers. This should be called at the start of
/// the module startup function which is defined by the user.
///
/// # Parameters
///
/// * `$class` - The type to initialize the handlers for.
#[macro_export]
macro_rules! object_handlers_init {
($class: ident) => {{
$crate::php::types::macros::paste! {
let ptr = $crate::php::types::object::ZendObjectHandlers::init::<$class>();
unsafe { [<$class _OBJECT_HANDLERS>] = ptr; };
}
}};
}

View File

@ -3,7 +3,6 @@
pub mod array;
pub mod long;
pub mod macros;
pub mod object;
pub mod string;
pub mod zval;