@@ -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 ;
1413use 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 {
547546impl 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.
573572pub 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+
579622impl < ' 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+
594664impl < ' 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
0 commit comments