Thanks to visit codestin.com
Credit goes to docs.rs

magnus/
r_array.rs

1//! Types and functions for working with Ruby’s Array class.
2
3use std::{cmp::Ordering, convert::Infallible, fmt, marker::PhantomData, os::raw::c_long, slice};
4
5#[cfg(ruby_gte_3_2)]
6use rb_sys::rb_ary_hidden_new;
7#[cfg(ruby_lt_3_2)]
8use rb_sys::rb_ary_tmp_new as rb_ary_hidden_new;
9use rb_sys::{
10    self, rb_ary_assoc, rb_ary_cat, rb_ary_clear, rb_ary_cmp, rb_ary_concat, rb_ary_delete,
11    rb_ary_delete_at, rb_ary_entry, rb_ary_includes, rb_ary_join, rb_ary_new, rb_ary_new_capa,
12    rb_ary_new_from_values, rb_ary_plus, rb_ary_pop, rb_ary_push, rb_ary_rassoc, rb_ary_replace,
13    rb_ary_resize, rb_ary_reverse, rb_ary_rotate, rb_ary_shared_with_p, rb_ary_shift,
14    rb_ary_sort_bang, rb_ary_store, rb_ary_subseq, rb_ary_to_ary, rb_ary_unshift,
15    rb_check_array_type, rb_obj_hide, rb_obj_reveal, ruby_value_type, RARRAY_CONST_PTR, RARRAY_LEN,
16    VALUE,
17};
18use seq_macro::seq;
19
20use crate::{
21    enumerator::Enumerator,
22    error::{protect, Error},
23    gc,
24    into_value::{IntoValue, IntoValueFromNative},
25    object::Object,
26    r_string::{IntoRString, RString},
27    try_convert::{TryConvert, TryConvertOwned},
28    value::{
29        private::{self, ReprValue as _},
30        NonZeroValue, ReprValue, Value,
31    },
32    Ruby,
33};
34
35/// # `RArray`
36///
37/// Functions that can be used to create Ruby `Array`s.
38///
39/// See also the [`RArray`] type.
40impl Ruby {
41    /// Create a new empty `RArray`.
42    ///
43    /// # Examples
44    ///
45    /// ```
46    /// use magnus::{Error, Ruby};
47    ///
48    /// fn example(ruby: &Ruby) -> Result<(), Error> {
49    ///     let ary = ruby.ary_new();
50    ///     assert!(ary.is_empty());
51    ///
52    ///     Ok(())
53    /// }
54    /// # Ruby::init(example).unwrap()
55    /// ```
56    pub fn ary_new(&self) -> RArray {
57        unsafe { RArray::from_rb_value_unchecked(rb_ary_new()) }
58    }
59
60    /// Create a new empty `RArray` with capacity for `n` elements
61    /// pre-allocated.
62    ///
63    /// # Examples
64    ///
65    /// ```
66    /// use magnus::{Error, Ruby};
67    ///
68    /// fn example(ruby: &Ruby) -> Result<(), Error> {
69    ///     let ary = ruby.ary_new_capa(16);
70    ///     assert!(ary.is_empty());
71    ///
72    ///     Ok(())
73    /// }
74    /// # Ruby::init(example).unwrap()
75    /// ```
76    pub fn ary_new_capa(&self, n: usize) -> RArray {
77        unsafe { RArray::from_rb_value_unchecked(rb_ary_new_capa(n as c_long)) }
78    }
79
80    /// Create a new `RArray` from a Rust vector.
81    ///
82    /// # Examples
83    ///
84    /// ```
85    /// use magnus::{rb_assert, Error, Ruby};
86    ///
87    /// fn example(ruby: &Ruby) -> Result<(), Error> {
88    ///     let ary = ruby.ary_from_vec(vec![1, 2, 3]);
89    ///     rb_assert!(ruby, "ary == [1, 2, 3]", ary);
90    ///
91    ///     Ok(())
92    /// }
93    /// # Ruby::init(example).unwrap()
94    /// ```
95    pub fn ary_from_vec<T>(&self, vec: Vec<T>) -> RArray
96    where
97        T: IntoValueFromNative,
98    {
99        self.ary_from_iter(vec)
100    }
101
102    /// Create a new `RArray` containing the elements in `slice`.
103    ///
104    /// # Examples
105    ///
106    /// ```
107    /// use magnus::{prelude::*, rb_assert, Error, Ruby};
108    ///
109    /// fn example(ruby: &Ruby) -> Result<(), Error> {
110    ///     let ary = ruby.ary_new_from_values(&[
111    ///         ruby.to_symbol("a").as_value(),
112    ///         ruby.integer_from_i64(1).as_value(),
113    ///         ruby.qnil().as_value(),
114    ///     ]);
115    ///     rb_assert!(ruby, "ary == [:a, 1, nil]", ary);
116    ///
117    ///     Ok(())
118    /// }
119    /// # Ruby::init(example).unwrap()
120    /// ```
121    ///
122    /// ```
123    /// use magnus::{rb_assert, Error, Ruby};
124    ///
125    /// fn example(ruby: &Ruby) -> Result<(), Error> {
126    ///     let ary = ruby.ary_new_from_values(&[
127    ///         ruby.to_symbol("a"),
128    ///         ruby.to_symbol("b"),
129    ///         ruby.to_symbol("c"),
130    ///     ]);
131    ///     rb_assert!(ruby, "ary == [:a, :b, :c]", ary);
132    ///
133    ///     Ok(())
134    /// }
135    /// # Ruby::init(example).unwrap()
136    /// ```
137    pub fn ary_new_from_values<T>(&self, slice: &[T]) -> RArray
138    where
139        T: ReprValue,
140    {
141        let ptr = slice.as_ptr() as *const VALUE;
142        unsafe {
143            RArray::from_rb_value_unchecked(rb_ary_new_from_values(slice.len() as c_long, ptr))
144        }
145    }
146
147    /// Create a new `RArray` from a Rust iterator.
148    ///
149    /// # Examples
150    ///
151    /// ```
152    /// use magnus::{rb_assert, Error, Ruby};
153    ///
154    /// fn example(ruby: &Ruby) -> Result<(), Error> {
155    ///     let ary = ruby.ary_from_iter((1..4).map(|i| i * 10));
156    ///     rb_assert!(ruby, "ary == [10, 20, 30]", ary);
157    ///
158    ///     Ok(())
159    /// }
160    /// # Ruby::init(example).unwrap()
161    /// ```
162    pub fn ary_from_iter<I, T>(&self, iter: I) -> RArray
163    where
164        I: IntoIterator<Item = T>,
165        T: IntoValue,
166    {
167        self.ary_try_from_iter(iter.into_iter().map(Result::<_, Infallible>::Ok))
168            .unwrap()
169    }
170
171    /// Create a new `RArray` from a fallible Rust iterator.
172    ///
173    /// Returns `Ok(RArray)` on sucess or `Err(E)` with the first error
174    /// encountered.
175    ///
176    /// # Examples
177    ///
178    /// ```
179    /// use magnus::{rb_assert, Error, Ruby};
180    ///
181    /// fn example(ruby: &Ruby) -> Result<(), Error> {
182    ///     let ary = ruby
183    ///         .ary_try_from_iter("1,2,3,4".split(',').map(|s| s.parse::<i64>()))
184    ///         .map_err(|e| Error::new(ruby.exception_runtime_error(), e.to_string()))?;
185    ///     rb_assert!(ruby, "ary == [1, 2, 3, 4]", ary);
186    ///
187    ///     Ok(())
188    /// }
189    /// # Ruby::init(example).unwrap()
190    /// ```
191    ///
192    /// ```
193    /// use magnus::{Error, Ruby};
194    ///
195    /// fn example(ruby: &Ruby) -> Result<(), Error> {
196    ///     let err = ruby
197    ///         .ary_try_from_iter("1,2,foo,4".split(',').map(|s| s.parse::<i64>()))
198    ///         .unwrap_err();
199    ///     assert_eq!(err.to_string(), "invalid digit found in string");
200    ///
201    ///     Ok(())
202    /// }
203    /// # Ruby::init(example).unwrap()
204    /// ```
205    pub fn ary_try_from_iter<I, T, E>(&self, iter: I) -> Result<RArray, E>
206    where
207        I: IntoIterator<Item = Result<T, E>>,
208        T: IntoValue,
209    {
210        let iter = iter.into_iter();
211        let (lower, _) = iter.size_hint();
212        let ary = if lower > 0 {
213            self.ary_new_capa(lower)
214        } else {
215            self.ary_new()
216        };
217        let mut buffer = [self.qnil().as_value(); 128];
218        let mut i = 0;
219        for v in iter {
220            buffer[i] = self.into_value(v?);
221            i += 1;
222            if i >= buffer.len() {
223                i = 0;
224                ary.cat(&buffer).unwrap();
225            }
226        }
227        ary.cat(&buffer[..i]).unwrap();
228        Ok(ary)
229    }
230
231    /// Create a new Ruby Array that may only contain elements of type `T`.
232    ///
233    /// On creation this Array is hidden from Ruby, and must be consumed to
234    /// pass it to Ruby (where it reverts to a regular untyped Array). It is
235    /// then inaccessible to Rust.
236    ///
237    /// ```
238    /// use magnus::{rb_assert, Error, Ruby};
239    ///
240    /// fn example(ruby: &Ruby) -> Result<(), Error> {
241    ///     let ary = ruby.typed_ary_new::<f64>();
242    ///     ary.push("1".parse().unwrap())?;
243    ///     ary.push("2.3".parse().unwrap())?;
244    ///     ary.push("4.5".parse().unwrap())?;
245    ///     rb_assert!(ruby, "ary == [1.0, 2.3, 4.5]", ary);
246    ///     // ary has moved and can no longer be used.
247    ///
248    ///     Ok(())
249    /// }
250    /// # Ruby::init(example).unwrap()
251    /// ```
252    pub fn typed_ary_new<T>(&self) -> TypedArray<T> {
253        unsafe {
254            let ary = rb_ary_hidden_new(0);
255            TypedArray(NonZeroValue::new_unchecked(Value::new(ary)), PhantomData)
256        }
257    }
258}
259
260/// A Value pointer to a RArray struct, Ruby's internal representation of an
261/// Array.
262///
263/// See the [`ReprValue`] and [`Object`] traits for additional methods
264/// available on this type. See [`Ruby`](Ruby#rarray) for methods to create an
265/// `RArray`.
266#[derive(Clone, Copy)]
267#[repr(transparent)]
268pub struct RArray(NonZeroValue);
269
270impl RArray {
271    /// Return `Some(RArray)` if `val` is a `RArray`, `None` otherwise.
272    ///
273    /// # Examples
274    ///
275    /// ```
276    /// use magnus::{eval, RArray};
277    /// # let _cleanup = unsafe { magnus::embed::init() };
278    ///
279    /// assert!(RArray::from_value(eval(r#"[true, 0, "example"]"#).unwrap()).is_some());
280    /// assert!(RArray::from_value(eval(r#"{"answer" => 42}"#).unwrap()).is_none());
281    /// assert!(RArray::from_value(eval(r"nil").unwrap()).is_none());
282    /// ```
283    #[inline]
284    pub fn from_value(val: Value) -> Option<Self> {
285        unsafe {
286            (val.rb_type() == ruby_value_type::RUBY_T_ARRAY)
287                .then(|| Self(NonZeroValue::new_unchecked(val)))
288        }
289    }
290
291    #[inline]
292    pub(crate) unsafe fn from_rb_value_unchecked(val: VALUE) -> Self {
293        Self(NonZeroValue::new_unchecked(Value::new(val)))
294    }
295
296    /// Create a new empty `RArray`.
297    ///
298    /// # Panics
299    ///
300    /// Panics if called from a non-Ruby thread. See [`Ruby::ary_new`] for the
301    /// non-panicking version.
302    ///
303    /// # Examples
304    ///
305    /// ```
306    /// # #![allow(deprecated)]
307    /// use magnus::RArray;
308    /// # let _cleanup = unsafe { magnus::embed::init() };
309    ///
310    /// let ary = RArray::new();
311    /// assert!(ary.is_empty());
312    /// ```
313    #[cfg_attr(
314        not(feature = "old-api"),
315        deprecated(note = "please use `Ruby::ary_new` instead")
316    )]
317    #[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
318    #[inline]
319    pub fn new() -> Self {
320        get_ruby!().ary_new()
321    }
322
323    /// Create a new empty `RArray` with capacity for `n` elements
324    /// pre-allocated.
325    ///
326    /// # Panics
327    ///
328    /// Panics if called from a non-Ruby thread. See [`Ruby::ary_new_capa`] for
329    /// the non-panicking version.
330    ///
331    /// # Examples
332    ///
333    /// ```
334    /// # #![allow(deprecated)]
335    /// use magnus::RArray;
336    /// # let _cleanup = unsafe { magnus::embed::init() };
337    ///
338    /// let ary = RArray::with_capacity(16);
339    /// assert!(ary.is_empty());
340    /// ```
341    #[cfg_attr(
342        not(feature = "old-api"),
343        deprecated(note = "please use `Ruby::ary_new_capa` instead")
344    )]
345    #[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
346    #[inline]
347    pub fn with_capacity(n: usize) -> Self {
348        get_ruby!().ary_new_capa(n)
349    }
350
351    /// Convert or wrap a Ruby [`Value`] to a `RArray`.
352    ///
353    /// If `val` responds to `#to_ary` calls that and passes on the returned
354    /// array, otherwise returns a single element array containing `val`.
355    ///
356    /// # Examples
357    ///
358    /// ```
359    /// use magnus::{prelude::*, rb_assert, Error, RArray, Ruby};
360    ///
361    /// fn example(ruby: &Ruby) -> Result<(), Error> {
362    ///     let ary = RArray::to_ary(ruby.integer_from_i64(1).as_value())?;
363    ///     rb_assert!(ruby, "[1] == ary", ary);
364    ///
365    ///     let ary = RArray::to_ary(ruby.ary_from_vec(vec![1, 2, 3]).as_value())?;
366    ///     rb_assert!(ruby, "[1, 2, 3] == ary", ary);
367    ///
368    ///     Ok(())
369    /// }
370    /// # Ruby::init(example).unwrap()
371    /// ```
372    ///
373    /// This can fail in the case of a misbehaving `#to_ary` method:
374    ///
375    /// ```
376    /// use magnus::{Error, RArray, Ruby};
377    ///
378    /// fn example(ruby: &Ruby) -> Result<(), Error> {
379    ///     let val = ruby.eval(
380    ///         r#"
381    ///             o = Object.new
382    ///             def o.to_ary
383    ///               "not an array"
384    ///             end
385    ///             o
386    ///         "#,
387    ///     )?;
388    ///     assert!(RArray::to_ary(val).is_err());
389    ///
390    ///     Ok(())
391    /// }
392    /// # Ruby::init(example).unwrap()
393    /// ```
394    pub fn to_ary(val: Value) -> Result<Self, Error> {
395        protect(|| unsafe { Self::from_rb_value_unchecked(rb_ary_to_ary(val.as_rb_value())) })
396    }
397
398    /// Iterates though `self` and checks each element is convertable to a `T`.
399    ///
400    /// Returns a typed copy of `self`. Mutating the returned copy will not
401    /// mutate `self`.
402    ///
403    /// This makes most sense when `T` is a Ruby type, although that is not
404    /// enforced. If `T` is a Rust type then see [`RArray::to_vec`] for an
405    /// alternative.
406    ///
407    /// # Examples
408    ///
409    /// ```
410    /// use magnus::{function, prelude::*, typed_data, Error, RArray, Ruby};
411    ///
412    /// #[magnus::wrap(class = "Point")]
413    /// struct Point {
414    ///     x: isize,
415    ///     y: isize,
416    /// }
417    ///
418    /// impl Point {
419    ///     fn new(x: isize, y: isize) -> Self {
420    ///         Self { x, y }
421    ///     }
422    /// }
423    ///
424    /// fn example(ruby: &Ruby) -> Result<(), Error> {
425    ///     let point_class = ruby.define_class("Point", ruby.class_object())?;
426    ///     point_class.define_singleton_method("new", function!(Point::new, 2))?;
427    ///
428    ///     let ary: RArray = ruby.eval(
429    ///         r#"
430    ///           [
431    ///             Point.new(1, 2),
432    ///             Point.new(3, 4),
433    ///             Point.new(5, 6),
434    ///           ]
435    ///         "#,
436    ///     )?;
437    ///
438    ///     let typed = ary.typecheck::<typed_data::Obj<Point>>()?;
439    ///     let point = typed.pop()?;
440    ///     assert_eq!(point.x, 5);
441    ///     assert_eq!(point.y, 6);
442    ///
443    ///     Ok(())
444    /// }
445    /// # Ruby::init(example).unwrap();
446    /// # let _ = Point { x: 1, y: 2 }.x + Point { x: 3, y: 4 }.y;
447    /// ```
448    pub fn typecheck<T>(self) -> Result<TypedArray<T>, Error>
449    where
450        T: TryConvert,
451    {
452        for r in self {
453            T::try_convert(r)?;
454        }
455        unsafe {
456            let ary = rb_ary_hidden_new(0);
457            rb_ary_replace(ary, self.as_rb_value());
458            Ok(TypedArray(
459                NonZeroValue::new_unchecked(Value::new(ary)),
460                PhantomData,
461            ))
462        }
463    }
464
465    /// Create a new `RArray` that is a duplicate of `self`.
466    ///
467    /// The new array is only a shallow clone.
468    ///
469    /// # Examples
470    ///
471    /// ```
472    /// use magnus::{rb_assert, Error, Ruby};
473    ///
474    /// fn example(ruby: &Ruby) -> Result<(), Error> {
475    ///     let a = ruby.ary_from_vec(vec![1, 2, 3]);
476    ///     let b = a.dup();
477    ///     rb_assert!(ruby, "a == b", a, b);
478    ///     a.push(4)?;
479    ///     b.push(5)?;
480    ///     rb_assert!(ruby, "a == [1, 2, 3, 4]", a);
481    ///     rb_assert!(ruby, "b == [1, 2, 3, 5]", b);
482    ///
483    ///     Ok(())
484    /// }
485    /// # Ruby::init(example).unwrap()
486    /// ```
487    pub fn dup(self) -> Self {
488        // rb_ary_subseq does a cheap copy-on-write
489        unsafe { Self::from_rb_value_unchecked(rb_ary_subseq(self.as_rb_value(), 0, c_long::MAX)) }
490    }
491
492    /// Return the number of entries in `self` as a Rust [`usize`].
493    ///
494    /// # Examples
495    ///
496    /// ```
497    /// use magnus::{Error, RArray, Ruby};
498    ///
499    /// fn example(ruby: &Ruby) -> Result<(), Error> {
500    ///     let ary = ruby.ary_new();
501    ///     assert_eq!(ary.len(), 0);
502    ///
503    ///     let ary: RArray = ruby.eval("[:a, :b, :c]")?;
504    ///     assert_eq!(ary.len(), 3);
505    ///
506    ///     Ok(())
507    /// }
508    /// # Ruby::init(example).unwrap()
509    /// ```
510    pub fn len(self) -> usize {
511        debug_assert_value!(self);
512        unsafe { RARRAY_LEN(self.as_rb_value()) as _ }
513    }
514
515    /// Return whether self contains any entries or not.
516    ///
517    /// # Examples
518    ///
519    /// ```
520    /// use magnus::{Error, Ruby};
521    ///
522    /// fn example(ruby: &Ruby) -> Result<(), Error> {
523    ///     let ary = ruby.ary_new();
524    ///     assert!(ary.is_empty());
525    ///
526    ///     ary.push("foo")?;
527    ///     assert!(!ary.is_empty());
528    ///
529    ///     Ok(())
530    /// }
531    /// # Ruby::init(example).unwrap()
532    /// ```
533    pub fn is_empty(self) -> bool {
534        self.len() == 0
535    }
536
537    /// Returns `true` if `val` is in `self`, `false` otherwise.
538    ///
539    /// # Examples
540    ///
541    /// ```
542    /// use magnus::{Error, RArray, Ruby};
543    ///
544    /// fn example(ruby: &Ruby) -> Result<(), Error> {
545    ///     let ary: RArray = ruby.eval(r#"[:foo, "bar", 2]"#)?;
546    ///     assert!(ary.includes(ruby.to_symbol("foo")));
547    ///     assert!(ary.includes("bar"));
548    ///     assert!(ary.includes(2));
549    ///     // 2.0 == 2 in Ruby
550    ///     assert!(ary.includes(2.0));
551    ///     assert!(!ary.includes("foo"));
552    ///     assert!(!ary.includes(ruby.qnil()));
553    ///
554    ///     Ok(())
555    /// }
556    /// # Ruby::init(example).unwrap()
557    /// ```
558    pub fn includes<T>(self, val: T) -> bool
559    where
560        T: IntoValue,
561    {
562        let val = Ruby::get_with(self).into_value(val);
563        unsafe { Value::new(rb_ary_includes(self.as_rb_value(), val.as_rb_value())).to_bool() }
564    }
565
566    /// Concatenate elements from the slice `s` to `self`.
567    ///
568    /// Returns `Err` if `self` is frozen.
569    ///
570    /// # Examples
571    ///
572    /// ```
573    /// use magnus::{prelude::*, rb_assert, Error, Ruby};
574    ///
575    /// fn example(ruby: &Ruby) -> Result<(), Error> {
576    ///     let ary = ruby.ary_new();
577    ///     ary.cat(&[
578    ///         ruby.to_symbol("a").as_value(),
579    ///         ruby.integer_from_i64(1).as_value(),
580    ///         ruby.qnil().as_value(),
581    ///     ])?;
582    ///     rb_assert!(ruby, "ary == [:a, 1, nil]", ary);
583    ///
584    ///     Ok(())
585    /// }
586    /// # Ruby::init(example).unwrap()
587    /// ```
588    ///
589    /// ```
590    /// use magnus::{rb_assert, Error, Ruby};
591    ///
592    /// fn example(ruby: &Ruby) -> Result<(), Error> {
593    ///     let ary = ruby.ary_new();
594    ///     ary.cat(&[
595    ///         ruby.to_symbol("a"),
596    ///         ruby.to_symbol("b"),
597    ///         ruby.to_symbol("c"),
598    ///     ])?;
599    ///     rb_assert!(ruby, "ary == [:a, :b, :c]", ary);
600    ///
601    ///     Ok(())
602    /// }
603    /// # Ruby::init(example).unwrap()
604    /// ```
605    pub fn cat<T>(self, s: &[T]) -> Result<(), Error>
606    where
607        T: ReprValue,
608    {
609        let ptr = s.as_ptr() as *const VALUE;
610        protect(|| unsafe { Value::new(rb_ary_cat(self.as_rb_value(), ptr, s.len() as c_long)) })?;
611        Ok(())
612    }
613
614    /// Concatenate elements from Ruby array `other` to `self`.
615    ///
616    /// Returns `Err` if `self` is frozen.
617    ///
618    /// # Examples
619    ///
620    /// ```
621    /// use magnus::{rb_assert, Error, Ruby};
622    ///
623    /// fn example(ruby: &Ruby) -> Result<(), Error> {
624    ///     let a = ruby.ary_from_vec(vec![1, 2, 3]);
625    ///     let b = ruby.ary_from_vec(vec!["a", "b", "c"]);
626    ///     a.concat(b)?;
627    ///     rb_assert!(ruby, r#"a == [1, 2, 3, "a", "b", "c"]"#, a);
628    ///     rb_assert!(ruby, r#"b == ["a", "b", "c"]"#, b);
629    ///
630    ///     Ok(())
631    /// }
632    /// # Ruby::init(example).unwrap()
633    /// ```
634    pub fn concat(self, other: Self) -> Result<(), Error> {
635        protect(|| unsafe { Value::new(rb_ary_concat(self.as_rb_value(), other.as_rb_value())) })?;
636        Ok(())
637    }
638
639    /// Create a new `RArray` containing the both the elements in `self` and
640    /// `other`.
641    ///
642    /// # Examples
643    ///
644    /// ```
645    /// use magnus::{rb_assert, Error, Ruby};
646    ///
647    /// fn example(ruby: &Ruby) -> Result<(), Error> {
648    ///     let a = ruby.ary_from_vec(vec![1, 2, 3]);
649    ///     let b = ruby.ary_from_vec(vec!["a", "b", "c"]);
650    ///     let c = a.plus(b);
651    ///     rb_assert!(ruby, r#"c == [1, 2, 3, "a", "b", "c"]"#, c);
652    ///     rb_assert!(ruby, r#"a == [1, 2, 3]"#, a);
653    ///     rb_assert!(ruby, r#"b == ["a", "b", "c"]"#, b);
654    ///
655    ///     Ok(())
656    /// }
657    /// # Ruby::init(example).unwrap()
658    /// ```
659    pub fn plus(self, other: Self) -> Self {
660        unsafe {
661            Self::from_rb_value_unchecked(rb_ary_plus(self.as_rb_value(), other.as_rb_value()))
662        }
663    }
664
665    /// Create a new `RArray` containing the elements in `slice`.
666    ///
667    /// # Panics
668    ///
669    /// Panics if called from a non-Ruby thread. See
670    /// [`Ruby::ary_new_from_values`] for the non-panicking version.
671    ///
672    /// # Examples
673    ///
674    /// ```
675    /// # #![allow(deprecated)]
676    /// use magnus::{prelude::*, rb_assert, value::qnil, Integer, RArray, Symbol};
677    /// # let _cleanup = unsafe { magnus::embed::init() };
678    ///
679    /// let ary = RArray::from_slice(&[
680    ///     Symbol::new("a").as_value(),
681    ///     Integer::from_i64(1).as_value(),
682    ///     qnil().as_value(),
683    /// ]);
684    /// rb_assert!("ary == [:a, 1, nil]", ary);
685    /// ```
686    ///
687    /// ```
688    /// # #![allow(deprecated)]
689    /// use magnus::{rb_assert, RArray, Symbol};
690    /// # let _cleanup = unsafe { magnus::embed::init() };
691    ///
692    /// let ary = RArray::from_slice(&[Symbol::new("a"), Symbol::new("b"), Symbol::new("c")]);
693    /// rb_assert!("ary == [:a, :b, :c]", ary);
694    /// ```
695    #[cfg_attr(
696        not(feature = "old-api"),
697        deprecated(note = "please use `Ruby::ary_new_from_values` instead")
698    )]
699    #[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
700    #[inline]
701    pub fn from_slice<T>(slice: &[T]) -> Self
702    where
703        T: ReprValue,
704    {
705        get_ruby!().ary_new_from_values(slice)
706    }
707
708    /// Add `item` to the end of `self`.
709    ///
710    /// Returns `Err` if `self` is frozen.
711    ///
712    /// # Examples
713    ///
714    /// ```
715    /// use magnus::{rb_assert, Error, Ruby};
716    ///
717    /// fn example(ruby: &Ruby) -> Result<(), Error> {
718    ///     let ary = ruby.ary_new();
719    ///     ary.push(ruby.to_symbol("a"))?;
720    ///     ary.push(1)?;
721    ///     ary.push(())?;
722    ///     rb_assert!(ruby, "ary == [:a, 1, nil]", ary);
723    ///
724    ///     Ok(())
725    /// }
726    /// # Ruby::init(example).unwrap()
727    /// ```
728    pub fn push<T>(self, item: T) -> Result<(), Error>
729    where
730        T: IntoValue,
731    {
732        let item = Ruby::get_with(self).into_value(item);
733        protect(|| unsafe { Value::new(rb_ary_push(self.as_rb_value(), item.as_rb_value())) })?;
734        Ok(())
735    }
736
737    /// Remove and return the last element of `self`, converting it to a `T`.
738    ///
739    /// Errors if `self` is frozen or if the conversion fails.
740    ///
741    /// # Examples
742    ///
743    /// ```
744    /// use magnus::{Error, RArray, Ruby};
745    ///
746    /// fn example(ruby: &Ruby) -> Result<(), Error> {
747    ///     let ary: RArray = ruby.eval("[1, 2, 3]")?;
748    ///     assert_eq!(ary.pop::<i64>()?, 3);
749    ///     assert_eq!(ary.pop::<i64>()?, 2);
750    ///     assert_eq!(ary.pop::<i64>()?, 1);
751    ///     assert!(ary.pop::<i64>().is_err());
752    ///
753    ///     Ok(())
754    /// }
755    /// # Ruby::init(example).unwrap()
756    /// ```
757    ///
758    /// ```
759    /// use magnus::{Error, RArray, Ruby};
760    ///
761    /// fn example(ruby: &Ruby) -> Result<(), Error> {
762    ///     let ary: RArray = ruby.eval("[1, 2, 3]")?;
763    ///     assert_eq!(ary.pop::<Option<i64>>()?, Some(3));
764    ///     assert_eq!(ary.pop::<Option<i64>>()?, Some(2));
765    ///     assert_eq!(ary.pop::<Option<i64>>()?, Some(1));
766    ///     assert_eq!(ary.pop::<Option<i64>>()?, None);
767    ///
768    ///     Ok(())
769    /// }
770    /// # Ruby::init(example).unwrap()
771    /// ```
772    pub fn pop<T>(self) -> Result<T, Error>
773    where
774        T: TryConvert,
775    {
776        protect(|| unsafe { Value::new(rb_ary_pop(self.as_rb_value())) })
777            .and_then(TryConvert::try_convert)
778    }
779
780    /// Add `item` to the beginning of `self`.
781    ///
782    /// Returns `Err` if `self` is frozen.
783    ///
784    /// # Examples
785    ///
786    /// ```
787    /// use magnus::{rb_assert, Error, Ruby};
788    ///
789    /// fn example(ruby: &Ruby) -> Result<(), Error> {
790    ///     let ary = ruby.ary_new();
791    ///     ary.unshift(ruby.to_symbol("a"))?;
792    ///     ary.unshift(1)?;
793    ///     ary.unshift(())?;
794    ///     rb_assert!(ruby, "ary == [nil, 1, :a]", ary);
795    ///
796    ///     Ok(())
797    /// }
798    /// # Ruby::init(example).unwrap()
799    /// ```
800    pub fn unshift<T>(self, item: T) -> Result<(), Error>
801    where
802        T: IntoValue,
803    {
804        let item = Ruby::get_with(self).into_value(item);
805        protect(|| unsafe { Value::new(rb_ary_unshift(self.as_rb_value(), item.as_rb_value())) })?;
806        Ok(())
807    }
808
809    /// Remove and return the first element of `self`, converting it to a `T`.
810    ///
811    /// Errors if `self` is frozen or if the conversion fails.
812    ///
813    /// # Examples
814    ///
815    /// ```
816    /// use magnus::{Error, RArray, Ruby};
817    ///
818    /// fn example(ruby: &Ruby) -> Result<(), Error> {
819    ///     let ary: RArray = ruby.eval("[1, 2, 3]")?;
820    ///     assert_eq!(ary.shift::<i64>()?, 1);
821    ///     assert_eq!(ary.shift::<i64>()?, 2);
822    ///     assert_eq!(ary.shift::<i64>()?, 3);
823    ///     assert!(ary.shift::<i64>().is_err());
824    ///
825    ///     Ok(())
826    /// }
827    /// # Ruby::init(example).unwrap()
828    /// ```
829    ///
830    /// ```
831    /// use magnus::{Error, RArray, Ruby};
832    ///
833    /// fn example(ruby: &Ruby) -> Result<(), Error> {
834    ///     let ary: RArray = ruby.eval("[1, 2, 3]")?;
835    ///     assert_eq!(ary.shift::<Option<i64>>()?, Some(1));
836    ///     assert_eq!(ary.shift::<Option<i64>>()?, Some(2));
837    ///     assert_eq!(ary.shift::<Option<i64>>()?, Some(3));
838    ///     assert_eq!(ary.shift::<Option<i64>>()?, None);
839    ///
840    ///     Ok(())
841    /// }
842    /// # Ruby::init(example).unwrap()
843    /// ```
844    pub fn shift<T>(self) -> Result<T, Error>
845    where
846        T: TryConvert,
847    {
848        protect(|| unsafe { Value::new(rb_ary_shift(self.as_rb_value())) })
849            .and_then(TryConvert::try_convert)
850    }
851
852    /// Remove all elements from `self` that match `item`'s `==` method.
853    ///
854    /// Returns `Err` if `self` is frozen.
855    ///
856    /// # Examples
857    ///
858    /// ```
859    /// use magnus::{rb_assert, Error, Ruby};
860    ///
861    /// fn example(ruby: &Ruby) -> Result<(), Error> {
862    ///     let ary = ruby.ary_from_vec(vec![1, 1, 2, 3]);
863    ///     ary.delete(1)?;
864    ///     rb_assert!(ruby, "ary == [2, 3]", ary);
865    ///
866    ///     Ok(())
867    /// }
868    /// # Ruby::init(example).unwrap()
869    /// ```
870    pub fn delete<T>(self, item: T) -> Result<(), Error>
871    where
872        T: IntoValue,
873    {
874        let item = Ruby::get_with(self).into_value(item);
875        protect(|| unsafe { Value::new(rb_ary_delete(self.as_rb_value(), item.as_rb_value())) })?;
876        Ok(())
877    }
878
879    /// Remove and return the element of `self` at `index`, converting it to a
880    /// `T`.
881    ///
882    /// `index` may be negative, in which case it counts backward from the end
883    /// of the array.
884    ///
885    /// Returns `Err` if `self` is frozen or if the conversion fails.
886    ///
887    /// The returned element will be Ruby's `nil` when `index` is out of bounds
888    /// this makes it impossible to distingush between out of bounds and
889    /// removing `nil` without an additional length check.
890    ///
891    /// # Examples
892    ///
893    /// ```
894    /// use magnus::{rb_assert, Error, Ruby};
895    ///
896    /// fn example(ruby: &Ruby) -> Result<(), Error> {
897    ///     let ary = ruby.ary_from_vec(vec!["a", "b", "c"]);
898    ///     let removed: Option<String> = ary.delete_at(1)?;
899    ///     assert_eq!(removed, Some(String::from("b")));
900    ///     rb_assert!(ruby, r#"ary == ["a", "c"]"#, ary);
901    ///
902    ///     Ok(())
903    /// }
904    /// # Ruby::init(example).unwrap()
905    /// ```
906    pub fn delete_at<T>(self, index: isize) -> Result<T, Error>
907    where
908        T: TryConvert,
909    {
910        protect(|| unsafe { Value::new(rb_ary_delete_at(self.as_rb_value(), index as c_long)) })
911            .and_then(TryConvert::try_convert)
912    }
913
914    /// Remove all elements from `self`
915    ///
916    /// Returns `Err` if `self` is frozen.
917    ///
918    /// # Examples
919    ///
920    /// ```
921    /// use magnus::{Error, Ruby};
922    ///
923    /// fn example(ruby: &Ruby) -> Result<(), Error> {
924    ///     let ary = ruby.ary_from_vec::<i64>(vec![1, 2, 3]);
925    ///     assert!(!ary.is_empty());
926    ///     ary.clear()?;
927    ///     assert!(ary.is_empty());
928    ///
929    ///     Ok(())
930    /// }
931    /// # Ruby::init(example).unwrap()
932    /// ```
933    pub fn clear(self) -> Result<(), Error> {
934        protect(|| unsafe { Value::new(rb_ary_clear(self.as_rb_value())) })?;
935        Ok(())
936    }
937
938    /// Expand or shrink the length of `self`.
939    ///
940    /// When increasing the length of the array empty positions will be filled
941    /// with `nil`.
942    ///
943    /// Returns `Err` if `self` is frozen.
944    ///
945    /// # Examples
946    ///
947    /// ```
948    /// use magnus::{rb_assert, Error, Ruby};
949    ///
950    /// fn example(ruby: &Ruby) -> Result<(), Error> {
951    ///     let ary = ruby.ary_from_vec::<i64>(vec![1, 2, 3]);
952    ///     ary.resize(5)?;
953    ///     rb_assert!(ruby, "ary == [1, 2, 3, nil, nil]", ary);
954    ///     ary.resize(2)?;
955    ///     rb_assert!(ruby, "ary == [1, 2]", ary);
956    ///
957    ///     Ok(())
958    /// }
959    /// # Ruby::init(example).unwrap()
960    /// ```
961    pub fn resize(self, len: usize) -> Result<(), Error> {
962        protect(|| unsafe { Value::new(rb_ary_resize(self.as_rb_value(), len as c_long)) })?;
963        Ok(())
964    }
965
966    /// Reverses the order of `self` in place.
967    ///
968    /// Returns `Err` if `self` is frozen.
969    ///
970    /// # Examples
971    ///
972    /// ```
973    /// use magnus::{rb_assert, Error, Ruby};
974    ///
975    /// fn example(ruby: &Ruby) -> Result<(), Error> {
976    ///     let ary = ruby.ary_from_vec::<i64>(vec![1, 2, 3]);
977    ///     ary.reverse()?;
978    ///     rb_assert!(ruby, "ary == [3, 2, 1]", ary);
979    ///
980    ///     Ok(())
981    /// }
982    /// # Ruby::init(example).unwrap()
983    /// ```
984    pub fn reverse(self) -> Result<(), Error> {
985        protect(|| unsafe { Value::new(rb_ary_reverse(self.as_rb_value())) })?;
986        Ok(())
987    }
988
989    /// Rotates the elements of `self` in place by `rot` positions.
990    ///
991    /// If `rot` is positive elements are rotated to the left, if negative,
992    /// to the right.
993    ///
994    /// Returns `Err` if `self` is frozen.
995    ///
996    /// # Examples
997    ///
998    /// ```
999    /// use magnus::{rb_assert, Error, Ruby};
1000    ///
1001    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1002    ///     let ary = ruby.ary_from_vec::<i64>(vec![1, 2, 3, 4, 5, 6, 7]);
1003    ///     ary.rotate(3)?;
1004    ///     rb_assert!(ruby, "ary == [4, 5, 6, 7, 1, 2, 3]", ary);
1005    ///
1006    ///     Ok(())
1007    /// }
1008    /// # Ruby::init(example).unwrap()
1009    /// ```
1010    ///
1011    /// ```
1012    /// use magnus::{rb_assert, Error, Ruby};
1013    ///
1014    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1015    ///     let ary = ruby.ary_from_vec::<i64>(vec![1, 2, 3, 4, 5, 6, 7]);
1016    ///     ary.rotate(-3)?;
1017    ///     rb_assert!(ruby, "ary == [5, 6, 7, 1, 2, 3, 4]", ary);
1018    ///
1019    ///     Ok(())
1020    /// }
1021    /// # Ruby::init(example).unwrap()
1022    /// ```
1023    pub fn rotate(self, rot: isize) -> Result<(), Error> {
1024        protect(|| unsafe { Value::new(rb_ary_rotate(self.as_rb_value(), rot as c_long)) })?;
1025        Ok(())
1026    }
1027
1028    /// Storts the elements of `self` in place using Ruby's `<=>` operator.
1029    ///
1030    /// Returns `Err` if `self` is frozen.
1031    ///
1032    /// # Examples
1033    ///
1034    /// ```
1035    /// use magnus::{rb_assert, Error, Ruby};
1036    ///
1037    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1038    ///     let ary = ruby.ary_from_vec::<i64>(vec![2, 1, 3]);
1039    ///     ary.sort()?;
1040    ///     rb_assert!(ruby, "ary == [1, 2, 3]", ary);
1041    ///
1042    ///     Ok(())
1043    /// }
1044    /// # Ruby::init(example).unwrap()
1045    /// ```
1046    pub fn sort(self) -> Result<(), Error> {
1047        protect(|| unsafe { Value::new(rb_ary_sort_bang(self.as_rb_value())) })?;
1048        Ok(())
1049    }
1050
1051    /// Create a new `RArray` from a Rust vector.
1052    ///
1053    /// # Panics
1054    ///
1055    /// Panics if called from a non-Ruby thread. See [`Ruby::ary_from_vec`] for
1056    /// the non-panicking version.
1057    ///
1058    /// # Examples
1059    ///
1060    /// ```
1061    /// # #![allow(deprecated)]
1062    /// use magnus::{rb_assert, RArray};
1063    /// # let _cleanup = unsafe { magnus::embed::init() };
1064    ///
1065    /// let ary = RArray::from_vec(vec![1, 2, 3]);
1066    /// rb_assert!("ary == [1, 2, 3]", ary);
1067    /// ```
1068    #[cfg_attr(
1069        not(feature = "old-api"),
1070        deprecated(note = "please use `Ruby::ary_from_vec` instead")
1071    )]
1072    #[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
1073    #[inline]
1074    pub fn from_vec<T>(vec: Vec<T>) -> Self
1075    where
1076        T: IntoValueFromNative,
1077    {
1078        get_ruby!().ary_from_vec(vec)
1079    }
1080
1081    /// Return `self` as a slice of [`Value`]s.
1082    ///
1083    /// # Safety
1084    ///
1085    /// This is directly viewing memory owned and managed by Ruby. Ruby may
1086    /// modify or free the memory backing the returned slice, the caller must
1087    /// ensure this does not happen.
1088    ///
1089    /// Ruby must not be allowed to garbage collect or modify `self` while a
1090    /// reference to the slice is held.
1091    ///
1092    /// # Examples
1093    ///
1094    /// ```
1095    /// use magnus::{rb_assert, Error, RArray, Ruby};
1096    ///
1097    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1098    ///     let ary: RArray = ruby.eval("[1, 2, 3, 4, 5]")?;
1099    ///     // must not call any Ruby api that may modify ary while we have a
1100    ///     // reference to the return value of ::from_slice()
1101    ///     unsafe {
1102    ///         let middle = ruby.ary_new_from_values(&ary.as_slice()[1..4]);
1103    ///         rb_assert!(ruby, "middle == [2, 3, 4]", middle);
1104    ///     }
1105    ///
1106    ///     Ok(())
1107    /// }
1108    /// # Ruby::init(example).unwrap()
1109    /// ```
1110    pub unsafe fn as_slice(&self) -> &[Value] {
1111        self.as_slice_unconstrained()
1112    }
1113
1114    pub(crate) unsafe fn as_slice_unconstrained<'a>(self) -> &'a [Value] {
1115        debug_assert_value!(self);
1116        slice::from_raw_parts(
1117            RARRAY_CONST_PTR(self.as_rb_value()) as *const Value,
1118            RARRAY_LEN(self.as_rb_value()) as usize,
1119        )
1120    }
1121
1122    /// Convert `self` to a Rust vector of `T`s. Errors if converting any
1123    /// element in the array fails.
1124    ///
1125    /// This will only convert to a map of 'owned' Rust native types. The types
1126    /// representing Ruby objects can not be stored in a heap-allocated
1127    /// datastructure like a [`Vec`] as they are hidden from the mark phase
1128    /// of Ruby's garbage collector, and thus may be prematurely garbage
1129    /// collected in the following sweep phase.
1130    ///
1131    /// # Examples
1132    ///
1133    /// ```
1134    /// use magnus::{Error, RArray, Ruby};
1135    ///
1136    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1137    ///     let ary: RArray = ruby.eval("[1, 2, 3]")?;
1138    ///     assert_eq!(ary.to_vec::<i64>()?, vec![1, 2, 3]);
1139    ///
1140    ///     Ok(())
1141    /// }
1142    /// # Ruby::init(example).unwrap()
1143    /// ```
1144    pub fn to_vec<T>(self) -> Result<Vec<T>, Error>
1145    where
1146        T: TryConvertOwned,
1147    {
1148        unsafe { self.as_slice().iter().map(|v| T::try_convert(*v)).collect() }
1149    }
1150
1151    /// Convert `self` to a Rust array of [`Value`]s, of length `N`.
1152    ///
1153    /// Errors if the Ruby array is not of length `N`.
1154    ///
1155    /// # Examples
1156    ///
1157    /// ```
1158    /// use magnus::{Error, RArray, Ruby};
1159    ///
1160    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1161    ///     let ary: RArray = ruby.eval("[1, 2, 3]")?;
1162    ///     assert!(ary.to_value_array::<3>().is_ok());
1163    ///     assert!(ary.to_value_array::<2>().is_err());
1164    ///     assert!(ary.to_value_array::<4>().is_err());
1165    ///
1166    ///     Ok(())
1167    /// }
1168    /// # Ruby::init(example).unwrap()
1169    /// ```
1170    pub fn to_value_array<const N: usize>(self) -> Result<[Value; N], Error> {
1171        unsafe {
1172            self.as_slice().try_into().map_err(|_| {
1173                Error::new(
1174                    Ruby::get_with(self).exception_type_error(),
1175                    format!("expected Array of length {}", N),
1176                )
1177            })
1178        }
1179    }
1180
1181    /// Convert `self` to a Rust array of `T`s, of length `N`.
1182    ///
1183    /// Errors if converting any element in the array fails, or if the Ruby
1184    /// array is not of length `N`.
1185    ///
1186    /// # Examples
1187    ///
1188    /// ```
1189    /// use magnus::{Error, RArray, Ruby};
1190    ///
1191    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1192    ///     let ary: RArray = ruby.eval("[1, 2, 3]")?;
1193    ///     assert_eq!(ary.to_array::<i64, 3>()?, [1, 2, 3]);
1194    ///     assert!(ary.to_array::<i64, 2>().is_err());
1195    ///     assert!(ary.to_array::<i64, 4>().is_err());
1196    ///
1197    ///     Ok(())
1198    /// }
1199    /// # Ruby::init(example).unwrap()
1200    /// ```
1201    pub fn to_array<T, const N: usize>(self) -> Result<[T; N], Error>
1202    where
1203        T: TryConvert,
1204    {
1205        unsafe {
1206            let slice = self.as_slice();
1207            if slice.len() != N {
1208                return Err(Error::new(
1209                    Ruby::get_with(self).exception_type_error(),
1210                    format!("expected Array of length {}", N),
1211                ));
1212            }
1213            // one day might be able to collect direct into an array, but for
1214            // now need to go via Vec
1215            slice
1216                .iter()
1217                .copied()
1218                .map(TryConvert::try_convert)
1219                .collect::<Result<Vec<T>, Error>>()
1220                .map(|v| v.try_into().ok().unwrap())
1221        }
1222    }
1223
1224    /// Stringify the contents of `self` and join the sequence with `sep`.
1225    ///
1226    /// # Examples
1227    ///
1228    /// ```
1229    /// use magnus::{prelude::*, Error, Ruby};
1230    ///
1231    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1232    ///     let ary = ruby.ary_new_from_values(&[
1233    ///         ruby.to_symbol("a").as_value(),
1234    ///         ruby.integer_from_i64(1).as_value(),
1235    ///         ruby.qnil().as_value(),
1236    ///     ]);
1237    ///     assert_eq!(ary.join(", ").unwrap().to_string().unwrap(), "a, 1, ");
1238    ///
1239    ///     Ok(())
1240    /// }
1241    /// # Ruby::init(example).unwrap()
1242    /// ```
1243    pub fn join<T>(self, sep: T) -> Result<RString, Error>
1244    where
1245        T: IntoRString,
1246    {
1247        let sep = sep.into_r_string_with(&Ruby::get_with(self));
1248        protect(|| unsafe {
1249            RString::from_rb_value_unchecked(rb_ary_join(self.as_rb_value(), sep.as_rb_value()))
1250        })
1251    }
1252
1253    /// Return the element at `offset`, converting it to a `T`.
1254    ///
1255    /// Errors if the conversion fails.
1256    ///
1257    /// An offset out of range will return `nil`.
1258    ///
1259    /// # Examples
1260    ///
1261    /// ```
1262    /// use magnus::{Error, RArray, Ruby};
1263    ///
1264    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1265    ///     let ary: RArray = ruby.eval(r#"["a", "b", "c"]"#)?;
1266    ///
1267    ///     assert_eq!(ary.entry::<String>(0)?, String::from("a"));
1268    ///     assert_eq!(ary.entry::<char>(0)?, 'a');
1269    ///     assert_eq!(ary.entry::<Option<String>>(0)?, Some(String::from("a")));
1270    ///     assert_eq!(ary.entry::<String>(1)?, String::from("b"));
1271    ///     assert_eq!(ary.entry::<String>(-1)?, String::from("c"));
1272    ///     assert_eq!(ary.entry::<Option<String>>(3)?, None);
1273    ///
1274    ///     assert!(ary.entry::<i64>(0).is_err());
1275    ///     assert!(ary.entry::<String>(3).is_err());
1276    ///
1277    ///     Ok(())
1278    /// }
1279    /// # Ruby::init(example).unwrap()
1280    /// ```
1281    pub fn entry<T>(self, offset: isize) -> Result<T, Error>
1282    where
1283        T: TryConvert,
1284    {
1285        unsafe {
1286            T::try_convert(Value::new(rb_ary_entry(
1287                self.as_rb_value(),
1288                offset as c_long,
1289            )))
1290        }
1291    }
1292
1293    /// Set the element at `offset`.
1294    ///
1295    /// If `offset` is beyond the current size of the array the array will be
1296    /// expanded and padded with `nil`.
1297    ///
1298    /// Returns `Err` if `self` is frozen.
1299    ///
1300    /// # Examples
1301    ///
1302    /// ```
1303    /// use magnus::{rb_assert, Error, Ruby};
1304    ///
1305    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1306    ///     let ary = ruby.ary_new_from_values(&[
1307    ///         ruby.to_symbol("a"),
1308    ///         ruby.to_symbol("b"),
1309    ///         ruby.to_symbol("c"),
1310    ///     ]);
1311    ///     ary.store(0, ruby.to_symbol("d"))?;
1312    ///     ary.store(5, ruby.to_symbol("e"))?;
1313    ///     ary.store(6, ruby.to_symbol("f"))?;
1314    ///     ary.store(-1, ruby.to_symbol("g"))?;
1315    ///     rb_assert!(ruby, "ary == [:d, :b, :c, nil, nil, :e, :g]", ary);
1316    ///
1317    ///     Ok(())
1318    /// }
1319    /// # Ruby::init(example).unwrap()
1320    /// ```
1321    pub fn store<T>(self, offset: isize, val: T) -> Result<(), Error>
1322    where
1323        T: IntoValue,
1324    {
1325        let handle = Ruby::get_with(self);
1326        let val = handle.into_value(val);
1327        protect(|| {
1328            unsafe { rb_ary_store(self.as_rb_value(), offset as c_long, val.as_rb_value()) };
1329            handle.qnil()
1330        })?;
1331        Ok(())
1332    }
1333
1334    /// Returns an [`Enumerator`] over `self`.
1335    ///
1336    /// # Examples
1337    ///
1338    /// ```
1339    /// use magnus::{eval, prelude::*, RArray};
1340    /// # let _cleanup = unsafe { magnus::embed::init() };
1341    ///
1342    /// let mut res = Vec::new();
1343    /// # #[allow(deprecated)]
1344    /// for i in eval::<RArray>("[1, 2, 3]").unwrap().each() {
1345    ///     res.push(i64::try_convert(i.unwrap()).unwrap());
1346    /// }
1347    /// assert_eq!(res, vec![1, 2, 3]);
1348    /// ```
1349    #[deprecated(
1350        since = "0.7.0",
1351        note = "Please use `ary.into_iter()` or `ary.enumeratorize(\"each\", ())` instead."
1352    )]
1353    pub fn each(self) -> Enumerator {
1354        // TODO why doesn't rb_ary_each work?
1355        self.enumeratorize("each", ())
1356    }
1357
1358    /// Returns true if both `self` and `other` share the same backing storage.
1359    ///
1360    /// It is possible for two Ruby Arrays to share the same backing storage,
1361    /// and only when one of them is modified will the copy-on-write cost be
1362    /// paid.
1363    ///
1364    /// Currently, this method will only return `true` if `self` and `other`
1365    /// are of the same length, even though Ruby may continue to use the same
1366    /// backing storage after popping a value from either of the arrays.
1367    ///
1368    /// # Examples
1369    ///
1370    /// ```
1371    /// use magnus::{Error, Ruby};
1372    ///
1373    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1374    ///     let ary = ruby.ary_from_vec((0..256).collect());
1375    ///     let copy = ruby.ary_new();
1376    ///     copy.replace(ary)?;
1377    ///     assert!(ary.is_shared(copy));
1378    ///     assert!(copy.is_shared(ary));
1379    ///     copy.push(11)?;
1380    ///     assert!(!ary.is_shared(copy));
1381    ///     assert!(!copy.is_shared(ary));
1382    ///
1383    ///     Ok(())
1384    /// }
1385    /// # Ruby::init(example).unwrap()
1386    /// ```
1387    pub fn is_shared(self, other: Self) -> bool {
1388        unsafe {
1389            Value::new(rb_ary_shared_with_p(
1390                self.as_rb_value(),
1391                other.as_rb_value(),
1392            ))
1393            .to_bool()
1394        }
1395    }
1396
1397    /// Replace the contents of `self` with `from`.
1398    ///
1399    /// `from` is unmodified, and `self` becomes a copy of `from`. `self`'s
1400    /// former contents are abandoned.
1401    ///
1402    /// This is a very cheap operation, `self` will point at `from`'s backing
1403    /// storage until one is modified, and only then will the copy-on-write
1404    /// cost be paid.
1405    ///
1406    /// Returns `Err` if `self` is frozen.
1407    ///
1408    /// # Examples
1409    ///
1410    /// ```
1411    /// use magnus::{Error, Ruby};
1412    ///
1413    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1414    ///     let ary = ruby.ary_from_vec((0..256).collect());
1415    ///     let copy = ruby.ary_new();
1416    ///     copy.replace(ary)?;
1417    ///     assert!(copy.is_shared(ary));
1418    ///     copy.push(11)?;
1419    ///     assert!(!copy.is_shared(ary));
1420    ///
1421    ///     Ok(())
1422    /// }
1423    /// # Ruby::init(example).unwrap()
1424    /// ```
1425    pub fn replace(self, from: Self) -> Result<(), Error> {
1426        protect(|| unsafe { Value::new(rb_ary_replace(self.as_rb_value(), from.as_rb_value())) })?;
1427        Ok(())
1428    }
1429
1430    /// Create a new array from a subsequence of `self`.
1431    ///
1432    /// This is a very cheap operation, as `self` and the new array will share
1433    /// their backing storage until one is modified.
1434    ///
1435    /// # Examples
1436    ///
1437    /// ```
1438    /// use magnus::{rb_assert, Error, Ruby};
1439    ///
1440    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1441    ///     let ary = ruby.ary_from_vec(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
1442    ///     let a = ary.subseq(0, 5).unwrap();
1443    ///     let b = ary.subseq(5, 5).unwrap();
1444    ///     rb_assert!(ruby, "a == [1, 2, 3, 4, 5]", a);
1445    ///     rb_assert!(ruby, "b == [6, 7, 8, 9, 10]", b);
1446    ///
1447    ///     Ok(())
1448    /// }
1449    /// # Ruby::init(example).unwrap()
1450    /// ```
1451    // TODO maybe take a range instead of offset and length
1452    pub fn subseq(self, offset: usize, length: usize) -> Option<Self> {
1453        unsafe {
1454            let val = Value::new(rb_ary_subseq(
1455                self.as_rb_value(),
1456                offset as c_long,
1457                length as c_long,
1458            ));
1459            (!val.is_nil()).then(|| Self::from_rb_value_unchecked(val.as_rb_value()))
1460        }
1461    }
1462
1463    /// Search `self` as an 'associative array' for `key`.
1464    ///
1465    /// Assumes `self` is an array of arrays, searching from the start of the
1466    /// outer array, returns the first inner array where the first element
1467    /// matches `key`.
1468    ///
1469    /// # Examples
1470    ///
1471    /// ```
1472    /// use magnus::{Error, Ruby};
1473    ///
1474    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1475    ///     let ary = ruby.ary_from_vec(vec![("foo", 1), ("bar", 2), ("baz", 3), ("baz", 4)]);
1476    ///     assert_eq!(
1477    ///         ary.assoc::<_, (String, i64)>("baz")?,
1478    ///         (String::from("baz"), 3)
1479    ///     );
1480    ///     assert_eq!(ary.assoc::<_, Option<(String, i64)>>("quz")?, None);
1481    ///
1482    ///     Ok(())
1483    /// }
1484    /// # Ruby::init(example).unwrap()
1485    /// ```
1486    pub fn assoc<K, T>(self, key: K) -> Result<T, Error>
1487    where
1488        K: IntoValue,
1489        T: TryConvert,
1490    {
1491        let key = Ruby::get_with(self).into_value(key);
1492        protect(|| unsafe { Value::new(rb_ary_assoc(self.as_rb_value(), key.as_rb_value())) })
1493            .and_then(TryConvert::try_convert)
1494    }
1495
1496    /// Search `self` as an 'associative array' for `value`.
1497    ///
1498    /// Assumes `self` is an array of arrays, searching from the start of the
1499    /// outer array, returns the first inner array where the second element
1500    /// matches `value`.
1501    ///
1502    /// # Examples
1503    ///
1504    /// ```
1505    /// use magnus::{Error, Ruby};
1506    ///
1507    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1508    ///     let ary = ruby.ary_from_vec(vec![("foo", 1), ("bar", 2), ("baz", 3), ("qux", 3)]);
1509    ///     assert_eq!(ary.rassoc::<_, (String, i64)>(3)?, (String::from("baz"), 3));
1510    ///     assert_eq!(ary.rassoc::<_, Option<(String, i64)>>(4)?, None);
1511    ///
1512    ///     Ok(())
1513    /// }
1514    /// # Ruby::init(example).unwrap()
1515    /// ```
1516    pub fn rassoc<K, T>(self, value: K) -> Result<T, Error>
1517    where
1518        K: IntoValue,
1519        T: TryConvert,
1520    {
1521        let value = Ruby::get_with(self).into_value(value);
1522        protect(|| unsafe { Value::new(rb_ary_rassoc(self.as_rb_value(), value.as_rb_value())) })
1523            .and_then(TryConvert::try_convert)
1524    }
1525
1526    /// Recursively compares elements of the two arrays using Ruby's `<=>`.
1527    ///
1528    /// Returns `Some(Ordering::Equal)` if `self` and `other` are equal.
1529    /// Returns `Some(Ordering::Less)` if `self` if less than `other`.
1530    /// Returns `Some(Ordering::Greater)` if `self` if greater than `other`.
1531    /// Returns `None` if `self` and `other` are not comparable.
1532    ///
1533    /// # Examples
1534    ///
1535    /// ```
1536    /// use std::cmp::Ordering;
1537    ///
1538    /// use magnus::{Error, Ruby};
1539    ///
1540    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1541    ///     let a = ruby.ary_from_vec(vec![1, 2, 3]);
1542    ///     let b = ruby.ary_from_vec(vec![1, 2, 3]);
1543    ///     assert_eq!(a.cmp(b)?, Some(Ordering::Equal));
1544    ///
1545    ///     let c = ruby.ary_from_vec(vec![1, 2, 0]);
1546    ///     assert_eq!(a.cmp(c)?, Some(Ordering::Greater));
1547    ///
1548    ///     let d = ruby.ary_from_vec(vec![1, 2, 4]);
1549    ///     assert_eq!(a.cmp(d)?, Some(Ordering::Less));
1550    ///
1551    ///     let e = ruby.ary_from_vec(vec![1, 2]);
1552    ///     e.push(())?;
1553    ///     assert_eq!(a.cmp(e)?, None);
1554    ///
1555    ///     Ok(())
1556    /// }
1557    /// # Ruby::init(example).unwrap()
1558    /// ```
1559    ///
1560    /// Note that `std::cmp::Ordering` can be cast to `i{8,16,32,64,size}` to
1561    /// get the Ruby standard `-1`/`0`/`+1` for comparison results.
1562    ///
1563    /// ```
1564    /// assert_eq!(std::cmp::Ordering::Less as i64, -1);
1565    /// assert_eq!(std::cmp::Ordering::Equal as i64, 0);
1566    /// assert_eq!(std::cmp::Ordering::Greater as i64, 1);
1567    /// ```
1568    #[allow(clippy::should_implement_trait)]
1569    pub fn cmp(self, other: Self) -> Result<Option<Ordering>, Error> {
1570        protect(|| unsafe { Value::new(rb_ary_cmp(self.as_rb_value(), other.as_rb_value())) })
1571            .and_then(<Option<i64>>::try_convert)
1572            .map(|opt| opt.map(|i| i.cmp(&0)))
1573    }
1574}
1575
1576impl fmt::Display for RArray {
1577    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1578        write!(f, "{}", unsafe { self.to_s_infallible() })
1579    }
1580}
1581
1582impl fmt::Debug for RArray {
1583    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1584        write!(f, "{}", self.inspect())
1585    }
1586}
1587
1588impl IntoIterator for RArray {
1589    type Item = Value;
1590    type IntoIter = Iter<Value>;
1591
1592    /// Returns an [`Iter`] over a copy of `self`.
1593    ///
1594    /// `self` is copied using a fast copy-on-write optimisation, so if `self`
1595    /// is not modified then `self` and the copy will point to the same backing
1596    /// store and use no extra memory.
1597    ///
1598    /// The copy is skipped if `self` is frozen.
1599    ///
1600    /// # Examples
1601    ///
1602    /// ```
1603    /// use magnus::{Error, Ruby, TryConvert};
1604    ///
1605    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1606    ///     let ary = ruby.ary_new();
1607    ///     ary.push(1)?;
1608    ///     ary.push(2)?;
1609    ///     ary.push(3)?;
1610    ///
1611    ///     let iter = ary.into_iter();
1612    ///
1613    ///     ary.push(4)?;
1614    ///
1615    ///     let res = iter
1616    ///         .map(TryConvert::try_convert)
1617    ///         .collect::<Result<Vec<i64>, Error>>()?;
1618    ///
1619    ///     assert_eq!(res, vec![1, 2, 3]);
1620    ///
1621    ///     Ok(())
1622    /// }
1623    /// # Ruby::init(example).unwrap()
1624    /// ```
1625    fn into_iter(self) -> Self::IntoIter {
1626        let ary = if self.is_frozen() {
1627            self
1628        } else {
1629            let tmp = self.dup();
1630            unsafe { rb_obj_hide(tmp.as_rb_value()) };
1631            tmp
1632        };
1633        Iter::new(ary)
1634    }
1635}
1636
1637impl IntoValue for RArray {
1638    #[inline]
1639    fn into_value_with(self, _: &Ruby) -> Value {
1640        self.0.get()
1641    }
1642}
1643
1644macro_rules! impl_into_value {
1645    ($n:literal) => {
1646        seq!(N in 0..=$n {
1647            impl<#(T~N,)*> IntoValue for (#(T~N,)*)
1648            where
1649                #(T~N: IntoValue,)*
1650            {
1651                fn into_value_with(self, handle: &Ruby) -> Value {
1652                    let ary = [
1653                        #(handle.into_value(self.N),)*
1654                    ];
1655                    handle.ary_new_from_values(&ary).into_value_with(handle)
1656                }
1657            }
1658
1659            unsafe impl<#(T~N,)*> IntoValueFromNative for (#(T~N,)*) where #(T~N: IntoValueFromNative,)* {}
1660        });
1661    }
1662}
1663
1664seq!(N in 0..12 {
1665    impl_into_value!(N);
1666});
1667
1668impl<T> IntoValue for Vec<T>
1669where
1670    T: IntoValueFromNative,
1671{
1672    #[inline]
1673    fn into_value_with(self, handle: &Ruby) -> Value {
1674        handle.ary_from_vec(self).into_value_with(handle)
1675    }
1676}
1677
1678unsafe impl<T> IntoValueFromNative for Vec<T> where T: IntoValueFromNative {}
1679
1680#[cfg(feature = "old-api")]
1681impl<T> FromIterator<T> for RArray
1682where
1683    T: IntoValue,
1684{
1685    /// Creates a Ruby array from an iterator.
1686    ///
1687    /// # Panics
1688    ///
1689    /// Panics if called from a non-Ruby thread. See [`Ruby::ary_from_iter`]
1690    /// for the non-panicking version.
1691    fn from_iter<I>(iter: I) -> Self
1692    where
1693        I: IntoIterator<Item = T>,
1694    {
1695        get_ruby!().ary_from_iter(iter)
1696    }
1697}
1698
1699impl Object for RArray {}
1700
1701unsafe impl private::ReprValue for RArray {}
1702
1703impl ReprValue for RArray {}
1704
1705impl TryConvert for RArray {
1706    fn try_convert(val: Value) -> Result<Self, Error> {
1707        if let Some(v) = Self::from_value(val) {
1708            return Ok(v);
1709        }
1710        unsafe {
1711            protect(|| Value::new(rb_check_array_type(val.as_rb_value()))).and_then(|res| {
1712                Self::from_value(res).ok_or_else(|| {
1713                    Error::new(
1714                        Ruby::get_with(val).exception_type_error(),
1715                        format!("no implicit conversion of {} into Array", val.class()),
1716                    )
1717                })
1718            })
1719        }
1720    }
1721}
1722
1723/// A Ruby Array that may only contain elements of type `T`.
1724///
1725/// On creation this Array is hidden from Ruby, and must be consumed to
1726/// pass it to Ruby (where it reverts to a regular untyped Array). It is
1727/// then inaccessible to Rust.
1728///
1729/// See [`Ruby::typed_ary_new`] or [`RArray::typecheck`] for how to get a value
1730/// of `TypedArray`.
1731//
1732// Very deliberately not Copy or Clone so that values of this type are consumed
1733// when TypedArray::to_array is called, so you can either have typed access
1734// from Rust *or* expose it to Ruby.
1735#[repr(transparent)]
1736pub struct TypedArray<T>(NonZeroValue, PhantomData<T>);
1737
1738macro_rules! proxy {
1739    ($method:ident($($arg:ident: $typ:ty),*) -> $ret:ty) => {
1740        #[doc=concat!("See [`RArray::", stringify!($method), "`].")]
1741        pub fn $method(&self, $($arg: $typ),*) -> $ret {
1742            unsafe { RArray::from_value_unchecked(self.0.get()) }.$method($($arg),*)
1743        }
1744    };
1745}
1746
1747impl<T> TypedArray<T> {
1748    /// Consume `self`, returning it as an [`RArray`].
1749    pub fn to_r_array(self) -> RArray {
1750        let val = self.0.get();
1751        let ruby = Ruby::get_with(val);
1752        unsafe {
1753            rb_obj_reveal(val.as_rb_value(), ruby.class_array().as_rb_value());
1754            RArray::from_value_unchecked(val)
1755        }
1756    }
1757
1758    proxy!(len() -> usize);
1759    proxy!(is_empty() -> bool);
1760    proxy!(clear() -> Result<(), Error>);
1761    proxy!(resize(len: usize) -> Result<(), Error>);
1762    proxy!(reverse() -> Result<(), Error>);
1763    proxy!(rotate(rot: isize) -> Result<(), Error>);
1764    proxy!(sort() -> Result<(), Error>);
1765
1766    /// See [`RArray::dup`].
1767    pub fn dup(&self) -> Self {
1768        unsafe {
1769            let dup = RArray::from_value_unchecked(self.0.get()).dup();
1770            rb_obj_hide(dup.as_rb_value());
1771            TypedArray(NonZeroValue::new_unchecked(dup.as_value()), PhantomData)
1772        }
1773    }
1774
1775    /// See [`RArray::concat`].
1776    pub fn concat(&self, other: Self) -> Result<(), Error> {
1777        unsafe {
1778            RArray::from_value_unchecked(self.0.get())
1779                .concat(RArray::from_value_unchecked(other.0.get()))
1780        }
1781    }
1782
1783    /// See [`RArray::plus`].
1784    pub fn plus(&self, other: Self) -> Self {
1785        unsafe {
1786            let new_ary = RArray::from_value_unchecked(self.0.get())
1787                .plus(RArray::from_value_unchecked(other.0.get()));
1788            rb_obj_hide(new_ary.as_rb_value());
1789            TypedArray(NonZeroValue::new_unchecked(new_ary.as_value()), PhantomData)
1790        }
1791    }
1792
1793    /// See [`RArray::as_slice`].
1794    pub unsafe fn as_slice(&self) -> &[Value] {
1795        RArray::from_value_unchecked(self.0.get()).as_slice_unconstrained()
1796    }
1797
1798    /// See [`RArray::to_value_array`].
1799    pub fn to_value_array<const N: usize>(&self) -> Result<[Value; N], Error> {
1800        unsafe { RArray::from_value_unchecked(self.0.get()).to_value_array() }
1801    }
1802
1803    /// See [`RArray::join`].
1804    pub fn join<S>(&self, sep: S) -> Result<RString, Error>
1805    where
1806        S: IntoRString,
1807    {
1808        unsafe { RArray::from_value_unchecked(self.0.get()).join(sep) }
1809    }
1810
1811    // TODO is_shared
1812
1813    /// See [`RArray::replace`].
1814    pub fn replace(&self, from: Self) -> Result<(), Error> {
1815        unsafe {
1816            RArray::from_value_unchecked(self.0.get())
1817                .replace(RArray::from_value_unchecked(from.0.get()))
1818        }
1819    }
1820
1821    /// See [`RArray::subseq`].
1822    pub fn subseq(&self, offset: usize, length: usize) -> Option<Self> {
1823        unsafe {
1824            RArray::from_value_unchecked(self.0.get())
1825                .subseq(offset, length)
1826                .map(|ary| {
1827                    rb_obj_hide(ary.as_rb_value());
1828                    TypedArray(NonZeroValue::new_unchecked(ary.as_value()), PhantomData)
1829                })
1830        }
1831    }
1832
1833    /// See [`RArray::subseq`].
1834    #[allow(clippy::should_implement_trait)]
1835    pub fn cmp(&self, other: Self) -> Result<Option<Ordering>, Error> {
1836        unsafe {
1837            RArray::from_value_unchecked(self.0.get())
1838                .cmp(RArray::from_value_unchecked(other.0.get()))
1839        }
1840    }
1841}
1842
1843impl<T> TypedArray<T>
1844where
1845    T: IntoValue,
1846{
1847    proxy!(includes(val: T) -> bool);
1848    proxy!(push(item: T) -> Result<(), Error>);
1849    proxy!(unshift(item: T) -> Result<(), Error>);
1850    proxy!(delete(item: T) -> Result<(), Error>);
1851    proxy!(store(offset: isize, val: T) -> Result<(), Error>);
1852}
1853
1854impl<T> TypedArray<T>
1855where
1856    T: ReprValue,
1857{
1858    proxy!(cat(s: &[T]) -> Result<(), Error>);
1859}
1860
1861impl<T> TypedArray<T>
1862where
1863    T: TryConvert,
1864{
1865    proxy!(pop() -> Result<T, Error>);
1866    proxy!(shift() -> Result<T, Error>);
1867    proxy!(delete_at(index: isize) -> Result<T, Error>);
1868    proxy!(entry(offset: isize) -> Result<T, Error>);
1869
1870    /// See [`RArray::to_array`].
1871    pub fn to_array<const N: usize>(&self) -> Result<[T; N], Error> {
1872        unsafe { RArray::from_value_unchecked(self.0.get()).to_array() }
1873    }
1874
1875    /// Returns an [`Iter`] over a copy of `self`.
1876    ///
1877    /// `self` is copied using a fast copy-on-write optimisation, so if `self`
1878    /// is not modified then `self` and the copy will point to the same backing
1879    /// store and use no extra memory.
1880    ///
1881    /// # Examples
1882    ///
1883    /// ```
1884    /// use magnus::{Error, Ruby};
1885    ///
1886    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1887    ///     let ary = ruby.typed_ary_new();
1888    ///     ary.push(ruby.integer_from_i64(1))?;
1889    ///     ary.push(ruby.integer_from_i64(2))?;
1890    ///     ary.push(ruby.integer_from_i64(3))?;
1891    ///
1892    ///     let iter = ary.iter();
1893    ///
1894    ///     ary.push(ruby.integer_from_i64(4))?;
1895    ///
1896    ///     let res = iter
1897    ///         .map(|int| int.to_usize())
1898    ///         .collect::<Result<Vec<_>, Error>>()?;
1899    ///
1900    ///     assert_eq!(res, vec![1, 2, 3]);
1901    ///
1902    ///     Ok(())
1903    /// }
1904    /// # Ruby::init(example).unwrap()
1905    /// ```
1906    pub fn iter(&self) -> Iter<T> {
1907        Iter::new(unsafe { RArray::from_value_unchecked(self.dup().0.get()) })
1908    }
1909
1910    // TODO? assoc & rassoc
1911}
1912
1913impl<T> TypedArray<T>
1914where
1915    T: TryConvertOwned,
1916{
1917    /// See [`RArray::to_vec`].
1918    pub fn to_vec(&self) -> Vec<T> {
1919        unsafe { RArray::from_value_unchecked(self.0.get()).to_vec().unwrap() }
1920    }
1921}
1922
1923impl<T> IntoIterator for TypedArray<T>
1924where
1925    T: TryConvert,
1926{
1927    type Item = T;
1928    type IntoIter = Iter<T>;
1929
1930    /// Returns an [`Iter`] over `self`.
1931    ///
1932    /// # Examples
1933    ///
1934    /// ```
1935    /// use magnus::{Error, Ruby};
1936    ///
1937    /// fn example(ruby: &Ruby) -> Result<(), Error> {
1938    ///     let ary = ruby.typed_ary_new();
1939    ///     ary.push(ruby.integer_from_i64(1))?;
1940    ///     ary.push(ruby.integer_from_i64(2))?;
1941    ///     ary.push(ruby.integer_from_i64(3))?;
1942    ///
1943    ///     let res = ary
1944    ///         .into_iter()
1945    ///         .map(|int| int.to_usize())
1946    ///         .collect::<Result<Vec<_>, Error>>()?;
1947    ///
1948    ///     assert_eq!(res, vec![1, 2, 3]);
1949    ///
1950    ///     Ok(())
1951    /// }
1952    /// # Ruby::init(example).unwrap()
1953    /// ```
1954    fn into_iter(self) -> Self::IntoIter {
1955        Iter::new(unsafe { RArray::from_value_unchecked(self.0.get()) })
1956    }
1957}
1958
1959impl<T> IntoValue for TypedArray<T>
1960where
1961    T: IntoValue,
1962{
1963    fn into_value_with(self, _: &Ruby) -> Value {
1964        self.to_r_array().as_value()
1965    }
1966}
1967
1968impl<T> gc::private::Mark for TypedArray<T> {
1969    fn raw(self) -> VALUE {
1970        self.0.get().as_rb_value()
1971    }
1972}
1973impl<T> gc::Mark for TypedArray<T> {}
1974
1975/// An iterator over the elements of an array.
1976pub struct Iter<T> {
1977    data: RArray,
1978    len: usize,
1979    idx: usize,
1980    item_type: PhantomData<T>,
1981}
1982
1983impl<T> Iterator for Iter<T>
1984where
1985    T: TryConvert,
1986{
1987    type Item = T;
1988
1989    #[inline]
1990    fn next(&mut self) -> Option<Self::Item> {
1991        if self.idx >= self.len {
1992            None
1993        } else {
1994            let value = self.data.entry(self.idx as isize).ok();
1995            self.idx += 1;
1996            value
1997        }
1998    }
1999
2000    fn size_hint(&self) -> (usize, Option<usize>) {
2001        let remaining = self.len - self.idx;
2002        (remaining, Some(remaining))
2003    }
2004}
2005
2006impl<T> Iter<T> {
2007    fn new(data: RArray) -> Self {
2008        Self {
2009            data,
2010            len: data.len(),
2011            idx: 0,
2012            item_type: PhantomData,
2013        }
2014    }
2015}