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

davidcole1340 / ext-php-rs / 16392720284

19 Jul 2025 09:04PM UTC coverage: 24.784%. Remained the same
16392720284

Pull #529

github

ptondereau
refactor(array): split array.rs types into smaller files
Pull Request #529: refactor(array): split array.rs types into smaller files

79 of 299 new or added lines in 5 files covered. (26.42%)

976 of 3938 relevant lines covered (24.78%)

5.6 hits per line

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

17.95
/src/types/array/iterators.rs
1
use std::{
2
    convert::TryInto,
3
    iter::{DoubleEndedIterator, ExactSizeIterator, Iterator},
4
    ptr,
5
};
6

7
use super::{ArrayKey, ZendHashTable};
8
use crate::boxed::ZBox;
9
use crate::{
10
    convert::FromZval,
11
    ffi::{
12
        zend_hash_get_current_data_ex, zend_hash_get_current_key_type_ex,
13
        zend_hash_get_current_key_zval_ex, zend_hash_move_backwards_ex, zend_hash_move_forward_ex,
14
        HashPosition,
15
    },
16
    types::Zval,
17
};
18

19
/// Immutable iterator upon a reference to a hashtable.
20
pub struct Iter<'a> {
21
    ht: &'a ZendHashTable,
22
    current_num: i64,
23
    end_num: i64,
24
    pos: HashPosition,
25
    end_pos: HashPosition,
26
}
27

28
impl<'a> Iter<'a> {
29
    /// Creates a new iterator over a hashtable.
30
    ///
31
    /// # Parameters
32
    ///
33
    /// * `ht` - The hashtable to iterate.
34
    pub fn new(ht: &'a ZendHashTable) -> Self {
9✔
35
        let end_num: i64 = ht
27✔
36
            .len()
37
            .try_into()
38
            .expect("Integer overflow in hashtable length");
39
        let end_pos = if ht.nNumOfElements > 0 {
18✔
40
            ht.nNumOfElements - 1
9✔
41
        } else {
NEW
42
            0
×
43
        };
44

45
        Self {
46
            ht,
47
            current_num: 0,
48
            end_num,
49
            pos: 0,
50
            end_pos,
51
        }
52
    }
53

54
    pub fn next_zval(&mut self) -> Option<(Zval, &'a Zval)> {
26✔
55
        if self.current_num >= self.end_num {
26✔
56
            return None;
6✔
57
        }
58

59
        let key_type = unsafe {
NEW
60
            zend_hash_get_current_key_type_ex(ptr::from_ref(self.ht).cast_mut(), &raw mut self.pos)
×
61
        };
62

63
        // Key type `-1` is ???
64
        // Key type `1` is string
65
        // Key type `2` is long
66
        // Key type `3` is null meaning the end of the array
67
        if key_type == -1 || key_type == 3 {
20✔
NEW
68
            return None;
×
69
        }
70

NEW
71
        let mut key = Zval::new();
×
72

73
        unsafe {
74
            zend_hash_get_current_key_zval_ex(
NEW
75
                ptr::from_ref(self.ht).cast_mut(),
×
NEW
76
                (&raw const key).cast_mut(),
×
NEW
77
                &raw mut self.pos,
×
78
            );
79
        }
80
        let value = unsafe {
NEW
81
            let val_ptr =
×
NEW
82
                zend_hash_get_current_data_ex(ptr::from_ref(self.ht).cast_mut(), &raw mut self.pos);
×
83

NEW
84
            if val_ptr.is_null() {
×
NEW
85
                return None;
×
86
            }
87

NEW
88
            &*val_ptr
×
89
        };
90

91
        if !key.is_long() && !key.is_string() {
9✔
NEW
92
            key.set_long(self.current_num);
×
93
        }
94

NEW
95
        unsafe { zend_hash_move_forward_ex(ptr::from_ref(self.ht).cast_mut(), &raw mut self.pos) };
×
NEW
96
        self.current_num += 1;
×
97

NEW
98
        Some((key, value))
×
99
    }
100
}
101

102
impl<'a> IntoIterator for &'a ZendHashTable {
103
    type Item = (ArrayKey<'a>, &'a Zval);
104
    type IntoIter = Iter<'a>;
105

106
    /// Returns an iterator over the key(s) and value contained inside the
107
    /// hashtable.
108
    ///
109
    /// # Example
110
    ///
111
    /// ```no_run
112
    /// use ext_php_rs::types::ZendHashTable;
113
    ///
114
    /// let mut ht = ZendHashTable::new();
115
    ///
116
    /// for (key, val) in ht.iter() {
117
    /// //   ^ Index if inserted at an index.
118
    /// //        ^ Optional string key, if inserted like a hashtable.
119
    /// //             ^ Inserted value.
120
    ///
121
    ///     dbg!(key, val);
122
    /// }
123
    #[inline]
124
    fn into_iter(self) -> Self::IntoIter {
9✔
125
        Iter::new(self)
18✔
126
    }
127
}
128

129
impl<'a> Iterator for Iter<'a> {
130
    type Item = (ArrayKey<'a>, &'a Zval);
131

132
    fn next(&mut self) -> Option<Self::Item> {
26✔
133
        self.next_zval()
52✔
134
            .map(|(k, v)| (ArrayKey::from_zval(&k).expect("Invalid array key!"), v))
126✔
135
    }
136

NEW
137
    fn count(self) -> usize
×
138
    where
139
        Self: Sized,
140
    {
NEW
141
        self.ht.len()
×
142
    }
143
}
144

