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}