@@ -7,7 +7,6 @@ use std::{
77 ffi:: CString ,
88 fmt:: Debug ,
99 iter:: FromIterator ,
10- ptr:: NonNull ,
1110 u64,
1211} ;
1312
@@ -16,10 +15,12 @@ use crate::{
1615 convert:: { FromZval , IntoZval } ,
1716 error:: { Error , Result } ,
1817 ffi:: {
19- _Bucket, _zend_new_array, zend_array_destroy, zend_array_dup, zend_hash_clean,
20- zend_hash_index_del, zend_hash_index_find, zend_hash_index_update,
18+ _zend_new_array, zend_array_count, zend_array_destroy, zend_array_dup, zend_hash_clean,
19+ zend_hash_get_current_data_ex, zend_hash_get_current_key_type_ex,
20+ zend_hash_get_current_key_zval_ex, zend_hash_index_del, zend_hash_index_find,
21+ zend_hash_index_update, zend_hash_move_backwards_ex, zend_hash_move_forward_ex,
2122 zend_hash_next_index_insert, zend_hash_str_del, zend_hash_str_find, zend_hash_str_update,
22- HT_MIN_SIZE ,
23+ HashPosition , HT_MIN_SIZE ,
2324 } ,
2425 flags:: DataType ,
2526 types:: Zval ,
@@ -117,7 +118,7 @@ impl ZendHashTable {
117118 /// assert_eq!(ht.len(), 2);
118119 /// ```
119120 pub fn len ( & self ) -> usize {
120- self . nNumOfElements as usize
121+ unsafe { zend_array_count ( self as * const ZendHashTable as * mut ZendHashTable ) as usize }
121122 }
122123
123124 /// Returns whether the hash table is empty.
@@ -520,8 +521,8 @@ impl ToOwned for ZendHashTable {
520521/// Immutable iterator upon a reference to a hashtable.
521522pub struct Iter < ' a > {
522523 ht : & ' a ZendHashTable ,
523- pos : Option < NonNull < _Bucket > > ,
524- end : Option < NonNull < _Bucket > > ,
524+ current_num : u64 ,
525+ pos : HashPosition ,
525526}
526527
527528impl < ' a > Iter < ' a > {
@@ -531,37 +532,57 @@ impl<'a> Iter<'a> {
531532 ///
532533 /// * `ht` - The hashtable to iterate.
533534 pub fn new ( ht : & ' a ZendHashTable ) -> Self {
534- #[ cfg( not( php82) ) ]
535- return Self {
535+ Self {
536536 ht,
537- pos : NonNull :: new ( ht. arData ) ,
538- end : NonNull :: new ( unsafe { ht. arData . offset ( ht. nNumUsed as isize ) } ) ,
539- } ;
540- #[ cfg( php82) ]
541- return Self {
542- ht,
543- pos : NonNull :: new ( unsafe { ht. __bindgen_anon_1 . arData } ) ,
544- end : NonNull :: new ( unsafe { ht. __bindgen_anon_1 . arData . offset ( ht. nNumUsed as isize ) } ) ,
545- } ;
537+ current_num : 0 ,
538+ pos : 0 ,
539+ }
546540 }
547541}
548542
549543impl < ' a > Iterator for Iter < ' a > {
550544 type Item = ( u64 , Option < String > , & ' a Zval ) ;
551545
552546 fn next ( & mut self ) -> Option < Self :: Item > {
553- let pos = self . pos ?;
547+ let key_type = unsafe {
548+ zend_hash_get_current_key_type_ex (
549+ self . ht as * const ZendHashTable as * mut ZendHashTable ,
550+ & mut self . pos as * mut HashPosition ,
551+ )
552+ } ;
554553
555- if pos == self . end ? {
554+ if key_type == - 1 {
556555 return None ;
557556 }
558557
559- let bucket = unsafe { pos. as_ref ( ) } ;
560- let key = unsafe { bucket. key . as_ref ( ) } . and_then ( |s| s. try_into ( ) . ok ( ) ) ;
558+ let key = Zval :: new ( ) ;
559+ unsafe {
560+ zend_hash_get_current_key_zval_ex (
561+ self . ht as * const ZendHashTable as * mut ZendHashTable ,
562+ & key as * const Zval as * mut Zval ,
563+ & mut self . pos as * mut HashPosition ,
564+ ) ;
565+ }
566+ let value = unsafe {
567+ & * zend_hash_get_current_data_ex (
568+ self . ht as * const ZendHashTable as * mut ZendHashTable ,
569+ & mut self . pos as * mut HashPosition ,
570+ )
571+ } ;
572+ let r: ( u64 , Option < String > , & Zval ) = match key. is_long ( ) {
573+ true => ( key. long ( ) . unwrap_or ( 0 ) as u64 , None , value) ,
574+ false => ( self . current_num , key. try_into ( ) . ok ( ) , value) ,
575+ } ;
561576
562- self . pos = NonNull :: new ( unsafe { pos. as_ptr ( ) . offset ( 1 ) } ) ;
577+ unsafe {
578+ zend_hash_move_forward_ex (
579+ self . ht as * const ZendHashTable as * mut ZendHashTable ,
580+ & mut self . pos as * mut HashPosition ,
581+ )
582+ } ;
583+ self . current_num += 1 ;
563584
564- Some ( ( bucket . h , key , & bucket . val ) )
585+ Some ( r )
565586 }
566587
567588 fn count ( self ) -> usize
@@ -580,18 +601,45 @@ impl<'a> ExactSizeIterator for Iter<'a> {
580601
581602impl < ' a > DoubleEndedIterator for Iter < ' a > {
582603 fn next_back ( & mut self ) -> Option < Self :: Item > {
583- let end = self . end ?;
604+ let key_type = unsafe {
605+ zend_hash_get_current_key_type_ex (
606+ self . ht as * const ZendHashTable as * mut ZendHashTable ,
607+ & mut self . pos as * mut HashPosition ,
608+ )
609+ } ;
584610
585- if end == self . pos ? {
611+ if key_type == - 1 {
586612 return None ;
587613 }
588614
589- let new_end = NonNull :: new ( unsafe { end. as_ptr ( ) . offset ( -1 ) } ) ?;
590- let bucket = unsafe { new_end. as_ref ( ) } ;
591- let key = unsafe { bucket. key . as_ref ( ) } . and_then ( |s| s. try_into ( ) . ok ( ) ) ;
592- self . end = Some ( new_end) ;
615+ let key = Zval :: new ( ) ;
616+ unsafe {
617+ zend_hash_get_current_key_zval_ex (
618+ self . ht as * const ZendHashTable as * mut ZendHashTable ,
619+ & key as * const Zval as * mut Zval ,
620+ & mut self . pos as * mut HashPosition ,
621+ ) ;
622+ }
623+ let value = unsafe {
624+ & * zend_hash_get_current_data_ex (
625+ self . ht as * const ZendHashTable as * mut ZendHashTable ,
626+ & mut self . pos as * mut HashPosition ,
627+ )
628+ } ;
629+ let r: ( u64 , Option < String > , & Zval ) = match key. is_long ( ) {
630+ true => ( key. long ( ) . unwrap_or ( 0 ) as u64 , None , value) ,
631+ false => ( self . current_num , key. try_into ( ) . ok ( ) , value) ,
632+ } ;
633+
634+ unsafe {
635+ zend_hash_move_backwards_ex (
636+ self . ht as * const ZendHashTable as * mut ZendHashTable ,
637+ & mut self . pos as * mut HashPosition ,
638+ )
639+ } ;
640+ self . current_num -= 1 ;
593641
594- Some ( ( bucket . h , key , & bucket . val ) )
642+ Some ( r )
595643 }
596644}
597645
0 commit comments