• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

davidcole1340 / ext-php-rs / 16431545231

22 Jul 2025 12:41AM UTC coverage: 27.13% (-0.01%) from 27.144%
16431545231

Pull #535

github

web-flow
Merge 6c83cebda into 6869625f4
Pull Request #535: feat(array): introducing BTreeMap conversion and refactoring HashMap conversion

8 of 48 new or added lines in 4 files covered. (16.67%)

1124 of 4143 relevant lines covered (27.13%)

5.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

19.39
/src/types/array/mod.rs
1
//! Represents an array in PHP. As all arrays in PHP are associative arrays,
2
//! they are represented by hash tables.
3

4
use std::{convert::TryFrom, ffi::CString, fmt::Debug, ptr};
5

6
use crate::{
7
    boxed::{ZBox, ZBoxable},
8
    convert::{FromZval, IntoZval},
9
    error::Result,
10
    ffi::zend_ulong,
11
    ffi::{
12
        _zend_new_array, zend_array_count, zend_array_destroy, zend_array_dup, zend_hash_clean,
13
        zend_hash_index_del, zend_hash_index_find, zend_hash_index_update,
14
        zend_hash_next_index_insert, zend_hash_str_del, zend_hash_str_find, zend_hash_str_update,
15
        HT_MIN_SIZE,
16
    },
17
    flags::DataType,
18
    types::Zval,
19
};
20

21
mod array_key;
22
mod conversions;
23
mod iterators;
24

25
pub use array_key::ArrayKey;
26
pub use iterators::{Iter, Values};
27

28
/// A PHP hashtable.
29
///
30
/// In PHP, arrays are represented as hashtables. This allows you to push values
31
/// onto the end of the array like a vector, while also allowing you to insert
32
/// at arbitrary string key indexes.
33
///
34
/// A PHP hashtable stores values as [`Zval`]s. This allows you to insert
35
/// different types into the same hashtable. Types must implement [`IntoZval`]
36
/// to be able to be inserted into the hashtable.
37
///
38
/// # Examples
39
///
40
/// ```no_run
41
/// use ext_php_rs::types::ZendHashTable;
42
///
43
/// let mut ht = ZendHashTable::new();
44
/// ht.push(1);
45
/// ht.push("Hello, world!");
46
/// ht.insert("Like", "Hashtable");
47
///
48
/// assert_eq!(ht.len(), 3);
49
/// assert_eq!(ht.get_index(0).and_then(|zv| zv.long()), Some(1));
50
/// ```
51
pub type ZendHashTable = crate::ffi::HashTable;
52

