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

davidcole1340 / ext-php-rs / 16392821488

19 Jul 2025 09:16PM UTC coverage: 24.784%. Remained the same
16392821488

push

github

web-flow
refactor(array): split `array.rs` types into smaller files

Fixes: #524

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

58.14
/src/types/array/conversions/vec.rs
1
use std::convert::TryFrom;
2

3
use crate::{
4
    boxed::ZBox,
5
    convert::{FromZval, IntoZval},
6
    error::{Error, Result},
7
    flags::DataType,
8
    types::Zval,
9
};
10

11
use super::super::{ArrayKey, ZendHashTable};
12

13
///////////////////////////////////////////
14
// Vec<(K, V)> conversions
15
///////////////////////////////////////////
16

17
impl<'a, K, V> TryFrom<&'a ZendHashTable> for Vec<(K, V)>
18
where
19
    K: TryFrom<ArrayKey<'a>, Error = Error>,
20
    V: FromZval<'a>,
21
{
22
    type Error = Error;
23

24
    fn try_from(value: &'a ZendHashTable) -> Result<Self> {
7✔
25
        let mut vec = Vec::with_capacity(value.len());
28✔
26

27
        for (key, val) in value {
46✔
28
            vec.push((
25✔
29
                key.try_into()?,
31✔
30
                V::from_zval(val).ok_or_else(|| Error::ZvalConversion(val.get_type()))?,
11✔
31
            ));
32
        }
33

34
        Ok(vec)
4✔
35
    }
36
}
37