145
impl ExactSizeIterator for Iter<'_> {
NEW
146
    fn len(&self) -> usize {
×
NEW
147
        self.ht.len()
×
148
    }
149
}
150

151
impl DoubleEndedIterator for Iter<'_> {
NEW
152
    fn next_back(&mut self) -> Option<Self::Item> {
×
NEW
153
        if self.end_num <= self.current_num {
×
NEW
154
            return None;
×
155
        }
156

157
        let key_type = unsafe {
NEW
158
            zend_hash_get_current_key_type_ex(ptr::from_ref(self.ht).cast_mut(), &raw mut self.pos)
×
159
        };
160

NEW
161
        if key_type == -1 {
×
NEW
162
            return None;
×
163
        }
164

NEW
165
        let key = Zval::new();
×
166

167
        unsafe {
168
            zend_hash_get_current_key_zval_ex(
NEW
169
                ptr::from_ref(self.ht).cast_mut(),
×
NEW
170
                (&raw const key).cast_mut(),
×
NEW
171
                &raw mut self.end_pos,
×
172
            );
173
        }
174
        let value = unsafe {
NEW
175
            &*zend_hash_get_current_data_ex(
×
NEW
176
                ptr::from_ref(self.ht).cast_mut(),
×
NEW
177
                &raw mut self.end_pos,
×
178
            )
179
        };
180

NEW
181
        let key = match ArrayKey::from_zval(&key) {
×
NEW
182
            Some(key) => key,
×
NEW
183
            None => ArrayKey::Long(self.end_num),
×
184
        };
185

186
        unsafe {
NEW
187
            zend_hash_move_backwards_ex(ptr::from_ref(self.ht).cast_mut(), &raw mut self.end_pos)
×
188
        };
NEW
189
        self.end_num -= 1;
×
190

NEW
191
        Some((key, value))
×
192
    }
193
}
194

195
/// Immutable iterator which iterates over the values of the hashtable, as it
196
/// was a set or list.
197
pub struct Values<'a>(Iter<'a>);
198

199
impl<'a> Values<'a> {
200
    /// Creates a new iterator over a hashtables values.
201
    ///
202
    /// # Parameters
203
    ///
204
    /// * `ht` - The hashtable to iterate.
NEW
205
    pub fn new(ht: &'a ZendHashTable) -> Self {
×
NEW
206
        Self(Iter::new(ht))
×
207
    }
208
}
209

210
impl<'a> Iterator for Values<'a> {
211
    type Item = &'a Zval;
212

NEW
213
    fn next(&mut self) -> Option<Self::Item> {
×
NEW
214
        self.0.next().map(|(_, zval)| zval)
×
215
    }
216

NEW
217
    fn count(self) -> usize
×
218
    where
219
        Self: Sized,
220
    {
NEW
221
        self.0.count()
×
222
    }
223
}
224

225
impl ExactSizeIterator for Values<'_> {
NEW
226
    fn len(&self) -> usize {
×
NEW
227
        self.0.len()
×
228
    }
229
}
230

231
impl DoubleEndedIterator for Values<'_> {
NEW
232
    fn next_back(&mut self) -> Option<Self::Item> {
×
NEW
233
        self.0.next_back().map(|(_, zval)| zval)
×
234
    }
235
}
236

237
impl FromIterator<Zval> for ZBox<ZendHashTable> {
NEW
238
    fn from_iter<T: IntoIterator<Item = Zval>>(iter: T) -> Self {
×
NEW
239
        let mut ht = ZendHashTable::new();
×
NEW
240
        for item in iter {
×
241
            // Inserting a zval cannot fail, as `push` only returns `Err` if converting
242
            // `val` to a zval fails.
NEW
243
            let _ = ht.push(item);
×
244
        }
NEW
245
        ht
×
246
    }
247
}
248

249
impl FromIterator<(i64, Zval)> for ZBox<ZendHashTable> {
NEW
250
    fn from_iter<T: IntoIterator<Item = (i64, Zval)>>(iter: T) -> Self {
×
NEW
251
        let mut ht = ZendHashTable::new();
×
NEW
252
        for (key, val) in iter {
×
253
            // Inserting a zval cannot fail, as `push` only returns `Err` if converting
254
            // `val` to a zval fails.
NEW
255
            let _ = ht.insert_at_index(key, val);
×
256
        }
NEW
257
        ht
×
258
    }
259
}
260

261
impl<'a> FromIterator<(&'a str, Zval)> for ZBox<ZendHashTable> {
NEW
262
    fn from_iter<T: IntoIterator<Item = (&'a str, Zval)>>(iter: T) -> Self {
×
NEW
263
        let mut ht = ZendHashTable::new();
×
NEW
264
        for (key, val) in iter {
×
265
            // Inserting a zval cannot fail, as `push` only returns `Err` if converting
266
            // `val` to a zval fails.
NEW
267
            let _ = ht.insert(key, val);
×
268
        }
NEW
269
        ht
×
270
    }
271
}
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