53
// Clippy complains about there being no `is_empty` function when implementing
54
// on the alias `ZendStr` :( <https://github.com/rust-lang/rust-clippy/issues/7702>
55
#[allow(clippy::len_without_is_empty)]
56
impl ZendHashTable {
57
    /// Creates a new, empty, PHP hashtable, returned inside a [`ZBox`].
58
    ///
59
    /// # Example
60
    ///
61
    /// ```no_run
62
    /// use ext_php_rs::types::ZendHashTable;
63
    ///
64
    /// let ht = ZendHashTable::new();
65
    /// ```
66
    ///
67
    /// # Panics
68
    ///
69
    /// Panics if memory for the hashtable could not be allocated.
70
    #[must_use]
71
    pub fn new() -> ZBox<Self> {
9✔
72
        Self::with_capacity(HT_MIN_SIZE)
9✔
73
    }
74

75
    /// Creates a new, empty, PHP hashtable with an initial size, returned
76
    /// inside a [`ZBox`].
77
    ///
78
    /// # Parameters
79
    ///
80
    /// * `size` - The size to initialize the array with.
81
    ///
82
    /// # Example
83
    ///
84
    /// ```no_run
85
    /// use ext_php_rs::types::ZendHashTable;
86
    ///
87
    /// let ht = ZendHashTable::with_capacity(10);
88
    /// ```
89
    ///
90
    /// # Panics
91
    ///
92
    /// Panics if memory for the hashtable could not be allocated.
93
    #[must_use]
94
    pub fn with_capacity(size: u32) -> ZBox<Self> {
13✔
95
        unsafe {
96
            // SAFETY: PHP allocator handles the creation of the array.
97
            #[allow(clippy::used_underscore_items)]
98
            let ptr = _zend_new_array(size);
39✔
99

100
            // SAFETY: `as_mut()` checks if the pointer is null, and panics if it is not.
101
            ZBox::from_raw(
102
                ptr.as_mut()
39✔
103
                    .expect("Failed to allocate memory for hashtable"),
13✔
104
            )
105
        }
106
    }
107

108
    /// Returns the current number of elements in the array.
109
    ///
110
    /// # Example
111
    ///
112
    /// ```no_run
113
    /// use ext_php_rs::types::ZendHashTable;
114
    ///
115
    /// let mut ht = ZendHashTable::new();
116
    ///
117
    /// ht.push(1);
118
    /// ht.push("Hello, world");
119
    ///
120
    /// assert_eq!(ht.len(), 2);
121
    /// ```
122
    #[must_use]
123
    pub fn len(&self) -> usize {
22✔
124
        unsafe { zend_array_count(ptr::from_ref(self).cast_mut()) as usize }
66✔
125
    }
126

127
    /// Returns whether the hash table is empty.
128
    ///
129
    /// # Example
130
    ///
131
    /// ```no_run
132
    /// use ext_php_rs::types::ZendHashTable;
133
    ///
134
    /// let mut ht = ZendHashTable::new();
135
    ///
136
    /// assert_eq!(ht.is_empty(), true);
137
    ///
138
    /// ht.push(1);
139
    /// ht.push("Hello, world");
140
    ///
141
    /// assert_eq!(ht.is_empty(), false);
142
    /// ```
143
    #[must_use]
144
    pub fn is_empty(&self) -> bool {
×
145
        self.len() == 0
×
146
    }
147

148
    /// Clears the hash table, removing all values.
149
    ///
150
    /// # Example
151
    ///
152
    /// ```no_run
153
    /// use ext_php_rs::types::ZendHashTable;
154
    ///
155
    /// let mut ht = ZendHashTable::new();
156
    ///
157
    /// ht.insert("test", "hello world");
158
    /// assert_eq!(ht.is_empty(), false);
159
    ///
160
    /// ht.clear();
161
    /// assert_eq!(ht.is_empty(), true);
162
    /// ```
163
    pub fn clear(&mut self) {
×
164
        unsafe { zend_hash_clean(self) }
×
165
    }
166

167
    /// Attempts to retrieve a value from the hash table with a string key.
168
    ///
169
    /// # Parameters
170
    ///
171
    /// * `key` - The key to search for in the hash table.
172
    ///
173
    /// # Returns
174
    ///
175
    /// * `Some(&Zval)` - A reference to the zval at the position in the hash
176
    ///   table.
177
    /// * `None` - No value at the given position was found.
178
    ///
179
    /// # Example
180
    ///
181
    /// ```no_run
182
    /// use ext_php_rs::types::ZendHashTable;
183
    ///
184
    /// let mut ht = ZendHashTable::new();
185
    ///
186
    /// ht.insert("test", "hello world");
187
    /// assert_eq!(ht.get("test").and_then(|zv| zv.str()), Some("hello world"));
188
    /// ```
189
    #[must_use]
190
    pub fn get<'a, K>(&self, key: K) -> Option<&Zval>
12✔
191
    where
192
        K: Into<ArrayKey<'a>>,
193
    {
194
        match key.into() {
12✔
195
            ArrayKey::Long(index) => unsafe {
196
                #[allow(clippy::cast_sign_loss)]
197
                zend_hash_index_find(self, index as zend_ulong).as_ref()
×
198
            },
199
            ArrayKey::String(key) => unsafe {
200
                zend_hash_str_find(
NEW
201
                    self,
×
NEW
202
                    CString::new(key.as_str()).ok()?.as_ptr(),
×
NEW
203
                    key.len() as _,
×
204
                )
205
                .as_ref()
206
            },
207
            ArrayKey::Str(key) => unsafe {
208
                zend_hash_str_find(self, CString::new(key).ok()?.as_ptr(), key.len() as _).as_ref()
30✔
209
            },
210
        }
211
    }
212

213
    /// Attempts to retrieve a value from the hash table with a string key.
214
    ///
215
    /// # Parameters
216
    ///
217
    /// * `key` - The key to search for in the hash table.
218
    ///
219
    /// # Returns
220
    ///
221
    /// * `Some(&Zval)` - A reference to the zval at the position in the hash
222
    ///   table.
223
    /// * `None` - No value at the given position was found.
224
    ///
225
    /// # Example
226
    ///
227
    /// ```no_run
228
    /// use ext_php_rs::types::ZendHashTable;
229
    ///
230
    /// let mut ht = ZendHashTable::new();
231
    ///
232
    /// ht.insert("test", "hello world");
233
    /// assert_eq!(ht.get("test").and_then(|zv| zv.str()), Some("hello world"));
234
    /// ```
235
    // TODO: Verify if this is safe to use, as it allows mutating the
236
    // hashtable while only having a reference to it. #461
237
    #[allow(clippy::mut_from_ref)]
238
    #[must_use]
239
    pub fn get_mut<'a, K>(&self, key: K) -> Option<&mut Zval>
×
240
    where
241
        K: Into<ArrayKey<'a>>,
242
    {
243
        match key.into() {
×
244
            ArrayKey::Long(index) => unsafe {
245
                #[allow(clippy::cast_sign_loss)]
246
                zend_hash_index_find(self, index as zend_ulong).as_mut()
×
247
            },
248
            ArrayKey::String(key) => unsafe {
249
                zend_hash_str_find(
NEW
250
                    self,
×
NEW
251
                    CString::new(key.as_str()).ok()?.as_ptr(),
×
NEW
252
                    key.len() as _,
×
253
                )
254
                .as_mut()
255
            },
256
            ArrayKey::Str(key) => unsafe {
NEW
257
                zend_hash_str_find(self, CString::new(key).ok()?.as_ptr(), key.len() as _).as_mut()
×
258
            },
259
        }
260
    }
261

262
    /// Attempts to retrieve a value from the hash table with an index.
263
    ///
264
    /// # Parameters
265
    ///
266
    /// * `key` - The key to search for in the hash table.
267
    ///
268
    /// # Returns
269
    ///
270
    /// * `Some(&Zval)` - A reference to the zval at the position in the hash
271
    ///   table.
272
    /// * `None` - No value at the given position was found.
273
    ///
274
    /// # Example
275
    ///
276
    /// ```no_run
277
    /// use ext_php_rs::types::ZendHashTable;
278
    ///
279
    /// let mut ht = ZendHashTable::new();
280
    ///
281
    /// ht.push(100);
282
    /// assert_eq!(ht.get_index(0).and_then(|zv| zv.long()), Some(100));
283
    /// ```
284
    #[must_use]
285
    pub fn get_index(&self, key: i64) -> Option<&Zval> {
×
286
        #[allow(clippy::cast_sign_loss)]
287
        unsafe {
288
            zend_hash_index_find(self, key as zend_ulong).as_ref()
×
289
        }
290
    }
291

292
    /// Attempts to retrieve a value from the hash table with an index.
293
    ///
294
    /// # Parameters
295
    ///
296
    /// * `key` - The key to search for in the hash table.
297
    ///
298
    /// # Returns
299
    ///
300
    /// * `Some(&Zval)` - A reference to the zval at the position in the hash
301
    ///   table.
302
    /// * `None` - No value at the given position was found.
303
    ///
304
    /// # Example
305
    ///
306
    /// ```no_run
307
    /// use ext_php_rs::types::ZendHashTable;
308
    ///
309
    /// let mut ht = ZendHashTable::new();
310
    ///
311
    /// ht.push(100);
312
    /// assert_eq!(ht.get_index(0).and_then(|zv| zv.long()), Some(100));
313
    /// ```
314
    // TODO: Verify if this is safe to use, as it allows mutating the
315
    // hashtable while only having a reference to it. #461
316
    #[allow(clippy::mut_from_ref)]
317
    #[must_use]
318
    pub fn get_index_mut(&self, key: i64) -> Option<&mut Zval> {
×
319
        unsafe {
320
            #[allow(clippy::cast_sign_loss)]
321
            zend_hash_index_find(self, key as zend_ulong).as_mut()
×
322
        }
323
    }
324

325
    /// Attempts to remove a value from the hash table with a string key.
326
    ///
327
    /// # Parameters
328
    ///
329
    /// * `key` - The key to remove from the hash table.
330
    ///
331
    /// # Returns
332
    ///
333
    /// * `Some(())` - Key was successfully removed.
334
    /// * `None` - No key was removed, did not exist.
335
    ///
336
    /// # Example
337
    ///
338
    /// ```no_run
339
    /// use ext_php_rs::types::ZendHashTable;
340
    ///
341
    /// let mut ht = ZendHashTable::new();
342
    ///
343
    /// ht.insert("test", "hello world");
344
    /// assert_eq!(ht.len(), 1);
345
    ///
346
    /// ht.remove("test");
347
    /// assert_eq!(ht.len(), 0);
348
    /// ```
349
    pub fn remove<'a, K>(&mut self, key: K) -> Option<()>
×
350
    where
351
        K: Into<ArrayKey<'a>>,
352
    {
353
        let result = match key.into() {
×
354
            ArrayKey::Long(index) => unsafe {
355
                #[allow(clippy::cast_sign_loss)]
356
                zend_hash_index_del(self, index as zend_ulong)
×
357
            },
358
            ArrayKey::String(key) => unsafe {
359
                zend_hash_str_del(
NEW
360
                    self,
×
NEW
361
                    CString::new(key.as_str()).ok()?.as_ptr(),
×
NEW
362
                    key.len() as _,
×
363
                )
364
            },
365
            ArrayKey::Str(key) => unsafe {
NEW
366
                zend_hash_str_del(self, CString::new(key).ok()?.as_ptr(), key.len() as _)
×
367
            },
368
        };
369

370
        if result < 0 {
×
371
            None
×
372
        } else {
373
            Some(())
×
374
        }
375
    }
376

377
    /// Attempts to remove a value from the hash table with a string key.
378
    ///
379
    /// # Parameters
380
    ///
381
    /// * `key` - The key to remove from the hash table.
382
    ///
383
    /// # Returns
384
    ///
385
    /// * `Ok(())` - Key was successfully removed.
386
    /// * `None` - No key was removed, did not exist.
387
    ///
388
    /// # Example
389
    ///
390
    /// ```no_run
391
    /// use ext_php_rs::types::ZendHashTable;
392
    ///
393
    /// let mut ht = ZendHashTable::new();
394
    ///
395
    /// ht.push("hello");
396
    /// assert_eq!(ht.len(), 1);
397
    ///
398
    /// ht.remove_index(0);
399
    /// assert_eq!(ht.len(), 0);
400
    /// ```
401
    pub fn remove_index(&mut self, key: i64) -> Option<()> {
×
402
        let result = unsafe {
403
            #[allow(clippy::cast_sign_loss)]
404
            zend_hash_index_del(self, key as zend_ulong)
×
405
        };
406

407
        if result < 0 {
×
408
            None
×
409
        } else {
410
            Some(())
×
411
        }
412
    }
413

414
    /// Attempts to insert an item into the hash table, or update if the key
415
    /// already exists. Returns nothing in a result if successful.
416
    ///
417
    /// # Parameters
418
    ///
419
    /// * `key` - The key to insert the value at in the hash table.
420
    /// * `value` - The value to insert into the hash table.
421
    ///
422
    /// # Returns
423
    ///
424
    /// Returns nothing in a result on success.
425
    ///
426
    /// # Errors
427
    ///
428
    /// Returns an error if the key could not be converted into a [`CString`],
429
    /// or converting the value into a [`Zval`] failed.
430
    ///
431
    /// # Example
432
    ///
433
    /// ```no_run
434
    /// use ext_php_rs::types::ZendHashTable;
435
    ///
436
    /// let mut ht = ZendHashTable::new();
437
    ///
438
    /// ht.insert("a", "A");
439
    /// ht.insert("b", "B");
440
    /// ht.insert("c", "C");
441
    /// assert_eq!(ht.len(), 3);
442
    /// ```
443
    pub fn insert<'a, K, V>(&mut self, key: K, val: V) -> Result<()>
35✔
444
    where
445
        K: Into<ArrayKey<'a>>,
446
        V: IntoZval,
447
    {
448
        let mut val = val.into_zval(false)?;
105✔
449
        match key.into() {
×
450
            ArrayKey::Long(index) => {
19✔
451
                unsafe {
452
                    #[allow(clippy::cast_sign_loss)]
453
                    zend_hash_index_update(self, index as zend_ulong, &raw mut val)
×
454
                };
455
            }
456
            ArrayKey::String(key) => {
×
457
                unsafe {
458
                    zend_hash_str_update(
NEW
459
                        self,
×
NEW
460
                        CString::new(key.as_str())?.as_ptr(),
×
NEW
461
                        key.len(),
×
NEW
462
                        &raw mut val,
×
463
                    )
464
                };
465
            }
466
            ArrayKey::Str(key) => {
16✔
467
                unsafe {
468
                    zend_hash_str_update(self, CString::new(key)?.as_ptr(), key.len(), &raw mut val)
64✔
469
                };
470
            }
471
        }
472
        val.release();
35✔
473
        Ok(())
×
474
    }
475

476
    /// Inserts an item into the hash table at a specified index, or updates if
477
    /// the key already exists. Returns nothing in a result if successful.
478
    ///
479
    /// # Parameters
480
    ///
481
    /// * `key` - The index at which the value should be inserted.
482
    /// * `val` - The value to insert into the hash table.
483
    ///
484
    /// # Returns
485
    ///
486
    /// Returns nothing in a result on success.
487
    ///
488
    /// # Errors
489
    ///
490
    /// Returns an error if converting the value into a [`Zval`] failed.
491
    ///
492
    /// # Example
493
    ///
494
    /// ```no_run
495
    /// use ext_php_rs::types::ZendHashTable;
496
    ///
497
    /// let mut ht = ZendHashTable::new();
498
    ///
499
    /// ht.insert_at_index(0, "A");
500
    /// ht.insert_at_index(5, "B");
501
    /// ht.insert_at_index(0, "C"); // notice overriding index 0
502
    /// assert_eq!(ht.len(), 2);
503
    /// ```
504
    pub fn insert_at_index<V>(&mut self, key: i64, val: V) -> Result<()>
×
505
    where
506
        V: IntoZval,
507
    {
508
        let mut val = val.into_zval(false)?;
×
509
        unsafe {
510
            #[allow(clippy::cast_sign_loss)]
511
            zend_hash_index_update(self, key as zend_ulong, &raw mut val)
×
512
        };
513
        val.release();
×
514
        Ok(())
×
515
    }
516

517
    /// Pushes an item onto the end of the hash table. Returns a result
518
    /// containing nothing if the element was successfully inserted.
519
    ///
520
    /// # Parameters
521
    ///
522
    /// * `val` - The value to insert into the hash table.
523
    ///
524
    /// # Returns
525
    ///
526
    /// Returns nothing in a result on success.
527
    ///
528
    /// # Errors
529
    ///
530
    /// Returns an error if converting the value into a [`Zval`] failed.
531
    ///
532
    /// # Example
533
    ///
534
    /// ```no_run
535
    /// use ext_php_rs::types::ZendHashTable;
536
    ///
537
    /// let mut ht = ZendHashTable::new();
538
    ///
539
    /// ht.push("a");
540
    /// ht.push("b");
541
    /// ht.push("c");
542
    /// assert_eq!(ht.len(), 3);
543
    /// ```
544
    pub fn push<V>(&mut self, val: V) -> Result<()>
×
545
    where
546
        V: IntoZval,
547
    {
548
        let mut val = val.into_zval(false)?;
×
549
        unsafe { zend_hash_next_index_insert(self, &raw mut val) };
×
550
        val.release();
×
551

552
        Ok(())
×
553
    }
554

555
    /// Checks if the hashtable only contains numerical keys.
556
    ///
557
    /// # Returns
558
    ///
559
    /// True if all keys on the hashtable are numerical.
560
    ///
561
    /// # Example
562
    ///
563
    /// ```no_run
564
    /// use ext_php_rs::types::ZendHashTable;
565
    ///
566
    /// let mut ht = ZendHashTable::new();
567
    ///
568
    /// ht.push(0);
569
    /// ht.push(3);
570
    /// ht.push(9);
571
    /// assert!(ht.has_numerical_keys());
572
    ///
573
    /// ht.insert("obviously not numerical", 10);
574
    /// assert!(!ht.has_numerical_keys());
575
    /// ```
576
    #[must_use]
577
    pub fn has_numerical_keys(&self) -> bool {
×
578
        !self.into_iter().any(|(k, _)| !k.is_long())
×
579
    }
580

581
    /// Checks if the hashtable has numerical, sequential keys.
582
    ///
583
    /// # Returns
584
    ///
585
    /// True if all keys on the hashtable are numerical and are in sequential
586
    /// order (i.e. starting at 0 and not skipping any keys).
587
    ///
588
    /// # Panics
589
    ///
590
    /// Panics if the number of elements in the hashtable exceeds `i64::MAX`.
591
    ///
592
    /// # Example
593
    ///
594
    /// ```no_run
595
    /// use ext_php_rs::types::ZendHashTable;
596
    ///
597
    /// let mut ht = ZendHashTable::new();
598
    ///
599
    /// ht.push(0);
600
    /// ht.push(3);
601
    /// ht.push(9);
602
    /// assert!(ht.has_sequential_keys());
603
    ///
604
    /// ht.insert_at_index(90, 10);
605
    /// assert!(!ht.has_sequential_keys());
606
    /// ```
607
    #[must_use]
608
    pub fn has_sequential_keys(&self) -> bool {
×
609
        !self
×
610
            .into_iter()
×
611
            .enumerate()
×
612
            .any(|(i, (k, _))| ArrayKey::Long(i64::try_from(i).expect("Integer overflow")) != k)
×
613
    }
614

615
    /// Returns an iterator over the values contained inside the hashtable, as
616
    /// if it was a set or list.
617
    ///
618
    /// # Example
619
    ///
620
    /// ```no_run
621
    /// use ext_php_rs::types::ZendHashTable;
622
    ///
623
    /// let mut ht = ZendHashTable::new();
624
    ///
625
    /// for val in ht.values() {
626
    ///     dbg!(val);
627
    /// }
628
    #[inline]
629
    #[must_use]
630
    pub fn values(&self) -> Values<'_> {
×
631
        Values::new(self)
×
632
    }