38
impl<'a, V> TryFrom<&'a ZendHashTable> for Vec<(ArrayKey<'a>, V)>
39
where
40
    V: FromZval<'a>,
41
{
42
    type Error = Error;
43

44
    fn try_from(value: &'a ZendHashTable) -> Result<Self> {
2✔
45
        let mut vec = Vec::with_capacity(value.len());
8✔
46

47
        for (key, val) in value {
20✔
48
            vec.push((
12✔
49
                key,
6✔
50
                V::from_zval(val).ok_or_else(|| Error::ZvalConversion(val.get_type()))?,
18✔
51
            ));
52
        }
53

54
        Ok(vec)
2✔
55
    }
56
}
57

58
impl<'a, K, V> TryFrom<Vec<(K, V)>> for ZBox<ZendHashTable>
59
where
60
    K: Into<ArrayKey<'a>>,
61
    V: IntoZval,
62
{
63
    type Error = Error;
64

65
    fn try_from(value: Vec<(K, V)>) -> Result<Self> {
4✔
66
        let mut ht = ZendHashTable::with_capacity(
67
            value.len().try_into().map_err(|_| Error::IntegerOverflow)?,
16✔
68
        );
69

70
        for (k, v) in value {
40✔
71
            ht.insert(k, v)?;
36✔
72
        }
73

74
        Ok(ht)
4✔
75
    }
76
}
77

78
impl<'a, K, V> IntoZval for Vec<(K, V)>
79
where
80
    K: Into<ArrayKey<'a>>,
81
    V: IntoZval,
82
{
83
    const TYPE: DataType = DataType::Array;
84
    const NULLABLE: bool = false;
85

86
    fn set_zval(self, zv: &mut Zval, _: bool) -> Result<()> {
2✔
87
        let arr = self.try_into()?;
6✔
NEW
88
        zv.set_hashtable(arr);
×
NEW
89
        Ok(())
×
90
    }
91
}
92

93
impl<'a, K, V> FromZval<'a> for Vec<(K, V)>
94
where
95
    K: TryFrom<ArrayKey<'a>, Error = Error>,
96
    V: FromZval<'a>,
97
{
98
    const TYPE: DataType = DataType::Array;
99

100
    fn from_zval(zval: &'a Zval) -> Option<Self> {
3✔
101
        zval.array().and_then(|arr| arr.try_into().ok())
18✔
102
    }
103
}
104

105
impl<'a, V> FromZval<'a> for Vec<(ArrayKey<'a>, V)>
106
where
107
    V: FromZval<'a>,
108
{
109
    const TYPE: DataType = DataType::Array;
110

111
    fn from_zval(zval: &'a Zval) -> Option<Self> {
1✔
112
        zval.array().and_then(|arr| arr.try_into().ok())
6✔
113
    }
114
}
115

116
///////////////////////////////////////////
117
// Vec<T> conversions
118
///////////////////////////////////////////
119

120
impl<'a, T> TryFrom<&'a ZendHashTable> for Vec<T>
121
where
122
    T: FromZval<'a>,
123
{
124
    type Error = Error;
125

NEW
126
    fn try_from(value: &'a ZendHashTable) -> Result<Self> {
×
NEW
127
        let mut vec = Vec::with_capacity(value.len());
×
128

NEW
129
        for (_, val) in value {
×
NEW
130
            vec.push(T::from_zval(val).ok_or_else(|| Error::ZvalConversion(val.get_type()))?);
×
131
        }
132

NEW
133
        Ok(vec)
×
134
    }
135
}
136

137
impl<T> TryFrom<Vec<T>> for ZBox<ZendHashTable>
138
where
139
    T: IntoZval,
140
{
141
    type Error = Error;
142

NEW
143
    fn try_from(value: Vec<T>) -> Result<Self> {
×
144
        let mut ht = ZendHashTable::with_capacity(
NEW
145
            value.len().try_into().map_err(|_| Error::IntegerOverflow)?,
×
146
        );
147

NEW
148
        for val in value {
×
NEW
149
            ht.push(val)?;
×
150
        }
151

NEW
152
        Ok(ht)
×
153
    }
154
}
155

156
impl<T> IntoZval for Vec<T>
157
where
158
    T: IntoZval,
159
{
160
    const TYPE: DataType = DataType::Array;
161
    const NULLABLE: bool = false;
162

NEW
163
    fn set_zval(self, zv: &mut Zval, _: bool) -> Result<()> {
×
NEW
164
        let arr = self.try_into()?;
×
NEW
165
        zv.set_hashtable(arr);
×
NEW
166
        Ok(())
×
167
    }
168
}
169

170
impl<'a, T> FromZval<'a> for Vec<T>
171
where
172
    T: FromZval<'a>,
173
{
174
    const TYPE: DataType = DataType::Array;
175

NEW
176
    fn from_zval(zval: &'a Zval) -> Option<Self> {
×
NEW
177
        zval.array().and_then(|arr| arr.try_into().ok())
×
178
    }
179
}
180

181
#[cfg(test)]
182
#[cfg(feature = "embed")]
183
#[allow(clippy::unwrap_used)]
184
mod tests {
185
    use crate::boxed::ZBox;
186
    use crate::convert::{FromZval, IntoZval};
187
    use crate::embed::Embed;
188
    use crate::error::Error;
189
    use crate::types::{ArrayKey, ZendHashTable, Zval};
190

191
    #[test]
192
    fn test_hash_table_try_from_vec() {
193
        Embed::run(|| {
194
            let vec = vec![("key1", "value1"), ("key2", "value2"), ("key3", "value3")];
195

196
            let ht: ZBox<ZendHashTable> = vec.try_into().unwrap();
197
            assert_eq!(ht.len(), 3);
198
            assert_eq!(ht.get("key1").unwrap().string().unwrap(), "value1");
199
            assert_eq!(ht.get("key2").unwrap().string().unwrap(), "value2");
200
            assert_eq!(ht.get("key3").unwrap().string().unwrap(), "value3");
201

202
            let vec_i64 = vec![(1, "value1"), (2, "value2"), (3, "value3")];
203

204
            let ht_i64: ZBox<ZendHashTable> = vec_i64.try_into().unwrap();
205
            assert_eq!(ht_i64.len(), 3);
206
            assert_eq!(ht_i64.get(1).unwrap().string().unwrap(), "value1");
207
            assert_eq!(ht_i64.get(2).unwrap().string().unwrap(), "value2");
208
            assert_eq!(ht_i64.get(3).unwrap().string().unwrap(), "value3");
209
        });
210
    }
211

212
    #[test]
213
    fn test_vec_k_v_into_zval() {
214
        Embed::run(|| {
215
            let vec = vec![("key1", "value1"), ("key2", "value2"), ("key3", "value3")];
216

217
            let zval = vec.into_zval(false).unwrap();
218
            assert!(zval.is_array());
219
            let ht: &ZendHashTable = zval.array().unwrap();
220
            assert_eq!(ht.len(), 3);
221
            assert_eq!(ht.get("key1").unwrap().string().unwrap(), "value1");
222
            assert_eq!(ht.get("key2").unwrap().string().unwrap(), "value2");
223
            assert_eq!(ht.get("key3").unwrap().string().unwrap(), "value3");
224

225
            let vec_i64 = vec![(1, "value1"), (2, "value2"), (3, "value3")];
226
            let zval_i64 = vec_i64.into_zval(false).unwrap();
227
            assert!(zval_i64.is_array());
228
            let ht_i64: &ZendHashTable = zval_i64.array().unwrap();
229
            assert_eq!(ht_i64.len(), 3);
230
            assert_eq!(ht_i64.get(1).unwrap().string().unwrap(), "value1");
231
            assert_eq!(ht_i64.get(2).unwrap().string().unwrap(), "value2");
232
            assert_eq!(ht_i64.get(3).unwrap().string().unwrap(), "value3");
233
        });
234
    }
235

236
    #[test]
237
    fn test_vec_k_v_from_zval() {
238
        Embed::run(|| {
239
            let mut ht = ZendHashTable::new();
240
            ht.insert("key1", "value1").unwrap();
241
            ht.insert("key2", "value2").unwrap();
242
            ht.insert("key3", "value3").unwrap();
243
            let mut zval = Zval::new();
244
            zval.set_hashtable(ht);
245

246
            let vec: Vec<(String, String)> = Vec::<(String, String)>::from_zval(&zval).unwrap();
247
            assert_eq!(vec.len(), 3);
248
            assert_eq!(vec[0].0, "key1");
249
            assert_eq!(vec[0].1, "value1");
250
            assert_eq!(vec[1].0, "key2");
251
            assert_eq!(vec[1].1, "value2");
252
            assert_eq!(vec[2].0, "key3");
253
            assert_eq!(vec[2].1, "value3");
254

255
            let mut ht_i64 = ZendHashTable::new();
256
            ht_i64.insert(1, "value1").unwrap();
257
            ht_i64.insert("2", "value2").unwrap();
258
            ht_i64.insert(3, "value3").unwrap();
259
            let mut zval_i64 = Zval::new();
260
            zval_i64.set_hashtable(ht_i64);
261

262
            let vec_i64: Vec<(i64, String)> = Vec::<(i64, String)>::from_zval(&zval_i64).unwrap();
263
            assert_eq!(vec_i64.len(), 3);
264
            assert_eq!(vec_i64[0].0, 1);
265
            assert_eq!(vec_i64[0].1, "value1");
266
            assert_eq!(vec_i64[1].0, 2);
267
            assert_eq!(vec_i64[1].1, "value2");
268
            assert_eq!(vec_i64[2].0, 3);
269
            assert_eq!(vec_i64[2].1, "value3");
270

271
            let mut ht_mixed = ZendHashTable::new();
272
            ht_mixed.insert("key1", "value1").unwrap();
273
            ht_mixed.insert(2, "value2").unwrap();
274
            ht_mixed.insert("3", "value3").unwrap();
275
            let mut zval_mixed = Zval::new();
276
            zval_mixed.set_hashtable(ht_mixed);
277

278
            let vec_mixed: Option<Vec<(String, String)>> =
279
                Vec::<(String, String)>::from_zval(&zval_mixed);
280
            assert!(vec_mixed.is_none());
281
        });
282
    }
283

284
    #[test]
285
    fn test_vec_array_key_v_from_zval() {
286
        Embed::run(|| {
287
            let mut ht = ZendHashTable::new();
288
            ht.insert("key1", "value1").unwrap();
289
            ht.insert(2, "value2").unwrap();
290
            ht.insert("3", "value3").unwrap();
291
            let mut zval = Zval::new();
292
            zval.set_hashtable(ht);
293

294
            let vec: Vec<(ArrayKey, String)> = Vec::<(ArrayKey, String)>::from_zval(&zval).unwrap();
295
            assert_eq!(vec.len(), 3);
296
            assert_eq!(vec[0].0, ArrayKey::String("key1".to_string()));
297
            assert_eq!(vec[0].1, "value1");
298
            assert_eq!(vec[1].0, ArrayKey::Long(2));
299
            assert_eq!(vec[1].1, "value2");
300
            assert_eq!(vec[2].0, ArrayKey::Long(3));
301
            assert_eq!(vec[2].1, "value3");
302
        });
303
    }
304

305
    #[test]
306
    fn test_vec_i64_v_try_from_hash_table() {
307
        Embed::run(|| {
308
            let mut ht = ZendHashTable::new();
309
            ht.insert(1, "value1").unwrap();
310
            ht.insert("2", "value2").unwrap();
311

312
            let vec: Vec<(i64, String)> = ht.as_ref().try_into().unwrap();
313
            assert_eq!(vec.len(), 2);
314
            assert_eq!(vec[0].0, 1);
315
            assert_eq!(vec[0].1, "value1");
316
            assert_eq!(vec[1].0, 2);
317
            assert_eq!(vec[1].1, "value2");
318

319
            let mut ht2 = ZendHashTable::new();
320
            ht2.insert("key1", "value1").unwrap();
321
            ht2.insert("key2", "value2").unwrap();
322

323
            let vec2: crate::error::Result<Vec<(i64, String)>> = ht2.as_ref().try_into();
324
            assert!(vec2.is_err());
325
            assert!(matches!(vec2.unwrap_err(), Error::InvalidProperty));
326
        });
327
    }
328

329
    #[test]
330
    fn test_vec_string_v_try_from_hash_table() {
331
        Embed::run(|| {
332
            let mut ht = ZendHashTable::new();
333
            ht.insert("key1", "value1").unwrap();
334
            ht.insert("key2", "value2").unwrap();
335

336
            let vec: Vec<(String, String)> = ht.as_ref().try_into().unwrap();
337
            assert_eq!(vec.len(), 2);
338
            assert_eq!(vec[0].0, "key1");
339
            assert_eq!(vec[0].1, "value1");
340
            assert_eq!(vec[1].0, "key2");
341
            assert_eq!(vec[1].1, "value2");
342

343
            let mut ht2 = ZendHashTable::new();
344
            ht2.insert(1, "value1").unwrap();
345
            ht2.insert(2, "value2").unwrap();
346

347
            let vec2: crate::error::Result<Vec<(String, String)>> = ht2.as_ref().try_into();
348
            assert!(vec2.is_err());
349
            assert!(matches!(vec2.unwrap_err(), Error::InvalidProperty));
350
        });
351
    }
352

353
    #[test]
354
    fn test_vec_array_key_v_try_from_hash_table() {
355
        Embed::run(|| {
356
            let mut ht = ZendHashTable::new();
357
            ht.insert("key1", "value1").unwrap();
358
            ht.insert(2, "value2").unwrap();
359
            ht.insert("3", "value3").unwrap();
360

361
            let vec: Vec<(ArrayKey, String)> = ht.as_ref().try_into().unwrap();
362
            assert_eq!(vec.len(), 3);
363
            assert_eq!(vec[0].0, ArrayKey::String("key1".to_string()));
364
            assert_eq!(vec[0].1, "value1");
365
            assert_eq!(vec[1].0, ArrayKey::Long(2));
366
            assert_eq!(vec[1].1, "value2");
367
            assert_eq!(vec[2].0, ArrayKey::Long(3));
368
            assert_eq!(vec[2].1, "value3");
369
        });
370
    }
371
}
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