@@ -9,7 +9,7 @@ use std::{
99 iter:: FromIterator ,
1010 ptr,
1111} ;
12-
12+ use std :: str :: FromStr ;
1313use crate :: {
1414 boxed:: { ZBox , ZBoxable } ,
1515 convert:: { FromZval , IntoZval } ,
@@ -25,6 +25,7 @@ use crate::{
2525 flags:: DataType ,
2626 types:: Zval ,
2727} ;
28+ use crate :: ffi:: zend_ulong;
2829
2930/// A PHP hashtable.
3031///
@@ -188,9 +189,26 @@ impl ZendHashTable {
188189 /// assert_eq!(ht.get("test").and_then(|zv| zv.str()), Some("hello world"));
189190 /// ```
190191 #[ must_use]
191- pub fn get ( & self , key : & ' _ str ) -> Option < & Zval > {
192- let str = CString :: new ( key) . ok ( ) ?;
193- unsafe { zend_hash_str_find ( self , str. as_ptr ( ) , key. len ( ) as _ ) . as_ref ( ) }
192+ pub fn get < ' a , K > ( & self , key : K ) -> Option < & Zval > where K : Into < ArrayKey < ' a > > {
193+ match key. into ( ) {
194+ ArrayKey :: Long ( index) => {
195+ unsafe { zend_hash_index_find ( self , index as zend_ulong ) . as_ref ( ) }
196+ }
197+ ArrayKey :: String ( key) => {
198+ if let Ok ( index) = i64:: from_str ( key. as_str ( ) ) {
199+ unsafe { zend_hash_index_find ( self , index as zend_ulong ) . as_ref ( ) }
200+ } else {
201+ unsafe { zend_hash_str_find ( self , CString :: new ( key. as_str ( ) ) . ok ( ) ?. as_ptr ( ) , key. len ( ) as _ ) . as_ref ( ) }
202+ }
203+ }
204+ ArrayKey :: Str ( key) => {
205+ if let Ok ( index) = i64:: from_str ( key) {
206+ unsafe { zend_hash_index_find ( self , index as zend_ulong ) . as_ref ( ) }
207+ } else {
208+ unsafe { zend_hash_str_find ( self , CString :: new ( key) . ok ( ) ?. as_ptr ( ) , key. len ( ) as _ ) . as_ref ( ) }
209+ }
210+ }
211+ }
194212 }
195213
196214 /// Attempts to retrieve a value from the hash table with a string key.
@@ -216,9 +234,26 @@ impl ZendHashTable {
216234 /// assert_eq!(ht.get("test").and_then(|zv| zv.str()), Some("hello world"));
217235 /// ```
218236 #[ must_use]
219- pub fn get_mut ( & self , key : & ' _ str ) -> Option < & mut Zval > {
220- let str = CString :: new ( key) . ok ( ) ?;
221- unsafe { zend_hash_str_find ( self , str. as_ptr ( ) , key. len ( ) as _ ) . as_mut ( ) }
237+ pub fn get_mut < ' a , K > ( & self , key : K ) -> Option < & mut Zval > where K : Into < ArrayKey < ' a > > {
238+ match key. into ( ) {
239+ ArrayKey :: Long ( index) => {
240+ unsafe { zend_hash_index_find ( self , index as zend_ulong ) . as_mut ( ) }
241+ }
242+ ArrayKey :: String ( key) => {
243+ if let Ok ( index) = i64:: from_str ( key. as_str ( ) ) {
244+ unsafe { zend_hash_index_find ( self , index as zend_ulong ) . as_mut ( ) }
245+ } else {
246+ unsafe { zend_hash_str_find ( self , CString :: new ( key. as_str ( ) ) . ok ( ) ?. as_ptr ( ) , key. len ( ) as _ ) . as_mut ( ) }
247+ }
248+ }
249+ ArrayKey :: Str ( key) => {
250+ if let Ok ( index) = i64:: from_str ( key) {
251+ unsafe { zend_hash_index_find ( self , index as zend_ulong ) . as_mut ( ) }
252+ } else {
253+ unsafe { zend_hash_str_find ( self , CString :: new ( key) . ok ( ) ?. as_ptr ( ) , key. len ( ) as _ ) . as_mut ( ) }
254+ }
255+ }
256+ }
222257 }
223258
224259 /// Attempts to retrieve a value from the hash table with an index.
@@ -244,8 +279,8 @@ impl ZendHashTable {
244279 /// assert_eq!(ht.get_index(0).and_then(|zv| zv.long()), Some(100));
245280 /// ```
246281 #[ must_use]
247- pub fn get_index ( & self , key : u64 ) -> Option < & Zval > {
248- unsafe { zend_hash_index_find ( self , key) . as_ref ( ) }
282+ pub fn get_index ( & self , key : i64 ) -> Option < & Zval > {
283+ unsafe { zend_hash_index_find ( self , key as zend_ulong ) . as_ref ( ) }
249284 }
250285
251286 /// Attempts to retrieve a value from the hash table with an index.
@@ -271,8 +306,8 @@ impl ZendHashTable {
271306 /// assert_eq!(ht.get_index(0).and_then(|zv| zv.long()), Some(100));
272307 /// ```
273308 #[ must_use]
274- pub fn get_index_mut ( & self , key : u64 ) -> Option < & mut Zval > {
275- unsafe { zend_hash_index_find ( self , key) . as_mut ( ) }
309+ pub fn get_index_mut ( & self , key : i64 ) -> Option < & mut Zval > {
310+ unsafe { zend_hash_index_find ( self , key as zend_ulong ) . as_mut ( ) }
276311 }
277312
278313 /// Attempts to remove a value from the hash table with a string key.
@@ -299,9 +334,26 @@ impl ZendHashTable {
299334 /// ht.remove("test");
300335 /// assert_eq!(ht.len(), 0);
301336 /// ```
302- pub fn remove ( & mut self , key : & str ) -> Option < ( ) > {
303- let result =
304- unsafe { zend_hash_str_del ( self , CString :: new ( key) . ok ( ) ?. as_ptr ( ) , key. len ( ) as _ ) } ;
337+ pub fn remove < ' a , K > ( & mut self , key : K ) -> Option < ( ) > where K : Into < ArrayKey < ' a > > {
338+ let result = match key. into ( ) {
339+ ArrayKey :: Long ( index) => {
340+ unsafe { zend_hash_index_del ( self , index as zend_ulong ) }
341+ }
342+ ArrayKey :: String ( key) => {
343+ if let Ok ( index) = i64:: from_str ( key. as_str ( ) ) {
344+ unsafe { zend_hash_index_del ( self , index as zend_ulong ) }
345+ } else {
346+ unsafe { zend_hash_str_del ( self , CString :: new ( key. as_str ( ) ) . ok ( ) ?. as_ptr ( ) , key. len ( ) as _ ) }
347+ }
348+ }
349+ ArrayKey :: Str ( key) => {
350+ if let Ok ( index) = i64:: from_str ( key) {
351+ unsafe { zend_hash_index_del ( self , index as zend_ulong ) }
352+ } else {
353+ unsafe { zend_hash_str_del ( self , CString :: new ( key) . ok ( ) ?. as_ptr ( ) , key. len ( ) as _ ) }
354+ }
355+ }
356+ } ;
305357
306358 if result < 0 {
307359 None
@@ -334,8 +386,8 @@ impl ZendHashTable {
334386 /// ht.remove_index(0);
335387 /// assert_eq!(ht.len(), 0);
336388 /// ```
337- pub fn remove_index ( & mut self , key : u64 ) -> Option < ( ) > {
338- let result = unsafe { zend_hash_index_del ( self , key) } ;
389+ pub fn remove_index ( & mut self , key : i64 ) -> Option < ( ) > {
390+ let result = unsafe { zend_hash_index_del ( self , key as zend_ulong ) } ;
339391
340392 if result < 0 {
341393 None
@@ -373,12 +425,31 @@ impl ZendHashTable {
373425 /// ht.insert("c", "C");
374426 /// assert_eq!(ht.len(), 3);
375427 /// ```
376- pub fn insert < V > ( & mut self , key : & str , val : V ) -> Result < ( ) >
428+ pub fn insert < ' a , K , V > ( & mut self , key : K , val : V ) -> Result < ( ) >
377429 where
430+ K : Into < ArrayKey < ' a > > ,
378431 V : IntoZval ,
379432 {
380433 let mut val = val. into_zval ( false ) ?;
381- unsafe { zend_hash_str_update ( self , CString :: new ( key) ?. as_ptr ( ) , key. len ( ) , & raw mut val) } ;
434+ match key. into ( ) {
435+ ArrayKey :: Long ( index) => {
436+ unsafe { zend_hash_index_update ( self , index as zend_ulong , & raw mut val) } ;
437+ }
438+ ArrayKey :: String ( key) => {
439+ if let Ok ( idx) = i64:: from_str ( & key) {
440+ unsafe { zend_hash_index_update ( self , idx as zend_ulong , & mut val) } ;
441+ } else {
442+ unsafe { zend_hash_str_update ( self , CString :: new ( key. as_str ( ) ) ?. as_ptr ( ) , key. len ( ) , & raw mut val) } ;
443+ }
444+ }
445+ ArrayKey :: Str ( key) => {
446+ if let Ok ( idx) = i64:: from_str ( key) {
447+ unsafe { zend_hash_index_update ( self , idx as zend_ulong , & mut val) } ;
448+ } else {
449+ unsafe { zend_hash_str_update ( self , CString :: new ( key) ?. as_ptr ( ) , key. len ( ) , & raw mut val) } ;
450+ }
451+ }
452+ }
382453 val. release ( ) ;
383454 Ok ( ( ) )
384455 }
@@ -411,12 +482,12 @@ impl ZendHashTable {
411482 /// ht.insert_at_index(0, "C"); // notice overriding index 0
412483 /// assert_eq!(ht.len(), 2);
413484 /// ```
414- pub fn insert_at_index < V > ( & mut self , key : u64 , val : V ) -> Result < ( ) >
485+ pub fn insert_at_index < V > ( & mut self , key : i64 , val : V ) -> Result < ( ) >
415486 where
416487 V : IntoZval ,
417488 {
418489 let mut val = val. into_zval ( false ) ?;
419- unsafe { zend_hash_index_update ( self , key, & raw mut val) } ;
490+ unsafe { zend_hash_index_update ( self , key as zend_ulong , & raw mut val) } ;
420491 val. release ( ) ;
421492 Ok ( ( ) )
422493 }
@@ -554,6 +625,8 @@ impl ZendHashTable {
554625 /// }
555626 /// ArrayKey::String(key) => {
556627 /// }
628+ /// ArrayKey::Str(key) => {
629+ /// }
557630 /// }
558631 /// dbg!(key, val);
559632 /// }
@@ -606,15 +679,23 @@ pub struct Iter<'a> {
606679}
607680
608681/// Represents the key of a PHP array, which can be either a long or a string.
609- #[ derive( Debug , PartialEq ) ]
610- pub enum ArrayKey {
682+ #[ derive( Debug , Clone , PartialEq ) ]
683+ pub enum ArrayKey < ' a > {
611684 /// A numerical key.
612685 Long ( i64 ) ,
613686 /// A string key.
614687 String ( String ) ,
688+ /// A string key by reference.
689+ Str ( & ' a str ) ,
690+ }
691+
692+ impl From < String > for ArrayKey < ' _ > {
693+ fn from ( value : String ) -> Self {
694+ Self :: String ( value)
695+ }
615696}
616697
617- impl ArrayKey {
698+ impl ArrayKey < ' _ > {
618699 /// Check if the key is an integer.
619700 ///
620701 /// # Returns
@@ -625,20 +706,34 @@ impl ArrayKey {
625706 match self {
626707 ArrayKey :: Long ( _) => true ,
627708 ArrayKey :: String ( _) => false ,
709+ ArrayKey :: Str ( _) => false ,
628710 }
629711 }
630712}
631713
632- impl Display for ArrayKey {
714+ impl Display for ArrayKey < ' _ > {
633715 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
634716 match self {
635717 ArrayKey :: Long ( key) => write ! ( f, "{key}" ) ,
636718 ArrayKey :: String ( key) => write ! ( f, "{key}" ) ,
719+ ArrayKey :: Str ( key) => write ! ( f, "{key}" ) ,
637720 }
638721 }
639722}
640723
641- impl < ' a > FromZval < ' a > for ArrayKey {
724+ impl < ' a > From < & ' a str > for ArrayKey < ' a > {
725+ fn from ( key : & ' a str ) -> ArrayKey < ' a > {
726+ ArrayKey :: Str ( key)
727+ }
728+ }
729+
730+ impl < ' a > From < i64 > for ArrayKey < ' a > {
731+ fn from ( index : i64 ) -> ArrayKey < ' a > {
732+ ArrayKey :: Long ( index)
733+ }
734+ }
735+
736+ impl < ' a > FromZval < ' a > for ArrayKey < ' _ > {
642737 const TYPE : DataType = DataType :: String ;
643738
644739 fn from_zval ( zval : & ' a Zval ) -> Option < Self > {
@@ -680,7 +775,7 @@ impl<'a> Iter<'a> {
680775}
681776
682777impl < ' a > IntoIterator for & ' a ZendHashTable {
683- type Item = ( ArrayKey , & ' a Zval ) ;
778+ type Item = ( ArrayKey < ' a > , & ' a Zval ) ;
684779 type IntoIter = Iter < ' a > ;
685780
686781 /// Returns an iterator over the key(s) and value contained inside the
@@ -707,7 +802,7 @@ impl<'a> IntoIterator for &'a ZendHashTable {
707802}
708803
709804impl < ' a > Iterator for Iter < ' a > {
710- type Item = ( ArrayKey , & ' a Zval ) ;
805+ type Item = ( ArrayKey < ' a > , & ' a Zval ) ;
711806
712807 fn next ( & mut self ) -> Option < Self :: Item > {
713808 self . next_zval ( )
@@ -1046,8 +1141,8 @@ impl FromIterator<Zval> for ZBox<ZendHashTable> {
10461141 }
10471142}
10481143
1049- impl FromIterator < ( u64 , Zval ) > for ZBox < ZendHashTable > {
1050- fn from_iter < T : IntoIterator < Item = ( u64 , Zval ) > > ( iter : T ) -> Self {
1144+ impl FromIterator < ( i64 , Zval ) > for ZBox < ZendHashTable > {
1145+ fn from_iter < T : IntoIterator < Item = ( i64 , Zval ) > > ( iter : T ) -> Self {
10511146 let mut ht = ZendHashTable :: new ( ) ;
10521147 for ( key, val) in iter {
10531148 // Inserting a zval cannot fail, as `push` only returns `Err` if converting
@@ -1068,4 +1163,4 @@ impl<'a> FromIterator<(&'a str, Zval)> for ZBox<ZendHashTable> {
10681163 }
10691164 ht
10701165 }
1071- }
1166+ }
0 commit comments