633

634
    /// Returns an iterator over the key(s) and value contained inside the
635
    /// hashtable.
636
    ///
637
    /// # Example
638
    ///
639
    /// ```no_run
640
    /// use ext_php_rs::types::{ZendHashTable, ArrayKey};
641
    ///
642
    /// let mut ht = ZendHashTable::new();
643
    ///
644
    /// for (key, val) in ht.iter() {
645
    ///     match &key {
646
    ///         ArrayKey::Long(index) => {
647
    ///         }
648
    ///         ArrayKey::String(key) => {
649
    ///         }
650
    ///         ArrayKey::Str(key) => {
651
    ///         }
652
    ///     }
653
    ///     dbg!(key, val);
654
    /// }
655
    #[inline]
656
    #[must_use]
657
    pub fn iter(&self) -> Iter<'_> {
×
658
        self.into_iter()
×
659
    }
660
}
661

662
unsafe impl ZBoxable for ZendHashTable {
663
    fn free(&mut self) {
7✔
664
        // SAFETY: ZBox has immutable access to `self`.
665
        unsafe { zend_array_destroy(self) }
14✔
666
    }
667
}
668

669
impl Debug for ZendHashTable {
670
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
×
671
        f.debug_map()
×
672
            .entries(self.into_iter().map(|(k, v)| (k.to_string(), v)))
×
673
            .finish()
674
    }
