Skip to content

Commit 8f425fe

Browse files
committed
feat(iterator): use an iter key for both array and iterator
1 parent 0bf6424 commit 8f425fe

File tree

5 files changed

+79
-46
lines changed

5 files changed

+79
-46
lines changed

allowed_bindings.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ bind! {
9292
zend_internal_arg_info,
9393
zend_is_callable,
9494
zend_is_identical,
95+
zend_is_iterable,
9596
zend_long,
9697
zend_lookup_class_ex,
9798
zend_module_entry,

src/types/array.rs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ use crate::{
2525
flags::DataType,
2626
types::Zval,
2727
};
28+
use crate::types::iterator::IterKey;
29+
use crate::types::ZendLong;
2830

2931
/// A PHP hashtable.
3032
///
@@ -463,7 +465,7 @@ impl ZendHashTable {
463465
/// assert!(!ht.has_numerical_keys());
464466
/// ```
465467
pub fn has_numerical_keys(&self) -> bool {
466-
!self.iter().any(|(_, k, _)| k.is_some())
468+
!self.iter().any(|(k, _)| !k.is_numerical())
467469
}
468470

469471
/// Checks if the hashtable has numerical, sequential keys.
@@ -492,7 +494,7 @@ impl ZendHashTable {
492494
!self
493495
.iter()
494496
.enumerate()
495-
.any(|(i, (k, strk, _))| i as u64 != k || strk.is_some())
497+
.any(|(i, (k, _))| IterKey::Long(i as u64) != k)
496498
}
497499

498500
/// Returns an iterator over the key(s) and value contained inside the
@@ -505,7 +507,7 @@ impl ZendHashTable {
505507
///
506508
/// let mut ht = ZendHashTable::new();
507509
///
508-
/// for (idx, key, val) in ht.iter() {
510+
/// for (key, val) in ht.iter() {
509511
/// // ^ Index if inserted at an index.
510512
/// // ^ Optional string key, if inserted like a hashtable.
511513
/// // ^ Inserted value.
@@ -548,7 +550,7 @@ impl Debug for ZendHashTable {
548550
f.debug_map()
549551
.entries(
550552
self.iter()
551-
.map(|(k, k2, v)| (k2.unwrap_or_else(|| k.to_string()), v)),
553+
.map(|(k, v)| (k.to_string(), v)),
552554
)
553555
.finish()
554556
}
@@ -594,7 +596,7 @@ impl<'a> Iter<'a> {
594596
}
595597

596598
impl<'a> Iterator for Iter<'a> {
597-
type Item = (u64, Option<String>, &'a Zval);
599+
type Item = (IterKey, &'a Zval);
598600

599601
fn next(&mut self) -> Option<Self::Item> {
600602
let key_type = unsafe {
@@ -622,9 +624,13 @@ impl<'a> Iterator for Iter<'a> {
622624
&mut self.pos as *mut HashPosition,
623625
)
624626
};
625-
let r: (u64, Option<String>, &Zval) = match key.is_long() {
626-
true => (key.long().unwrap_or(0) as u64, None, value),
627-
false => (self.current_num, key.try_into().ok(), value),
627+
628+
let r = match key.is_long() {
629+
true => (IterKey::Long(key.long().unwrap_or(self.current_num as ZendLong) as u64), value),
630+
false => match key.try_into() {
631+
Ok(key) => (IterKey::String(key), value),
632+
Err(_) => (IterKey::Long(self.current_num), value),
633+
},
628634
};
629635

630636
unsafe {
@@ -679,9 +685,13 @@ impl<'a> DoubleEndedIterator for Iter<'a> {
679685
&mut self.pos as *mut HashPosition,
680686
)
681687
};
682-
let r: (u64, Option<String>, &Zval) = match key.is_long() {
683-
true => (key.long().unwrap_or(0) as u64, None, value),
684-
false => (self.current_num, key.try_into().ok(), value),
688+
689+
let r = match key.is_long() {
690+
true => (IterKey::Long(key.long().unwrap_or(self.current_num as ZendLong) as u64), value),
691+
false => match key.try_into() {
692+
Ok(key) => (IterKey::String(key), value),
693+
Err(_) => (IterKey::Long(self.current_num), value),
694+
},
685695
};
686696

687697
unsafe {
@@ -715,7 +725,7 @@ impl<'a> Iterator for Values<'a> {
715725
type Item = &'a Zval;
716726

717727
fn next(&mut self) -> Option<Self::Item> {
718-
self.0.next().map(|(_, _, zval)| zval)
728+
self.0.next().map(|(_, zval)| zval)
719729
}
720730

721731
fn count(self) -> usize
@@ -734,7 +744,7 @@ impl<'a> ExactSizeIterator for Values<'a> {
734744

735745
impl<'a> DoubleEndedIterator for Values<'a> {
736746
fn next_back(&mut self) -> Option<Self::Item> {
737-
self.0.next_back().map(|(_, _, zval)| zval)
747+
self.0.next_back().map(|(_, zval)| zval)
738748
}
739749
}
740750

@@ -780,9 +790,9 @@ where
780790
fn try_from(value: &'a ZendHashTable) -> Result<Self> {
781791
let mut hm = HashMap::with_capacity(value.len());
782792

783-
for (idx, key, val) in value.iter() {
793+
for (key, val) in value.iter() {
784794
hm.insert(
785-
key.unwrap_or_else(|| idx.to_string()),
795+
key.to_string(),
786796
V::from_zval(val).ok_or_else(|| Error::ZvalConversion(val.get_type()))?,
787797
);
788798
}
@@ -849,7 +859,7 @@ where
849859
fn try_from(value: &'a ZendHashTable) -> Result<Self> {
850860
let mut vec = Vec::with_capacity(value.len());
851861

852-
for (_, _, val) in value.iter() {
862+
for (_, val) in value.iter() {
853863
vec.push(T::from_zval(val).ok_or_else(|| Error::ZvalConversion(val.get_type()))?);
854864
}
855865

src/types/iterator.rs

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,10 @@ use crate::ffi::zend_object_iterator;
33
use crate::flags::DataType;
44
use crate::types::{ZendLong, Zval};
55
use std::convert::TryInto;
6+
use std::fmt::Display;
67

78
pub type ZendIterator = zend_object_iterator;
89

9-
pub struct Iter<'a> {
10-
zi: &'a mut ZendIterator,
11-
}
12-
1310
impl ZendIterator {
1411
pub fn iter(&mut self) -> Iter {
1512
self.index = 0;
@@ -60,8 +57,36 @@ impl ZendIterator {
6057
}
6158
}
6259

60+
#[derive(PartialEq)]
61+
pub enum IterKey {
62+
Long(u64),
63+
String(String),
64+
}
65+
66+
impl IterKey {
67+
pub fn is_numerical(&self) -> bool {
68+
match self {
69+
IterKey::Long(_) => true,
70+
IterKey::String(_) => false,
71+
}
72+
}
73+
}
74+
75+
impl Display for IterKey {
76+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77+
match self {
78+
IterKey::Long(key) => write!(f, "{}", key),
79+
IterKey::String(key) => write!(f, "{}", key),
80+
}
81+
}
82+
}
83+
84+
pub struct Iter<'a> {
85+
zi: &'a mut ZendIterator,
86+
}
87+
6388
impl<'a> Iterator for Iter<'a> {
64-
type Item = (u64, Option<String>, &'a Zval);
89+
type Item = (IterKey, &'a Zval);
6590

6691
fn next(&mut self) -> Option<Self::Item> {
6792
// Call next when index > 0, so next is really called at the start of each iteration, which allow to work better with generator iterator
@@ -81,14 +106,13 @@ impl<'a> Iterator for Iter<'a> {
81106

82107
Some(match key {
83108
Some(key) => match key.is_long() {
84-
false => (real_index, key.try_into().ok(), value),
85-
true => (
86-
key.long().unwrap_or(real_index as ZendLong) as u64,
87-
None,
88-
value,
89-
),
109+
false => match key.try_into() {
110+
Ok(key) => (IterKey::String(key), value),
111+
Err(_) => (IterKey::Long(real_index), value),
112+
},
113+
true => (IterKey::Long(key.long().unwrap_or(real_index as ZendLong) as u64), value),
90114
},
91-
None => (real_index, None, value),
115+
None => (IterKey::Long(real_index), value),
92116
})
93117
}
94118
}

src/types/object.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,8 @@ impl Debug for ZendObject {
328328
);
329329

330330
if let Ok(props) = self.get_properties() {
331-
for (id, key, val) in props.iter() {
332-
dbg.field(key.unwrap_or_else(|| id.to_string()).as_str(), val);
331+
for (key, val) in props.iter() {
332+
dbg.field(key.to_string().as_str(), val);
333333
}
334334
}
335335

src/zend/globals.rs

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,22 +57,20 @@ impl ExecutorGlobals {
5757
pub fn ini_values(&self) -> HashMap<String, Option<String>> {
5858
let hash_table = unsafe { &*self.ini_directives };
5959
let mut ini_hash_map: HashMap<String, Option<String>> = HashMap::new();
60-
for (_index, key, value) in hash_table.iter() {
61-
if let Some(key) = key {
62-
ini_hash_map.insert(key, unsafe {
63-
let ini_entry = &*value.ptr::<zend_ini_entry>().expect("Invalid ini entry");
64-
if ini_entry.value.is_null() {
65-
None
66-
} else {
67-
Some(
68-
(*ini_entry.value)
69-
.as_str()
70-
.expect("Ini value is not a string")
71-
.to_owned(),
72-
)
73-
}
74-
});
75-
}
60+
for (key, value) in hash_table.iter() {
61+
ini_hash_map.insert(key.to_string(), unsafe {
62+
let ini_entry = &*value.ptr::<zend_ini_entry>().expect("Invalid ini entry");
63+
if ini_entry.value.is_null() {
64+
None
65+
} else {
66+
Some(
67+
(*ini_entry.value)
68+
.as_str()
69+
.expect("Ini value is not a string")
70+
.to_owned(),
71+
)
72+
}
73+
});
7674
}
7775
ini_hash_map
7876
}

0 commit comments

Comments
 (0)