artichoke_backend/convert/
array.rs

1use crate::Artichoke;
2use crate::convert::{BoxUnboxVmValue, UnboxRubyError};
3use crate::core::{Convert, TryConvert, TryConvertMut, Value as _};
4use crate::error::Error;
5use crate::extn::core::array::Array;
6use crate::types::{Ruby, Rust};
7use crate::value::Value;
8
9impl TryConvertMut<&[Value], Value> for Artichoke {
10    type Error = Error;
11
12    fn try_convert_mut(&mut self, value: &[Value]) -> Result<Value, Self::Error> {
13        let ary = Array::from(value);
14        let value = Array::alloc_value(ary, self)?;
15        Ok(self.protect(value))
16    }
17}
18
19impl TryConvertMut<Vec<Value>, Value> for Artichoke {
20    type Error = Error;
21
22    fn try_convert_mut(&mut self, value: Vec<Value>) -> Result<Value, Self::Error> {
23        let ary = Array::from(value);
24        let value = Array::alloc_value(ary, self)?;
25        Ok(self.protect(value))
26    }
27}
28
29impl TryConvertMut<&[Option<Value>], Value> for Artichoke {
30    type Error = Error;
31
32    fn try_convert_mut(&mut self, value: &[Option<Value>]) -> Result<Value, Self::Error> {
33        let ary = value.iter().collect();
34        let value = Array::alloc_value(ary, self)?;
35        Ok(self.protect(value))
36    }
37}
38
39impl TryConvertMut<Vec<Vec<u8>>, Value> for Artichoke {
40    type Error = Error;
41
42    fn try_convert_mut(&mut self, value: Vec<Vec<u8>>) -> Result<Value, Self::Error> {
43        let ary = value
44            .into_iter()
45            .map(|item| self.try_convert_mut(item))
46            .collect::<Result<Array, _>>()?;
47        let value = Array::alloc_value(ary, self)?;
48        Ok(self.protect(value))
49    }
50}
51
52impl TryConvertMut<Vec<&[u8]>, Value> for Artichoke {
53    type Error = Error;
54
55    fn try_convert_mut(&mut self, value: Vec<&[u8]>) -> Result<Value, Self::Error> {
56        let ary = value
57            .into_iter()
58            .map(|item| self.try_convert_mut(item))
59            .collect::<Result<Array, _>>()?;
60        let value = Array::alloc_value(ary, self)?;
61        Ok(self.protect(value))
62    }
63}
64
65impl TryConvertMut<&[Vec<u8>], Value> for Artichoke {
66    type Error = Error;
67
68    fn try_convert_mut(&mut self, value: &[Vec<u8>]) -> Result<Value, Self::Error> {
69        let ary = value
70            .iter()
71            .map(|item| self.try_convert_mut(item.as_slice()))
72            .collect::<Result<Array, _>>()?;
73        let value = Array::alloc_value(ary, self)?;
74        Ok(self.protect(value))
75    }
76}
77
78impl TryConvertMut<&[&[u8]], Value> for Artichoke {
79    type Error = Error;
80
81    fn try_convert_mut(&mut self, value: &[&[u8]]) -> Result<Value, Self::Error> {
82        let ary = value
83            .iter()
84            .copied()
85            .map(|item| self.try_convert_mut(item))
86            .collect::<Result<Array, _>>()?;
87        let value = Array::alloc_value(ary, self)?;
88        Ok(self.protect(value))
89    }
90}
91
92impl TryConvertMut<Vec<String>, Value> for Artichoke {
93    type Error = Error;
94
95    fn try_convert_mut(&mut self, value: Vec<String>) -> Result<Value, Self::Error> {
96        let ary = value
97            .into_iter()
98            .map(|item| self.try_convert_mut(item))
99            .collect::<Result<Array, _>>()?;
100        let value = Array::alloc_value(ary, self)?;
101        Ok(self.protect(value))
102    }
103}
104
105impl TryConvertMut<Vec<&str>, Value> for Artichoke {
106    type Error = Error;
107
108    fn try_convert_mut(&mut self, value: Vec<&str>) -> Result<Value, Self::Error> {
109        let ary = value
110            .into_iter()
111            .map(|item| self.try_convert_mut(item))
112            .collect::<Result<Array, _>>()?;
113        let value = Array::alloc_value(ary, self)?;
114        Ok(self.protect(value))
115    }
116}
117
118impl TryConvertMut<&[String], Value> for Artichoke {
119    type Error = Error;
120
121    fn try_convert_mut(&mut self, value: &[String]) -> Result<Value, Self::Error> {
122        let ary = value
123            .iter()
124            .map(|item| self.try_convert_mut(item.as_str()))
125            .collect::<Result<Array, _>>()?;
126        let value = Array::alloc_value(ary, self)?;
127        Ok(self.protect(value))
128    }
129}
130
131impl TryConvertMut<&[&str], Value> for Artichoke {
132    type Error = Error;
133
134    fn try_convert_mut(&mut self, value: &[&str]) -> Result<Value, Self::Error> {
135        let ary = value
136            .iter()
137            .copied()
138            .map(|item| self.try_convert_mut(item))
139            .collect::<Result<Array, _>>()?;
140        let value = Array::alloc_value(ary, self)?;
141        Ok(self.protect(value))
142    }
143}
144
145impl TryConvertMut<Vec<i64>, Value> for Artichoke {
146    type Error = Error;
147
148    fn try_convert_mut(&mut self, value: Vec<i64>) -> Result<Value, Self::Error> {
149        let iter = value.into_iter().map(|item| self.convert(item));
150        let ary = iter.collect();
151        let value = Array::alloc_value(ary, self)?;
152        Ok(self.protect(value))
153    }
154}
155
156impl TryConvertMut<&[i64], Value> for Artichoke {
157    type Error = Error;
158
159    fn try_convert_mut(&mut self, value: &[i64]) -> Result<Value, Self::Error> {
160        let iter = value.iter().copied().map(|item| self.convert(item));
161        let ary = iter.collect();
162        let value = Array::alloc_value(ary, self)?;
163        Ok(self.protect(value))
164    }
165}
166
167impl TryConvertMut<&[Option<Vec<u8>>], Value> for Artichoke {
168    type Error = Error;
169
170    fn try_convert_mut(&mut self, value: &[Option<Vec<u8>>]) -> Result<Value, Self::Error> {
171        let ary = value
172            .iter()
173            .map(|item| self.try_convert_mut(item.as_deref()))
174            .collect::<Result<Array, _>>()?;
175        let value = Array::alloc_value(ary, self)?;
176        Ok(self.protect(value))
177    }
178}
179
180impl TryConvertMut<Vec<Option<Vec<u8>>>, Value> for Artichoke {
181    type Error = Error;
182
183    fn try_convert_mut(&mut self, value: Vec<Option<Vec<u8>>>) -> Result<Value, Self::Error> {
184        let ary = value
185            .into_iter()
186            .map(|item| self.try_convert_mut(item))
187            .collect::<Result<Array, _>>()?;
188        let value = Array::alloc_value(ary, self)?;
189        Ok(self.protect(value))
190    }
191}
192
193impl TryConvertMut<&[Option<&[u8]>], Value> for Artichoke {
194    type Error = Error;
195
196    fn try_convert_mut(&mut self, value: &[Option<&[u8]>]) -> Result<Value, Self::Error> {
197        let ary = value
198            .iter()
199            .copied()
200            .map(|item| self.try_convert_mut(item))
201            .collect::<Result<Array, _>>()?;
202        let value = Array::alloc_value(ary, self)?;
203        Ok(self.protect(value))
204    }
205}
206
207impl TryConvertMut<Vec<Option<&[u8]>>, Value> for Artichoke {
208    type Error = Error;
209
210    fn try_convert_mut(&mut self, value: Vec<Option<&[u8]>>) -> Result<Value, Self::Error> {
211        let ary = value
212            .into_iter()
213            .map(|item| self.try_convert_mut(item))
214            .collect::<Result<Array, _>>()?;
215        let value = Array::alloc_value(ary, self)?;
216        Ok(self.protect(value))
217    }
218}
219
220impl TryConvertMut<Vec<Vec<Option<Vec<u8>>>>, Value> for Artichoke {
221    type Error = Error;
222
223    fn try_convert_mut(&mut self, value: Vec<Vec<Option<Vec<u8>>>>) -> Result<Value, Self::Error> {
224        let ary = value
225            .into_iter()
226            .map(|item| self.try_convert_mut(item))
227            .collect::<Result<Array, _>>()?;
228        let value = Array::alloc_value(ary, self)?;
229        Ok(self.protect(value))
230    }
231}
232
233impl TryConvertMut<Vec<Vec<Option<&[u8]>>>, Value> for Artichoke {
234    type Error = Error;
235
236    fn try_convert_mut(&mut self, value: Vec<Vec<Option<&[u8]>>>) -> Result<Value, Self::Error> {
237        let ary = value
238            .into_iter()
239            .map(|item| self.try_convert_mut(item))
240            .collect::<Result<Array, _>>()?;
241        let value = Array::alloc_value(ary, self)?;
242        Ok(self.protect(value))
243    }
244}
245
246impl TryConvertMut<&[Option<&str>], Value> for Artichoke {
247    type Error = Error;
248
249    fn try_convert_mut(&mut self, value: &[Option<&str>]) -> Result<Value, Self::Error> {
250        let ary = value
251            .iter()
252            .copied()
253            .map(|item| self.try_convert_mut(item))
254            .collect::<Result<Array, _>>()?;
255        let value = Array::alloc_value(ary, self)?;
256        Ok(self.protect(value))
257    }
258}
259
260impl TryConvertMut<Vec<Option<&str>>, Value> for Artichoke {
261    type Error = Error;
262
263    fn try_convert_mut(&mut self, value: Vec<Option<&str>>) -> Result<Value, Self::Error> {
264        let ary = value
265            .into_iter()
266            .map(|item| self.try_convert_mut(item))
267            .collect::<Result<Array, _>>()?;
268        let value = Array::alloc_value(ary, self)?;
269        Ok(self.protect(value))
270    }
271}
272
273impl TryConvertMut<Vec<Vec<Option<&str>>>, Value> for Artichoke {
274    type Error = Error;
275
276    fn try_convert_mut(&mut self, value: Vec<Vec<Option<&str>>>) -> Result<Value, Self::Error> {
277        let ary = value
278            .into_iter()
279            .map(|item| self.try_convert_mut(item))
280            .collect::<Result<Array, _>>()?;
281        let value = Array::alloc_value(ary, self)?;
282        Ok(self.protect(value))
283    }
284}
285
286impl TryConvertMut<Value, Vec<Value>> for Artichoke {
287    type Error = Error;
288
289    fn try_convert_mut(&mut self, mut value: Value) -> Result<Vec<Value>, Self::Error> {
290        let Ruby::Array = value.ruby_type() else {
291            return Err(UnboxRubyError::new(&value, Rust::Vec).into());
292        };
293        let array = unsafe { Array::unbox_from_value(&mut value, self)? };
294        Ok(array.iter().collect())
295    }
296}
297
298impl TryConvertMut<Value, Vec<Vec<u8>>> for Artichoke {
299    type Error = Error;
300
301    fn try_convert_mut(&mut self, mut value: Value) -> Result<Vec<Vec<u8>>, Self::Error> {
302        let Ruby::Array = value.ruby_type() else {
303            return Err(UnboxRubyError::new(&value, Rust::Vec).into());
304        };
305        let array = unsafe { Array::unbox_from_value(&mut value, self)? };
306        array.iter().map(|elem| self.try_convert_mut(elem)).collect()
307    }
308}
309
310impl TryConvertMut<Value, Vec<Option<Vec<u8>>>> for Artichoke {
311    type Error = Error;
312
313    fn try_convert_mut(&mut self, mut value: Value) -> Result<Vec<Option<Vec<u8>>>, Self::Error> {
314        let Ruby::Array = value.ruby_type() else {
315            return Err(UnboxRubyError::new(&value, Rust::Vec).into());
316        };
317        let array = unsafe { Array::unbox_from_value(&mut value, self)? };
318        array.iter().map(|elem| self.try_convert_mut(elem)).collect()
319    }
320}
321
322impl<'a> TryConvertMut<Value, Vec<&'a [u8]>> for Artichoke {
323    type Error = Error;
324
325    fn try_convert_mut(&mut self, mut value: Value) -> Result<Vec<&'a [u8]>, Self::Error> {
326        let Ruby::Array = value.ruby_type() else {
327            return Err(UnboxRubyError::new(&value, Rust::Vec).into());
328        };
329        let array = unsafe { Array::unbox_from_value(&mut value, self)? };
330        array.iter().map(|elem| self.try_convert_mut(elem)).collect()
331    }
332}
333
334impl<'a> TryConvertMut<Value, Vec<Option<&'a [u8]>>> for Artichoke {
335    type Error = Error;
336
337    fn try_convert_mut(&mut self, mut value: Value) -> Result<Vec<Option<&'a [u8]>>, Self::Error> {
338        let Ruby::Array = value.ruby_type() else {
339            return Err(UnboxRubyError::new(&value, Rust::Vec).into());
340        };
341        let array = unsafe { Array::unbox_from_value(&mut value, self)? };
342        array.iter().map(|elem| self.try_convert_mut(elem)).collect()
343    }
344}
345
346impl TryConvertMut<Value, Vec<String>> for Artichoke {
347    type Error = Error;
348
349    fn try_convert_mut(&mut self, mut value: Value) -> Result<Vec<String>, Self::Error> {
350        let Ruby::Array = value.ruby_type() else {
351            return Err(UnboxRubyError::new(&value, Rust::Vec).into());
352        };
353        let array = unsafe { Array::unbox_from_value(&mut value, self)? };
354        array.iter().map(|elem| self.try_convert_mut(elem)).collect()
355    }
356}
357
358impl TryConvertMut<Value, Vec<Option<String>>> for Artichoke {
359    type Error = Error;
360
361    fn try_convert_mut(&mut self, mut value: Value) -> Result<Vec<Option<String>>, Self::Error> {
362        let Ruby::Array = value.ruby_type() else {
363            return Err(UnboxRubyError::new(&value, Rust::Vec).into());
364        };
365        let array = unsafe { Array::unbox_from_value(&mut value, self)? };
366        array.iter().map(|elem| self.try_convert_mut(elem)).collect()
367    }
368}
369
370impl<'a> TryConvertMut<Value, Vec<&'a str>> for Artichoke {
371    type Error = Error;
372
373    fn try_convert_mut(&mut self, mut value: Value) -> Result<Vec<&'a str>, Self::Error> {
374        let Ruby::Array = value.ruby_type() else {
375            return Err(UnboxRubyError::new(&value, Rust::Vec).into());
376        };
377        let array = unsafe { Array::unbox_from_value(&mut value, self)? };
378        array.iter().map(|elem| self.try_convert_mut(elem)).collect()
379    }
380}
381
382impl<'a> TryConvertMut<Value, Vec<Option<&'a str>>> for Artichoke {
383    type Error = Error;
384
385    fn try_convert_mut(&mut self, mut value: Value) -> Result<Vec<Option<&'a str>>, Self::Error> {
386        let Ruby::Array = value.ruby_type() else {
387            return Err(UnboxRubyError::new(&value, Rust::Vec).into());
388        };
389        let array = unsafe { Array::unbox_from_value(&mut value, self)? };
390        array.iter().map(|elem| self.try_convert_mut(elem)).collect()
391    }
392}
393
394impl TryConvertMut<Value, Vec<i64>> for Artichoke {
395    type Error = Error;
396
397    fn try_convert_mut(&mut self, mut value: Value) -> Result<Vec<i64>, Self::Error> {
398        let Ruby::Array = value.ruby_type() else {
399            return Err(UnboxRubyError::new(&value, Rust::Vec).into());
400        };
401        let array = unsafe { Array::unbox_from_value(&mut value, self)? };
402        array.iter().map(|elem| self.try_convert(elem)).collect()
403    }
404}
405
406#[cfg(test)]
407mod tests {
408    use crate::test::prelude::*;
409
410    #[test]
411    fn fail_convert() {
412        let mut interp = interpreter();
413        // get a Ruby value that can't be converted to a primitive type.
414        let value = interp.eval(b"Object.new").unwrap();
415        let result = value.try_convert_into_mut::<Vec<Value>>(&mut interp);
416        assert!(result.is_err());
417    }
418
419    #[test]
420    fn prop_arr_int_borrowed() {
421        let mut interp = interpreter();
422        run_arbitrary::<Vec<i64>>(|arr| {
423            // Borrowed converter
424            let value = interp.try_convert_mut(arr.clone()).unwrap();
425            let len = value.funcall(&mut interp, "length", &[], None).unwrap();
426            let len = len.try_convert_into::<usize>(&interp).unwrap();
427            assert_eq!(len, arr.len());
428
429            let empty = value.funcall(&mut interp, "empty?", &[], None).unwrap();
430            let empty = empty.try_convert_into::<bool>(&interp).unwrap();
431            assert_eq!(empty, arr.is_empty());
432
433            let recovered: Vec<i64> = interp.try_convert_mut(value).unwrap();
434            assert_eq!(recovered, arr);
435        });
436    }
437
438    #[test]
439    fn prop_arr_int_owned() {
440        let mut interp = interpreter();
441        run_arbitrary::<Vec<i64>>(|arr| {
442            // Owned converter
443            let value = interp.try_convert_mut(arr.clone()).unwrap();
444            let len = value.funcall(&mut interp, "length", &[], None).unwrap();
445            let len = len.try_convert_into::<usize>(&interp).unwrap();
446            assert_eq!(len, arr.len());
447
448            let empty = value.funcall(&mut interp, "empty?", &[], None).unwrap();
449            let empty = empty.try_convert_into::<bool>(&interp).unwrap();
450            assert_eq!(empty, arr.is_empty());
451
452            let recovered: Vec<i64> = interp.try_convert_mut(value).unwrap();
453            assert_eq!(recovered, arr);
454        });
455    }
456
457    #[test]
458    fn prop_arr_utf8_borrowed() {
459        let mut interp = interpreter();
460        run_arbitrary::<Vec<String>>(|arr| {
461            // Borrowed converter
462            let value = interp.try_convert_mut(arr.as_slice()).unwrap();
463            let len = value.funcall(&mut interp, "length", &[], None).unwrap();
464            let len = len.try_convert_into::<usize>(&interp).unwrap();
465            assert_eq!(len, arr.len());
466
467            let empty = value.funcall(&mut interp, "empty?", &[], None).unwrap();
468            let empty = empty.try_convert_into::<bool>(&interp).unwrap();
469            assert_eq!(empty, arr.is_empty());
470
471            let recovered: Vec<String> = interp.try_convert_mut(value).unwrap();
472            assert_eq!(recovered, arr);
473        });
474    }
475
476    #[test]
477    fn prop_arr_utf8_owned() {
478        let mut interp = interpreter();
479        run_arbitrary::<Vec<String>>(|arr| {
480            // Owned converter
481            let value = interp.try_convert_mut(arr.clone()).unwrap();
482            let len = value.funcall(&mut interp, "length", &[], None).unwrap();
483            let len = len.try_convert_into::<usize>(&interp).unwrap();
484            assert_eq!(len, arr.len());
485
486            let empty = value.funcall(&mut interp, "empty?", &[], None).unwrap();
487            let empty = empty.try_convert_into::<bool>(&interp).unwrap();
488            assert_eq!(empty, arr.is_empty());
489
490            let recovered: Vec<String> = interp.try_convert_mut(value).unwrap();
491            assert_eq!(recovered, arr);
492        });
493    }
494
495    #[test]
496    fn prop_arr_nilable_bstr_borrowed() {
497        let mut interp = interpreter();
498        run_arbitrary::<Vec<Option<Vec<u8>>>>(|arr| {
499            // Borrowed converter
500            let value = interp.try_convert_mut(arr.as_slice()).unwrap();
501            let len = value.funcall(&mut interp, "length", &[], None).unwrap();
502            let len = len.try_convert_into::<usize>(&interp).unwrap();
503            assert_eq!(len, arr.len());
504
505            let empty = value.funcall(&mut interp, "empty?", &[], None).unwrap();
506            let empty = empty.try_convert_into::<bool>(&interp).unwrap();
507            assert_eq!(empty, arr.is_empty());
508
509            let recovered: Vec<Option<Vec<u8>>> = interp.try_convert_mut(value).unwrap();
510            assert_eq!(recovered, arr);
511        });
512    }
513
514    #[test]
515    fn prop_arr_nilable_bstr_owned() {
516        let mut interp = interpreter();
517        run_arbitrary::<Vec<Option<Vec<u8>>>>(|arr| {
518            // Owned converter
519            let value = interp.try_convert_mut(arr.clone()).unwrap();
520            let len = value.funcall(&mut interp, "length", &[], None).unwrap();
521            let len = len.try_convert_into::<usize>(&interp).unwrap();
522            assert_eq!(len, arr.len());
523
524            let empty = value.funcall(&mut interp, "empty?", &[], None).unwrap();
525            let empty = empty.try_convert_into::<bool>(&interp).unwrap();
526            assert_eq!(empty, arr.is_empty());
527
528            let recovered: Vec<Option<Vec<u8>>> = interp.try_convert_mut(value).unwrap();
529            assert_eq!(recovered, arr);
530        });
531    }
532
533    #[test]
534    fn prop_roundtrip_err() {
535        let mut interp = interpreter();
536        run_arbitrary::<i64>(|i| {
537            let value = interp.convert(i);
538            let value = value.try_convert_into_mut::<Vec<Value>>(&mut interp);
539            assert!(value.is_err());
540        });
541    }
542}