675
}
676

677
impl ToOwned for ZendHashTable {
678
    type Owned = ZBox<ZendHashTable>;
679

680
    fn to_owned(&self) -> Self::Owned {
×
681
        unsafe {
682
            // SAFETY: FFI call does not modify `self`, returns a new hashtable.
683
            let ptr = zend_array_dup(ptr::from_ref(self).cast_mut());
×
684

685
            // SAFETY: `as_mut()` checks if the pointer is null, and panics if it is not.
686
            ZBox::from_raw(
687
                ptr.as_mut()
×
688
                    .expect("Failed to allocate memory for hashtable"),
×
689
            )
690
        }
691
    }
692
}
693

694
impl Default for ZBox<ZendHashTable> {
695
    fn default() -> Self {
×
696
        ZendHashTable::new()
×
697
    }
698
}
699

700
impl Clone for ZBox<ZendHashTable> {
701
    fn clone(&self) -> Self {
×
702
        (**self).to_owned()
×
703
    }
704
}
705

706
impl IntoZval for ZBox<ZendHashTable> {
707
    const TYPE: DataType = DataType::Array;
708
    const NULLABLE: bool = false;
709

710
    fn set_zval(self, zv: &mut Zval, _: bool) -> Result<()> {
×
711
        zv.set_hashtable(self);
×
712
        Ok(())
×
713
    }
714
}
715

716
impl<'a> FromZval<'a> for &'a ZendHashTable {
717
    const TYPE: DataType = DataType::Array;
718

719
    fn from_zval(zval: &'a Zval) -> Option<Self> {
×
720
        zval.array()
×
721
    }
722
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc