@@ -5,12 +5,11 @@ use std::{
5
5
collections:: HashMap ,
6
6
convert:: { TryFrom , TryInto } ,
7
7
ffi:: CString ,
8
- fmt:: Debug ,
8
+ fmt:: { Debug , Display } ,
9
9
iter:: FromIterator ,
10
10
u64,
11
11
} ;
12
12
13
- use crate :: types:: iterator:: IterKey ;
14
13
use crate :: {
15
14
boxed:: { ZBox , ZBoxable } ,
16
15
convert:: { FromZval , IntoZval } ,
@@ -464,7 +463,7 @@ impl ZendHashTable {
464
463
/// assert!(!ht.has_numerical_keys());
465
464
/// ```
466
465
pub fn has_numerical_keys ( & self ) -> bool {
467
- !self . iter ( ) . any ( |( k, _) | !k. is_long ( ) )
466
+ !self . into_iter ( ) . any ( |( k, _) | !k. is_long ( ) )
468
467
}
469
468
470
469
/// Checks if the hashtable has numerical, sequential keys.
@@ -491,13 +490,13 @@ impl ZendHashTable {
491
490
/// ```
492
491
pub fn has_sequential_keys ( & self ) -> bool {
493
492
!self
494
- . iter ( )
493
+ . into_iter ( )
495
494
. enumerate ( )
496
- . any ( |( i, ( k, _) ) | IterKey :: Long ( i as u64 ) != k)
495
+ . any ( |( i, ( k, _) ) | ArrayKey :: Long ( i as i64 ) != k)
497
496
}
498
497
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 .
501
500
///
502
501
/// # Example
503
502
///
@@ -506,20 +505,16 @@ impl ZendHashTable {
506
505
///
507
506
/// let mut ht = ZendHashTable::new();
508
507
///
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);
515
510
/// }
516
511
#[ inline]
517
- pub fn iter ( & self ) -> Iter {
518
- Iter :: new ( self )
512
+ pub fn values ( & self ) -> Values {
513
+ Values :: new ( self )
519
514
}
520
515
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 .
523
518
///
524
519
/// # Example
525
520
///
@@ -528,12 +523,16 @@ impl ZendHashTable {
528
523
///
529
524
/// let mut ht = ZendHashTable::new();
530
525
///
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);
533
532
/// }
534
533
#[ inline]
535
- pub fn values ( & self ) -> Values {
536
- Values :: new ( self )
534
+ pub fn iter ( & self ) -> Iter {
535
+ self . into_iter ( )
537
536
}
538
537
}
539
538
@@ -547,7 +546,7 @@ unsafe impl ZBoxable for ZendHashTable {
547
546
impl Debug for ZendHashTable {
548
547
fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
549
548
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) ) )
551
550
. finish ( )
552
551
}
553
552
}
@@ -572,10 +571,54 @@ impl ToOwned for ZendHashTable {
572
571
/// Immutable iterator upon a reference to a hashtable.
573
572
pub struct Iter < ' a > {
574
573
ht : & ' a ZendHashTable ,
575
- current_num : u64 ,
574
+ current_num : i64 ,
576
575
pos : HashPosition ,
577
576
}
578
577
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
+
579
622
impl < ' a > Iter < ' a > {
580
623
/// Creates a new iterator over a hashtable.
581
624
///
@@ -591,8 +634,35 @@ impl<'a> Iter<'a> {
591
634
}
592
635
}
593
636
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
+
594
664
impl < ' a > Iterator for Iter < ' a > {
595
- type Item = ( IterKey , & ' a Zval ) ;
665
+ type Item = ( ArrayKey < ' a > , & ' a Zval ) ;
596
666
597
667
fn next ( & mut self ) -> Option < Self :: Item > {
598
668
let key_type = unsafe {
@@ -621,9 +691,9 @@ impl<'a> Iterator for Iter<'a> {
621
691
)
622
692
} ;
623
693
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 ) ,
627
697
} ;
628
698
629
699
unsafe {
@@ -634,7 +704,7 @@ impl<'a> Iterator for Iter<'a> {
634
704
} ;
635
705
self . current_num += 1 ;
636
706
637
- Some ( r )
707
+ Some ( ( key , value ) )
638
708
}
639
709
640
710
fn count ( self ) -> usize
@@ -679,9 +749,9 @@ impl<'a> DoubleEndedIterator for Iter<'a> {
679
749
)
680
750
} ;
681
751
682
- let r = match IterKey :: from_zval ( & key) {
752
+ let r = match ArrayKey :: from_zval ( & key) {
683
753
Some ( key) => ( key, value) ,
684
- None => ( IterKey :: Long ( self . current_num ) , value) ,
754
+ None => ( ArrayKey :: Long ( self . current_num ) , value) ,
685
755
} ;
686
756
687
757
unsafe {
@@ -780,7 +850,7 @@ where
780
850
fn try_from ( value : & ' a ZendHashTable ) -> Result < Self > {
781
851
let mut hm = HashMap :: with_capacity ( value. len ( ) ) ;
782
852
783
- for ( key, val) in value. iter ( ) {
853
+ for ( key, val) in value {
784
854
hm. insert (
785
855
key. to_string ( ) ,
786
856
V :: from_zval ( val) . ok_or_else ( || Error :: ZvalConversion ( val. get_type ( ) ) ) ?,
@@ -849,7 +919,7 @@ where
849
919
fn try_from ( value : & ' a ZendHashTable ) -> Result < Self > {
850
920
let mut vec = Vec :: with_capacity ( value. len ( ) ) ;
851
921
852
- for ( _, val) in value. iter ( ) {
922
+ for ( _, val) in value {
853
923
vec. push ( T :: from_zval ( val) . ok_or_else ( || Error :: ZvalConversion ( val. get_type ( ) ) ) ?) ;
854
924
}
855
925
0 commit comments