mirror of
https://github.com/danog/ext-php-rs.git
synced 2025-01-23 05:21:20 +01:00
Refactored ZendHashTable conversions (#23)
We shouldn't really be returning Zval objects, rather references to Zval objects. There is currently a memory leak with arrays that need to be resolved.
This commit is contained in:
parent
87f1503ca5
commit
815452f799
@ -1,3 +1,5 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use ext_php_rs::{
|
||||
call_user_func, info_table_end, info_table_row, info_table_start, parse_args,
|
||||
php::{
|
||||
@ -45,7 +47,7 @@ impl Test {
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn set(execute_data: &mut ExecutionData, _retval: &mut Zval) {
|
||||
pub extern "C" fn set(execute_data: &mut ExecutionData, retval: &mut Zval) {
|
||||
let x = ZendClassObject::<Test>::get(execute_data).unwrap();
|
||||
x.a = 100;
|
||||
}
|
||||
@ -127,11 +129,16 @@ pub extern "C" fn get_module() -> *mut ext_php_rs::php::module::ModuleEntry {
|
||||
.arg(Arg::new("arr", DataType::Array))
|
||||
.build();
|
||||
|
||||
let t = FunctionBuilder::new("test_array", test_array)
|
||||
.returns(DataType::Array, false, false)
|
||||
.build();
|
||||
|
||||
ModuleBuilder::new("ext-skel", "0.1.0")
|
||||
.info_function(php_module_info)
|
||||
.startup_function(module_init)
|
||||
.function(funct)
|
||||
.function(array)
|
||||
.function(t)
|
||||
.build()
|
||||
.into_raw()
|
||||
}
|
||||
@ -176,7 +183,7 @@ pub extern "C" fn skeleton_array(execute_data: &mut ExecutionData, _retval: &mut
|
||||
|
||||
let ht: ZendHashTable = arr.val().unwrap();
|
||||
|
||||
for (k, x, y) in ht {
|
||||
for (k, x, y) in ht.into_iter() {
|
||||
println!("{:?} {:?} {:?}", k, x, y.string());
|
||||
}
|
||||
|
||||
@ -184,3 +191,14 @@ pub extern "C" fn skeleton_array(execute_data: &mut ExecutionData, _retval: &mut
|
||||
new.insert("Hello", "WOrld");
|
||||
let _ = _retval.set_array(new);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn test_array(execute_data: &mut ExecutionData, retval: &mut Zval) {
|
||||
let mut hm = HashMap::new();
|
||||
hm.insert("Hello", 123);
|
||||
hm.insert("World", 456);
|
||||
hm.insert("Asdf", 789);
|
||||
|
||||
let x: ZendHashTable = (&hm).into();
|
||||
retval.set_array(x);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
var_dump(SKEL_TEST_CONST, SKEL_TEST_LONG_CONST);
|
||||
var_dump(test_array());
|
||||
die;
|
||||
|
||||
$x = new TestClass();
|
||||
|
@ -241,9 +241,9 @@ impl Drop for ZendHashTable {
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for ZendHashTable {
|
||||
type Item = (u64, Option<String>, Zval);
|
||||
type IntoIter = Iter;
|
||||
impl<'a> IntoIterator for &'a ZendHashTable {
|
||||
type Item = (u64, Option<String>, &'a Zval);
|
||||
type IntoIter = Iter<'a>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
Self::IntoIter::new(self)
|
||||
@ -251,14 +251,14 @@ impl IntoIterator for ZendHashTable {
|
||||
}
|
||||
|
||||
/// Iterator for a Zend hashtable/array.
|
||||
pub struct Iter {
|
||||
ht: ZendHashTable,
|
||||
pub struct Iter<'a> {
|
||||
ht: &'a ZendHashTable,
|
||||
pos: *mut _Bucket,
|
||||
end: *mut _Bucket,
|
||||
}
|
||||
|
||||
impl Iter {
|
||||
pub fn new(ht: ZendHashTable) -> Self {
|
||||
impl<'a> Iter<'a> {
|
||||
pub fn new(ht: &'a ZendHashTable) -> Self {
|
||||
let ptr = unsafe { *ht.ptr };
|
||||
let pos = ptr.arData;
|
||||
let end = unsafe { ptr.arData.offset(ptr.nNumUsed as isize) };
|
||||
@ -266,8 +266,8 @@ impl Iter {
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Iter {
|
||||
type Item = (u64, Option<String>, Zval);
|
||||
impl<'a> Iterator for Iter<'a> {
|
||||
type Item = (u64, Option<String>, &'a Zval);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
// iterator complete
|
||||
@ -280,7 +280,7 @@ impl Iterator for Iter {
|
||||
// converting it to a reference (val.key.as_ref() returns None if ptr == null)
|
||||
let str_key: Option<String> = unsafe { val.key.as_ref() }.map(|key| key.into());
|
||||
|
||||
Some((val.h, str_key, val.val))
|
||||
Some((val.h, str_key, &val.val))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -298,8 +298,8 @@ impl Iterator for Iter {
|
||||
}
|
||||
|
||||
/// Implementation converting a ZendHashTable into a Rust HashTable.
|
||||
impl<'a> From<ZendHashTable> for HashMap<String, Zval> {
|
||||
fn from(zht: ZendHashTable) -> Self {
|
||||
impl<'a> From<&'a ZendHashTable> for HashMap<String, &'a Zval> {
|
||||
fn from(zht: &'a ZendHashTable) -> Self {
|
||||
let mut hm = HashMap::new();
|
||||
|
||||
for (idx, key, val) in zht.into_iter() {
|
||||
@ -311,16 +311,16 @@ impl<'a> From<ZendHashTable> for HashMap<String, Zval> {
|
||||
}
|
||||
|
||||
/// Implementation converting a Rust HashTable into a ZendHashTable.
|
||||
impl<'a, K, V> From<HashMap<K, V>> for ZendHashTable
|
||||
impl<'a, K, V> From<&'a HashMap<K, V>> for ZendHashTable
|
||||
where
|
||||
K: Into<String>,
|
||||
V: Into<Zval>,
|
||||
K: Into<String> + Copy,
|
||||
V: Into<Zval> + Copy,
|
||||
{
|
||||
fn from(hm: HashMap<K, V>) -> Self {
|
||||
fn from(hm: &'a HashMap<K, V>) -> Self {
|
||||
let mut ht = ZendHashTable::with_capacity(hm.len() as u32);
|
||||
|
||||
for (k, v) in hm {
|
||||
ht.insert(k.into(), v.into());
|
||||
for (k, v) in hm.iter() {
|
||||
ht.insert(*k, *v);
|
||||
}
|
||||
|
||||
ht
|
||||
@ -330,16 +330,13 @@ where
|
||||
/// Implementation for converting a `ZendHashTable` into a `Vec` of given type.
|
||||
/// If the contents of the hash table cannot be turned into a type `T`, it wil skip over the item
|
||||
/// and return a `Vec` consisting of only elements that could be converted.
|
||||
impl<'a, V> From<ZendHashTable> for Vec<V>
|
||||
impl<'a, V> From<&'a ZendHashTable> for Vec<V>
|
||||
where
|
||||
V: TryFrom<Zval>,
|
||||
V: TryFrom<&'a Zval>,
|
||||
{
|
||||
fn from(ht: ZendHashTable) -> Self {
|
||||
fn from(ht: &'a ZendHashTable) -> Self {
|
||||
ht.into_iter()
|
||||
.filter_map(|(_, _, v)| match v.try_into() {
|
||||
Ok(v) => Some(v),
|
||||
Err(_) => None,
|
||||
})
|
||||
.filter_map(|(_, _, v)| v.try_into().ok())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user