22
33use crate :: {
44 alloc:: { EAllocatable , EBox } ,
5+ strings:: ZendString ,
56 sys:: * ,
67 values:: Val ,
78} ;
8- use std:: mem:: zeroed;
9+ use std:: { borrow :: Cow , mem:: zeroed} ;
910
1011/// Key for [Array].
12+ #[ derive( Debug , Clone , PartialEq ) ]
1113pub enum Key < ' a > {
1214 Index ( u64 ) ,
13- Str ( & ' a str ) ,
15+ Str ( Cow < ' a , str > ) ,
1416}
1517
1618impl From < u64 > for Key < ' _ > {
@@ -21,7 +23,13 @@ impl From<u64> for Key<'_> {
2123
2224impl < ' a > From < & ' a str > for Key < ' a > {
2325 fn from ( s : & ' a str ) -> Self {
24- Key :: Str ( s)
26+ Key :: Str ( Cow :: Borrowed ( s) )
27+ }
28+ }
29+
30+ impl From < String > for Key < ' _ > {
31+ fn from ( s : String ) -> Self {
32+ Key :: Str ( Cow :: Owned ( s) )
2533 }
2634}
2735
@@ -45,7 +53,12 @@ impl Array {
4553 }
4654 }
4755
48- pub ( crate ) unsafe fn from_mut_ptr < ' a > ( ptr : * mut zend_array ) -> & ' a mut Array {
56+ pub unsafe fn from_ptr < ' a > ( ptr : * const zend_array ) -> & ' a Array {
57+ let ptr = ptr as * const Array ;
58+ ptr. as_ref ( ) . expect ( "ptr shouldn't be null" )
59+ }
60+
61+ pub unsafe fn from_mut_ptr < ' a > ( ptr : * mut zend_array ) -> & ' a mut Array {
4962 let ptr = ptr as * mut Array ;
5063 ptr. as_mut ( ) . expect ( "ptr shouldn't be null" )
5164 }
@@ -100,13 +113,34 @@ impl Array {
100113 unsafe { zend_array_count ( & mut self . inner ) as usize }
101114 }
102115
116+ pub fn exists < ' a > ( & self , key : impl Into < Key < ' a > > ) -> bool {
117+ let key = key. into ( ) ;
118+ unsafe {
119+ match key {
120+ Key :: Index ( i) => phper_zend_hash_index_exists ( & self . inner , i) ,
121+ Key :: Str ( s) => phper_zend_hash_str_exists (
122+ & self . inner ,
123+ s. as_ref ( ) . as_ptr ( ) . cast ( ) ,
124+ s. as_ref ( ) . len ( ) ,
125+ ) ,
126+ }
127+ }
128+ }
129+
103130 pub fn clone ( & self ) -> EBox < Self > {
104131 let mut other = Self :: new ( ) ;
105132 unsafe {
106133 zend_hash_copy ( other. as_mut_ptr ( ) , self . as_ptr ( ) as * mut _ , None ) ;
107134 }
108135 other
109136 }
137+
138+ pub fn iter ( & self ) -> Iter < ' _ > {
139+ Iter {
140+ index : 0 ,
141+ array : & self ,
142+ }
143+ }
110144}
111145
112146impl EAllocatable for Array {
@@ -115,6 +149,8 @@ impl EAllocatable for Array {
115149 if ( * ptr) . inner . gc . refcount == 0 {
116150 zend_hash_destroy ( ptr. cast ( ) ) ;
117151 _efree ( ptr. cast ( ) ) ;
152+ } else {
153+ ( * ptr) . inner . gc . refcount -= 1 ;
118154 }
119155 }
120156 }
@@ -125,3 +161,45 @@ impl Drop for Array {
125161 unreachable ! ( "Allocation on the stack is not allowed" )
126162 }
127163}
164+
165+ pub struct Iter < ' a > {
166+ index : isize ,
167+ array : & ' a Array ,
168+ }
169+
170+ impl < ' a > Iterator for Iter < ' a > {
171+ type Item = ( Key < ' a > , & ' a Val ) ;
172+
173+ fn next ( & mut self ) -> Option < Self :: Item > {
174+ loop {
175+ if self . index >= self . array . inner . nNumUsed as isize {
176+ break None ;
177+ }
178+
179+ unsafe {
180+ let bucket = self . array . inner . arData . offset ( self . index ) ;
181+
182+ let key = if ( * bucket) . key . is_null ( ) {
183+ Key :: Index ( ( * bucket) . h )
184+ } else {
185+ let s = ZendString :: from_ptr ( ( * bucket) . key ) ;
186+ let s = s. to_string ( ) . unwrap ( ) ;
187+ Key :: Str ( Cow :: Owned ( s) )
188+ } ;
189+
190+ let val = & mut ( * bucket) . val ;
191+ let mut val = Val :: from_mut_ptr ( val) ;
192+ if val. get_type ( ) . is_indirect ( ) {
193+ val = Val :: from_mut_ptr ( ( * val. as_mut_ptr ( ) ) . value . zv ) ;
194+ }
195+
196+ self . index += 1 ;
197+
198+ if val. get_type ( ) . is_undef ( ) {
199+ continue ;
200+ }
201+ break Some ( ( key, val) ) ;
202+ }
203+ }
204+ }
205+ }
0 commit comments