Skip to content

Commit 3418b04

Browse files
committed
Refactoring
1 parent 7614f3a commit 3418b04

File tree

4 files changed

+135
-83
lines changed

4 files changed

+135
-83
lines changed

docsrs_bindings.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1657,7 +1657,7 @@ extern "C" {
16571657
);
16581658
}
16591659
extern "C" {
1660-
pub fn zend_is_iterable(iterable: *mut zval) -> bool;
1660+
pub fn zend_is_iterable(iterable: *const zval) -> bool;
16611661
}
16621662
pub const _zend_expected_type_Z_EXPECTED_LONG: _zend_expected_type = 0;
16631663
pub const _zend_expected_type_Z_EXPECTED_LONG_OR_NULL: _zend_expected_type = 1;

src/types/array.rs

Lines changed: 102 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@ use std::{
55
collections::HashMap,
66
convert::{TryFrom, TryInto},
77
ffi::CString,
8-
fmt::Debug,
8+
fmt::{Debug, Display},
99
iter::FromIterator,
1010
u64,
1111
};
1212

13-
use crate::types::iterator::IterKey;
1413
use crate::{
1514
boxed::{ZBox, ZBoxable},
1615
convert::{FromZval, IntoZval},
@@ -464,7 +463,7 @@ impl ZendHashTable {
464463
/// assert!(!ht.has_numerical_keys());
465464
/// ```
466465
pub fn has_numerical_keys(&self) -> bool {
467-
!self.iter().any(|(k, _)| !k.is_long())
466+
!self.into_iter().any(|(k, _)| !k.is_long())
468467
}
469468

470469
/// Checks if the hashtable has numerical, sequential keys.
@@ -491,13 +490,13 @@ impl ZendHashTable {
491490
/// ```
492491
pub fn has_sequential_keys(&self) -> bool {
493492
!self
494-
.iter()
493+
.into_iter()
495494
.enumerate()
496-
.any(|(i, (k, _))| IterKey::Long(i as u64) != k)
495+
.any(|(i, (k, _))| ArrayKey::Long(i as i64) != k)
497496
}
498497

499-
/// Returns an iterator over the key(s) and value contained inside the
500-
/// hashtable.
498+
/// Returns an iterator over the values contained inside the hashtable, as
499+
/// if it was a set or list.
501500
///
502501
/// # Example
503502
///
@@ -506,20 +505,16 @@ impl ZendHashTable {
506505
///
507506
/// let mut ht = ZendHashTable::new();
508507
///
509-
/// for (key, val) in ht.iter() {
510-
/// // ^ Index if inserted at an index.
511-
/// // ^ Optional string key, if inserted like a hashtable.
512-
/// // ^ Inserted value.
513-
///
514-
/// dbg!(key, val);
508+
/// for val in ht.values() {
509+
/// dbg!(val);
515510
/// }
516511
#[inline]
517-
pub fn iter(&self) -> Iter {
518-
Iter::new(self)
512+
pub fn values(&self) -> Values {
513+
Values::new(self)
519514
}
520515

521-
/// Returns an iterator over the values contained inside the hashtable, as
522-
/// if it was a set or list.
516+
/// Returns an iterator over the key(s) and value contained inside the
517+
/// hashtable.
523518
///
524519
/// # Example
525520
///
@@ -528,12 +523,16 @@ impl ZendHashTable {
528523
///
529524
/// let mut ht = ZendHashTable::new();
530525
///
531-
/// for val in ht.values() {
532-
/// dbg!(val);
526+
/// for (key, val) in ht {
527+
/// // ^ Index if inserted at an index.
528+
/// // ^ Optional string key, if inserted like a hashtable.
529+
/// // ^ Inserted value.
530+
///
531+
/// dbg!(key, val);
533532
/// }
534533
#[inline]
535-
pub fn values(&self) -> Values {
536-
Values::new(self)
534+
pub fn iter(&self) -> Iter {
535+
self.into_iter()
537536
}
538537
}
539538

@@ -547,7 +546,7 @@ unsafe impl ZBoxable for ZendHashTable {
547546
impl Debug for ZendHashTable {
548547
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
549548
f.debug_map()
550-
.entries(self.iter().map(|(k, v)| (k.to_string(), v)))
549+
.entries(self.into_iter().map(|(k, v)| (k.to_string(), v)))
551550
.finish()
552551
}
553552
}
@@ -572,10 +571,54 @@ impl ToOwned for ZendHashTable {
572571
/// Immutable iterator upon a reference to a hashtable.
573572
pub struct Iter<'a> {
574573
ht: &'a ZendHashTable,
575-
current_num: u64,
574+
current_num: i64,
576575
pos: HashPosition,
577576
}
578577

578+
#[derive(Debug, PartialEq)]
579+
pub enum ArrayKey<'a> {
580+
Long(i64),
581+
String(&'a str),
582+
}
583+
584+
/// Represent the key of a PHP array, which can be either a long or a string.
585+
impl<'a> ArrayKey<'a> {
586+
/// Check if the key is an integer.
587+
///
588+
/// # Returns
589+
///
590+
/// Returns true if the key is an integer, false otherwise.
591+
pub fn is_long(&self) -> bool {
592+
match self {
593+
ArrayKey::Long(_) => true,
594+
ArrayKey::String(_) => false,
595+
}
596+
}
597+
}
598+
599+
impl<'a> Display for ArrayKey<'a> {
600+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
601+
match self {
602+
ArrayKey::Long(key) => write!(f, "{}", key),
603+
ArrayKey::String(key) => write!(f, "{}", key),
604+
}
605+
}
606+
}
607+
608+
impl<'a> FromZval<'_> for ArrayKey<'a> {
609+
const TYPE: DataType = DataType::String;
610+
611+
fn from_zval(zval: &Zval) -> Option<Self> {
612+
if let Some(key) = zval.long() {
613+
return Some(ArrayKey::Long(key));
614+
}
615+
if let Some(key) = zval.str() {
616+
return Some(ArrayKey::String(key));
617+
}
618+
return None;
619+
}
620+
}
621+
579622
impl<'a> Iter<'a> {
580623
/// Creates a new iterator over a hashtable.
581624
///
@@ -591,8 +634,35 @@ impl<'a> Iter<'a> {
591634
}
592635
}
593636

637+
impl<'a> IntoIterator for &'a ZendHashTable {
638+
type Item = (ArrayKey<'a>, &'a Zval);
639+
type IntoIter = Iter<'a>;
640+
641+
/// Returns an iterator over the key(s) and value contained inside the
642+
/// hashtable.
643+
///
644+
/// # Example
645+
///
646+
/// ```no_run
647+
/// use ext_php_rs::types::ZendHashTable;
648+
///
649+
/// let mut ht = ZendHashTable::new();
650+
///
651+
/// for (key, val) in ht {
652+
/// // ^ Index if inserted at an index.
653+
/// // ^ Optional string key, if inserted like a hashtable.
654+
/// // ^ Inserted value.
655+
///
656+
/// dbg!(key, val);
657+
/// }
658+
#[inline]
659+
fn into_iter(self) -> Self::IntoIter {
660+
Iter::new(self)
661+
}
662+
}
663+
594664
impl<'a> Iterator for Iter<'a> {
595-
type Item = (IterKey, &'a Zval);
665+
type Item = (ArrayKey<'a>, &'a Zval);
596666

597667
fn next(&mut self) -> Option<Self::Item> {
598668
let key_type = unsafe {
@@ -621,9 +691,9 @@ impl<'a> Iterator for Iter<'a> {
621691
)
622692
};
623693

624-
let r = match IterKey::from_zval(&key) {
625-
Some(key) => (key, value),
626-
None => (IterKey::Long(self.current_num), value),
694+
let key = match ArrayKey::from_zval(&key) {
695+
Some(key) => key,
696+
None => ArrayKey::Long(self.current_num),
627697
};
628698

629699
unsafe {
@@ -634,7 +704,7 @@ impl<'a> Iterator for Iter<'a> {
634704
};
635705
self.current_num += 1;
636706

637-
Some(r)
707+
Some((key, value))
638708
}
639709

640710
fn count(self) -> usize
@@ -679,9 +749,9 @@ impl<'a> DoubleEndedIterator for Iter<'a> {
679749
)
680750
};
681751

682-
let r = match IterKey::from_zval(&key) {
752+
let r = match ArrayKey::from_zval(&key) {
683753
Some(key) => (key, value),
684-
None => (IterKey::Long(self.current_num), value),
754+
None => (ArrayKey::Long(self.current_num), value),
685755
};
686756

687757
unsafe {
@@ -780,7 +850,7 @@ where
780850
fn try_from(value: &'a ZendHashTable) -> Result<Self> {
781851
let mut hm = HashMap::with_capacity(value.len());
782852

783-
for (key, val) in value.iter() {
853+
for (key, val) in value {
784854
hm.insert(
785855
key.to_string(),
786856
V::from_zval(val).ok_or_else(|| Error::ZvalConversion(val.get_type()))?,
@@ -849,7 +919,7 @@ where
849919
fn try_from(value: &'a ZendHashTable) -> Result<Self> {
850920
let mut vec = Vec::with_capacity(value.len());
851921

852-
for (_, val) in value.iter() {
922+
for (_, val) in value {
853923
vec.push(T::from_zval(val).ok_or_else(|| Error::ZvalConversion(val.get_type()))?);
854924
}
855925

src/types/iterable.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
use super::array::Iter as ZendHashTableIter;
1+
use super::array::{ArrayKey, Iter as ZendHashTableIter};
22
use super::iterator::Iter as ZendIteratorIter;
33
use crate::convert::FromZval;
44
use crate::flags::DataType;
5-
use crate::types::iterator::IterKey;
65
use crate::types::{ZendHashTable, ZendIterator, Zval};
76

87
/// This type represents a PHP iterable, which can be either an array or an
@@ -15,6 +14,7 @@ pub enum Iterable<'a> {
1514

1615
impl<'a> Iterable<'a> {
1716
/// Creates a new rust iterator from a PHP iterable.
17+
/// May return None if a Traversable cannot be rewound.
1818
pub fn iter(&mut self) -> Option<Iter> {
1919
match self {
2020
Iterable::Array(array) => Some(Iter::Array(array.iter())),
@@ -23,6 +23,15 @@ impl<'a> Iterable<'a> {
2323
}
2424
}
2525

26+
impl<'a> IntoIterator for &'a mut Iterable<'a> {
27+
type Item = (&'a Zval, &'a Zval);
28+
type IntoIter = Iter<'a>;
29+
30+
fn into_iter(self) -> Self::IntoIter {
31+
self.iter().expect("Could not rewind iterator!")
32+
}
33+
}
34+
2635
impl<'a> FromZval<'a> for Iterable<'a> {
2736
const TYPE: DataType = DataType::Iterable;
2837

@@ -46,11 +55,15 @@ pub enum Iter<'a> {
4655
}
4756

4857
impl<'a> Iterator for Iter<'a> {
49-
type Item = (IterKey, &'a Zval);
58+
type Item = (&'a Zval, &'a Zval);
5059

5160
fn next(&mut self) -> Option<Self::Item> {
5261
match self {
53-
Iter::Array(array) => array.next(),
62+
Iter::Array(array) => match array.next() {
63+
Some((ArrayKey::Long(k), v)) => Zval::new().set_long(v),
64+
Some((ArrayKey::String(k), v)) => Zval::new().set_string(v),
65+
None => None,
66+
},
5467
Iter::Traversable(traversable) => traversable.next(),
5568
}
5669
}

src/types/iterator.rs

Lines changed: 15 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@ use std::fmt::{Debug, Display, Formatter};
77

88
/// A PHP Iterator.
99
///
10-
/// In PHP, iterators are represented as zend_object_iterator. This allow user
11-
/// to iterate over object implementing Traversable interface using foreach.
10+
/// In PHP, iterators are represented as zend_object_iterator. This allows user
11+
/// to iterate over objects implementing Traversable interface using foreach.
12+
///
13+
/// Use ZendIterable to iterate over both iterators and arrays.
1214
pub type ZendIterator = zend_object_iterator;
1315

1416
impl ZendIterator {
1517
/// Creates a new rust iterator from a zend_object_iterator.
1618
///
17-
/// # Returns
18-
///
19-
/// Returns a iterator over the zend_object_iterator.
19+
/// Returns a iterator over the zend_object_iterator, or None if the
20+
/// iterator cannot be rewound.
2021
pub fn iter(&mut self) -> Option<Iter> {
2122
self.index = 0;
2223

@@ -122,50 +123,18 @@ impl ZendIterator {
122123
}
123124
}
124125

125-
impl Debug for ZendIterator {
126-
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
127-
f.debug_struct("ZendIterator").finish()
128-
}
129-
}
130-
131-
#[derive(Debug, PartialEq)]
132-
pub enum IterKey {
133-
Long(u64),
134-
String(String),
135-
}
126+
impl<'a> IntoIterator for &'a mut ZendIterator {
127+
type Item = (&'a Zval, &'a Zval);
128+
type IntoIter = Iter<'a>;
136129

137-
/// Represent the key of a PHP iterator, which can be either a long or a string.
138-
impl IterKey {
139-
/// Check if the key is an integer.
140-
///
141-
/// # Returns
142-
///
143-
/// Returns true if the key is an integer, false otherwise.
144-
pub fn is_long(&self) -> bool {
145-
match self {
146-
IterKey::Long(_) => true,
147-
IterKey::String(_) => false,
148-
}
149-
}
150-
}
151-
152-
impl Display for IterKey {
153-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154-
match self {
155-
IterKey::Long(key) => write!(f, "{}", key),
156-
IterKey::String(key) => write!(f, "{}", key),
157-
}
130+
fn into_iter(self) -> Self::IntoIter {
131+
self.iter().expect("Could not rewind iterator!")
158132
}
159133
}
160134

161-
impl FromZval<'_> for IterKey {
162-
const TYPE: DataType = DataType::String;
163-
164-
fn from_zval(zval: &Zval) -> Option<Self> {
165-
match zval.long() {
166-
Some(key) => Some(IterKey::Long(key as u64)),
167-
None => zval.string().map(IterKey::String),
168-
}
135+
impl Debug for ZendIterator {
136+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
137+
f.debug_struct("ZendIterator").finish()
169138
}
170139
}
171140

@@ -175,7 +144,7 @@ pub struct Iter<'a> {
175144
}
176145

177146
impl<'a> Iterator for Iter<'a> {
178-
type Item = (IterKey, &'a Zval);
147+
type Item = (&'a Zval, &'a Zval);
179148

180149
fn next(&mut self) -> Option<Self::Item> {
181150
// Call next when index > 0, so next is really called at the start of each

0 commit comments

Comments
 (0)