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

davidcole1340 / ext-php-rs / 18881635050

28 Oct 2025 04:18PM UTC coverage: 31.037% (-0.1%) from 31.138%
18881635050

Pull #566

github

web-flow
Merge 610ff3dd0 into a0387a4cd
Pull Request #566: chore(rust): bump Rust edition to 2024

10 of 91 new or added lines in 14 files covered. (10.99%)

1 existing line in 1 file now uncovered.

1356 of 4369 relevant lines covered (31.04%)

8.5 hits per line

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

24.47
/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, HT_MIN_SIZE, zend_array_count, zend_array_destroy, zend_array_dup,
13
        zend_hash_clean, 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
    },
16
    flags::DataType,
17
    types::Zval,
18
};
19

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

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

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

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

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

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

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

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

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

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

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

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

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

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

NEW
369
        if result < 0 { None } else { Some(()) }
×
370
    }
371

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

NEW
402
        if result < 0 { None } else { Some(()) }
×
403
    }
404

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

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

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

543
        Ok(())
×
544
    }
545

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

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

606
    /// Returns an iterator over the values contained inside the hashtable, as
607
    /// if it was a set or list.
608
    ///
609
    /// # Example
610
    ///
611
    /// ```no_run
612
    /// use ext_php_rs::types::ZendHashTable;
613
    ///
614
    /// let mut ht = ZendHashTable::new();
615
    ///
616
    /// for val in ht.values() {
617
    ///     dbg!(val);
618
    /// }
619
    #[inline]
620
    #[must_use]
621
    pub fn values(&self) -> Values<'_> {
×
622
        Values::new(self)
×
623
    }
624

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

653
unsafe impl ZBoxable for ZendHashTable {
654
    fn free(&mut self) {
14✔
655
        // SAFETY: ZBox has immutable access to `self`.
656
        unsafe { zend_array_destroy(self) }
28✔
657
    }
658
}
659

660
impl Debug for ZendHashTable {
661
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
×
662
        f.debug_map()
×
663
            .entries(self.into_iter().map(|(k, v)| (k.to_string(), v)))
×
664
            .finish()
665
    }
666
}
667

668
impl ToOwned for ZendHashTable {
669
    type Owned = ZBox<ZendHashTable>;
670

671
    fn to_owned(&self) -> Self::Owned {
×
672
        unsafe {
673
            // SAFETY: FFI call does not modify `self`, returns a new hashtable.
674
            let ptr = zend_array_dup(ptr::from_ref(self).cast_mut());
×
675

676
            // SAFETY: `as_mut()` checks if the pointer is null, and panics if it is not.
677
            ZBox::from_raw(
678
                ptr.as_mut()
×
679
                    .expect("Failed to allocate memory for hashtable"),
×
680
            )
681
        }
682
    }
683
}
684

685
impl Default for ZBox<ZendHashTable> {
686
    fn default() -> Self {
×
687
        ZendHashTable::new()
×
688
    }
689
}
690

691
impl Clone for ZBox<ZendHashTable> {
692
    fn clone(&self) -> Self {
×
693
        (**self).to_owned()
×
694
    }
695
}
696

697
impl IntoZval for ZBox<ZendHashTable> {
698
    const TYPE: DataType = DataType::Array;
699
    const NULLABLE: bool = false;
700

701
    fn set_zval(self, zv: &mut Zval, _: bool) -> Result<()> {
×
702
        zv.set_hashtable(self);
×
703
        Ok(())
×
704
    }
705
}
706

707
impl<'a> FromZval<'a> for &'a ZendHashTable {
708
    const TYPE: DataType = DataType::Array;
709

710
    fn from_zval(zval: &'a Zval) -> Option<Self> {
×
711
        zval.array()
×
712
    }
713
}
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

© 2025 Coveralls, Inc