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

extphprs / ext-php-rs / 30644118628

31 Jul 2026 03:43PM UTC coverage: 66.519% (+0.008%) from 66.511%
30644118628

Pull #757

github

web-flow
Merge 32a5c43e8 into 522cf3424
Pull Request #757: fix(types)!: stop deriving mutable references from shared borrows

12 of 46 new or added lines in 8 files covered. (26.09%)

10 existing lines in 4 files now uncovered.

8859 of 13318 relevant lines covered (66.52%)

33.19 hits per line

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

0.0
/src/types/iterable.rs
1
use super::array::Iter as ZendHashTableIter;
2
use super::iterator::Iter as ZendIteratorIter;
3
use crate::convert::FromZvalMut;
4
use crate::flags::DataType;
5
use crate::types::{ZendHashTable, ZendIterator, Zval};
6

7
/// This type represents a PHP iterable, which can be either an array or an
8
/// object implementing the Traversable interface.
9
///
10
/// An `Iterable` can only be extracted from a mutable [`Zval`], via
11
/// [`FromZvalMut`]. Resolving the `Traversable` variant invokes the Zend
12
/// `get_iterator` handler, which mutates the object, so a shared borrow is not
13
/// enough:
14
///
15
/// ```compile_fail
16
/// use ext_php_rs::{convert::FromZvalMut, types::{Iterable, Zval}};
17
///
18
/// fn extract(zval: &Zval) -> Option<Iterable<'_>> {
19
///     Iterable::from_zval_mut(zval)
20
/// }
21
/// ```
22
#[derive(Debug)]
23
pub enum Iterable<'a> {
24
    /// Iterable is an Array
25
    Array(&'a ZendHashTable),
26
    /// Iterable is a Traversable
27
    Traversable(&'a mut ZendIterator),
28
}
29

30
impl Iterable<'_> {
31
    /// Creates a new rust iterator from a PHP iterable.
32
    /// May return None if a Traversable cannot be rewound.
33
    // TODO: Check iter not returning iterator
34
    #[allow(clippy::iter_not_returning_iterator)]
35
    pub fn iter(&mut self) -> Option<Iter<'_>> {
×
36
        match self {
×
37
            Iterable::Array(array) => Some(Iter::Array(array.iter())),
×
38
            Iterable::Traversable(traversable) => Some(Iter::Traversable(traversable.iter()?)),
×
39
        }
40
    }
×
41
}
42

43
// TODO: Implement `iter_mut`
44
#[allow(clippy::into_iter_without_iter)]
45
impl<'a> IntoIterator for &'a mut Iterable<'a> {
46
    type Item = (Zval, &'a Zval);
47
    type IntoIter = Iter<'a>;
48

49
    fn into_iter(self) -> Self::IntoIter {
×
50
        self.iter().expect("Could not rewind iterator!")
×
51
    }
×
52
}
53

54
impl<'a> FromZvalMut<'a> for Iterable<'a> {
55
    const TYPE: DataType = DataType::Iterable;
56

NEW
57
    fn from_zval_mut(zval: &'a mut Zval) -> Option<Self> {
×
NEW
58
        if zval.is_traversable() {
×
NEW
59
            return zval.traversable().map(Iterable::Traversable);
×
UNCOV
60
        }
×
61

NEW
62
        zval.array().map(Iterable::Array)
×
63
    }
×
64
}
65

66
/// Rust iterator over a PHP iterable.
67
pub enum Iter<'a> {
68
    Array(ZendHashTableIter<'a>),
69
    Traversable(ZendIteratorIter<'a>),
70
}
71

72
impl<'a> Iterator for Iter<'a> {
73
    type Item = (Zval, &'a Zval);
74

75
    fn next(&mut self) -> Option<Self::Item> {
×
76
        match self {
×
77
            Iter::Array(array) => array.next_zval(),
×
78
            Iter::Traversable(traversable) => traversable.next(),
×
79
        }
80
    }
×
81
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc