Skip to content

Commit aea8717

Browse files
Refactor Zend strings (#77)
* Call zval destructor when changing zval type and dropping * Remove `ZendHashTable` wrapper Replaced by returning references to the actual hashtable, and having a new type `OwnedHashTable` when creating a new hashtable. * Refactor `ZendString` into a borrowed and owned variant `&ZendStr` is now equivalent to `&str`, while `ZendString` is equivalent to `String`. * Tidy up `ZendString`, add `Debug` implementation
1 parent 7c484a0 commit aea8717

File tree

9 files changed

+331
-124
lines changed

9 files changed

+331
-124
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ categories = ["api-bindings"]
1212

1313
[dependencies]
1414
bitflags = "1.2.1"
15+
parking_lot = "0.11.2"
1516
ext-php-rs-derive = { version = "=0.4.0", path = "./ext-php-rs-derive" }
1617

1718
[build-dependencies]

build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ fn main() {
8585
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
8686
.rustfmt_bindings(true)
8787
.no_copy("_zend_value")
88+
.no_copy("_zend_string")
8889
.layout_tests(env::var("EXT_PHP_RS_TEST").is_ok());
8990

9091
for binding in ALLOWED_BINDINGS.iter() {

example/skel/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,10 @@ pub fn closure_count() -> Closure {
112112

113113
#[php_module]
114114
pub fn module(module: ModuleBuilder) -> ModuleBuilder {
115-
module
115+
module.function(
116+
FunctionBuilder::new("test_zval", test_zval)
117+
.arg(Arg::new("test", DataType::Array))
118+
.build()
119+
.unwrap(),
120+
)
116121
}

example/skel/test.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
<?php
22

3+
<<<<<<< HEAD
4+
<<<<<<< HEAD
5+
<<<<<<< HEAD
36
test_zval(['hello' => 'world']);
7+
=======
8+
test_zval();
9+
>>>>>>> 712aded56 (Call zval destructor when changing zval type and dropping)
10+
=======
11+
test_zval(['hello' => 'world']);
12+
>>>>>>> 3646da741 (Remove `ZendHashTable` wrapper)
13+
=======
14+
test_zval([]);
15+
>>>>>>> 7ba9ee9bf (Refactor `ZendString` into a borrowed and owned variant)
416
//include 'vendor/autoload.php';
517

618
//$ext = new ReflectionExtension('skel');

src/php/class.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ impl ClassEntry {
3838
/// not be found or the class table has not been initialized.
3939
pub fn try_find(name: &str) -> Option<&'static Self> {
4040
ExecutorGlobals::get().class_table()?;
41-
let name = ZendString::new(name, false).ok()?;
41+
let mut name = ZendString::new(name, false).ok()?;
4242

4343
unsafe {
44-
crate::bindings::zend_lookup_class_ex(name.borrow_ptr(), std::ptr::null_mut(), 0)
44+
crate::bindings::zend_lookup_class_ex(name.as_mut_zend_str(), std::ptr::null_mut(), 0)
4545
.as_ref()
4646
}
4747
}
@@ -115,8 +115,7 @@ impl ClassEntry {
115115
if self.flags().contains(ClassFlags::ResolvedParent) {
116116
unsafe { self.__bindgen_anon_1.parent.as_ref() }
117117
} else {
118-
let name =
119-
unsafe { ZendString::from_ptr(self.__bindgen_anon_1.parent_name, false) }.ok()?;
118+
let name = unsafe { self.__bindgen_anon_1.parent_name.as_ref()? };
120119
Self::try_find(name.as_str()?)
121120
}
122121
}
@@ -288,7 +287,7 @@ impl ClassBuilder {
288287
///
289288
/// Returns an [`Error`] variant if the class could not be registered.
290289
pub fn build(mut self) -> Result<&'static mut ClassEntry> {
291-
self.ptr.name = ZendString::new_interned(&self.name)?.release();
290+
self.ptr.name = ZendString::new_interned(&self.name, true)?.into_inner();
292291

293292
self.methods.push(FunctionEntry::end());
294293
let func = Box::into_raw(self.methods.into_boxed_slice()) as *const FunctionEntry;
@@ -349,9 +348,9 @@ impl ClassBuilder {
349348

350349
impl Debug for ClassEntry {
351350
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352-
let name: String = unsafe { ZendString::from_ptr(self.name, false) }
353-
.and_then(|str| str.try_into())
354-
.map_err(|_| std::fmt::Error)?;
351+
let name: String = unsafe { self.name.as_ref() }
352+
.and_then(|s| s.try_into().ok())
353+
.ok_or(std::fmt::Error)?;
355354

356355
f.debug_struct("ClassEntry")
357356
.field("name", &name)

src/php/types/array.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,7 @@ use crate::{
2424
php::enums::DataType,
2525
};
2626

27-
use super::{
28-
string::ZendString,
29-
zval::{FromZval, IntoZval, Zval},
30-
};
27+
use super::zval::{FromZval, IntoZval, Zval};
3128

3229
/// PHP array, which is represented in memory as a hashtable.
3330
pub use crate::bindings::HashTable;
@@ -239,9 +236,7 @@ impl<'a> Iterator for Iter<'a> {
239236
}
240237

241238
let bucket = unsafe { pos.as_ref() };
242-
let key = unsafe { ZendString::from_ptr(bucket.key, false) }
243-
.and_then(|s| s.try_into())
244-
.ok();
239+
let key = unsafe { bucket.key.as_ref() }.and_then(|s| s.try_into().ok());
245240

246241
self.pos = NonNull::new(unsafe { pos.as_ptr().offset(1) });
247242

@@ -272,9 +267,7 @@ impl<'a> DoubleEndedIterator for Iter<'a> {
272267

273268
let new_end = NonNull::new(unsafe { end.as_ptr().offset(-1) })?;
274269
let bucket = unsafe { new_end.as_ref() };
275-
let key = unsafe { ZendString::from_ptr(bucket.key, false) }
276-
.and_then(|s| s.try_into())
277-
.ok();
270+
let key = unsafe { bucket.key.as_ref() }.and_then(|s| s.try_into().ok());
278271
self.end = Some(new_end);
279272

280273
Some((bucket.h, key, &bucket.val))
@@ -370,7 +363,11 @@ impl OwnedHashTable {
370363
}
371364
}
372365

373-
/// Returns the inner pointer to the hashtable, without destroying the
366+
/// Converts the owned Zend hashtable into the internal pointer, bypassing the [`Drop`]
367+
/// implementation.
368+
///
369+
/// The caller is responsible for freeing the resulting pointer using the `zend_array_destroy`
370+
/// function.
374371
pub fn into_inner(self) -> *mut HashTable {
375372
let this = ManuallyDrop::new(self);
376373
this.ptr.as_ptr()

src/php/types/object.rs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,13 @@ pub enum PropertyQuery {
4545
impl ZendObject {
4646
/// Attempts to retrieve the class name of the object.
4747
pub fn get_class_name(&self) -> Result<String> {
48-
let name = unsafe {
49-
ZendString::from_ptr(
50-
self.handlers()?.get_class_name.ok_or(Error::InvalidScope)?(self),
51-
false,
52-
)
53-
}?;
54-
55-
name.try_into()
48+
unsafe {
49+
self.handlers()?
50+
.get_class_name
51+
.and_then(|f| f(self).as_ref())
52+
.ok_or(Error::InvalidScope)
53+
.and_then(|s| s.try_into())
54+
}
5655
}
5756

5857
/// Checks if the given object is an instance of a registered class with Rust
@@ -74,13 +73,13 @@ impl ZendObject {
7473
return Err(Error::InvalidProperty);
7574
}
7675

77-
let name = ZendString::new(name, false)?;
76+
let mut name = ZendString::new(name, false)?;
7877
let mut rv = Zval::new();
7978

8079
unsafe {
8180
self.handlers()?.read_property.ok_or(Error::InvalidScope)?(
8281
self.mut_ptr(),
83-
name.borrow_ptr(),
82+
name.as_mut_zend_str(),
8483
1,
8584
std::ptr::null_mut(),
8685
&mut rv,
@@ -98,13 +97,13 @@ impl ZendObject {
9897
/// * `name` - The name of the property.
9998
/// * `value` - The value to set the property to.
10099
pub fn set_property(&mut self, name: &str, value: impl IntoZval) -> Result<&Zval> {
101-
let name = ZendString::new(name, false)?;
100+
let mut name = ZendString::new(name, false)?;
102101
let mut value = value.into_zval(false)?;
103102

104103
unsafe {
105104
self.handlers()?.write_property.ok_or(Error::InvalidScope)?(
106105
self,
107-
name.borrow_ptr(),
106+
name.as_mut_zend_str(),
108107
&mut value,
109108
std::ptr::null_mut(),
110109
)
@@ -127,7 +126,7 @@ impl ZendObject {
127126
Ok(unsafe {
128127
self.handlers()?.has_property.ok_or(Error::InvalidScope)?(
129128
self.mut_ptr(),
130-
name.borrow_ptr(),
129+
name.deref() as *const _ as *mut _,
131130
query as _,
132131
std::ptr::null_mut(),
133132
)

0 commit comments

Comments
 (0)