7
7
8
8
use std:: cell:: OnceCell ;
9
9
use std:: marker:: PhantomData ;
10
+ use std:: ops:: RangeBounds ;
10
11
use std:: { cmp, fmt} ;
11
12
12
13
use godot_ffi as sys;
@@ -15,6 +16,7 @@ use sys::{ffi_methods, interface_fn, GodotFfi};
15
16
use crate :: builtin:: * ;
16
17
use crate :: meta;
17
18
use crate :: meta:: error:: { ConvertError , FromGodotError , FromVariantError } ;
19
+ use crate :: meta:: godot_range:: GodotRange ;
18
20
use crate :: meta:: {
19
21
element_godot_type_name, element_variant_type, ArrayElement , AsArg , ClassName , ElementType ,
20
22
ExtVariantType , FromGodot , GodotConvert , GodotFfiVariant , GodotType , PropertyHintInfo , RefArg ,
@@ -526,57 +528,98 @@ impl<T: ArrayElement> Array<T> {
526
528
result. with_cache ( self )
527
529
}
528
530
529
- /// Returns a sub-range `begin..end`, as a new array .
531
+ /// Returns a sub-range `begin..end` as a new `Array` .
530
532
///
531
533
/// The values of `begin` (inclusive) and `end` (exclusive) will be clamped to the array size.
532
534
///
535
+ /// If either `begin` or `end` are negative, their value is relative to the end of the array.
536
+ ///
537
+ /// # Example
538
+ /// ```no_run
539
+ /// # use godot::builtin::array;
540
+ /// assert_eq!(array![0, 1, 2, 3, 4, 5].subarray_shallow(-1..-5, None), array![5, 3]);
541
+ /// ```
542
+ ///
543
+ /// If `end` is not specified, the range spans through whole array.
544
+ ///
545
+ /// # Example
546
+ /// ```no_run
547
+ /// # use godot::builtin::array;
548
+ /// assert_eq!(array![0, 1, 2, 3, 4, 5].subarray_shallow(1.., None), array![1, 2, 3, 4, 5]);
549
+ /// ```
550
+ ///
533
551
/// If specified, `step` is the relative index between source elements. It can be negative,
534
- /// in which case `begin` must be higher than `end`. For example,
535
- /// `Array::from(&[0, 1, 2, 3, 4, 5]).slice(5, 1, -2)` returns `[5, 3]`.
552
+ /// in which case `begin` must be higher than `end`.
553
+ ///
554
+ /// # Example
555
+ /// ```no_run
556
+ /// # use godot::builtin::array;
557
+ /// assert_eq!(array![0, 1, 2, 3, 4, 5].subarray_shallow(-1..-5, Some(-2)), array![5, 3]);
558
+ /// ```
536
559
///
537
560
/// Array elements are copied to the slice, but any reference types (such as `Array`,
538
561
/// `Dictionary` and `Object`) will still refer to the same value. To create a deep copy, use
539
562
/// [`subarray_deep()`][Self::subarray_deep] instead.
540
563
///
541
564
/// _Godot equivalent: `slice`_
542
565
#[ doc( alias = "slice" ) ]
543
- // TODO(v0.3): change to i32 like NodePath::slice/subpath() and support+test negative indices.
544
- pub fn subarray_shallow ( & self , begin : usize , end : usize , step : Option < isize > ) -> Self {
545
- self . subarray_impl ( begin, end, step, false )
566
+ pub fn subarray_shallow ( & self , range : impl RangeBounds < i32 > , step : Option < i32 > ) -> Self {
567
+ self . subarray_impl ( range, step, false )
546
568
}
547
569
548
- /// Returns a sub-range `begin..end`, as a new `Array`.
570
+ /// Returns a sub-range `begin..end` as a new `Array`.
549
571
///
550
572
/// The values of `begin` (inclusive) and `end` (exclusive) will be clamped to the array size.
551
573
///
574
+ /// If either `begin` or `end` are negative, their value is relative to the end of the array.
575
+ ///
576
+ /// # Example
577
+ /// ```no_run
578
+ /// # use godot::builtin::array;
579
+ /// assert_eq!(array![0, 1, 2, 3, 4, 5].subarray_deep(-1..-5, None), array![5, 3]);
580
+ /// ```
581
+ ///
582
+ /// If `end` is not specified, the range spans through whole array.
583
+ ///
584
+ /// # Example
585
+ /// ```no_run
586
+ /// # use godot::builtin::array;
587
+ /// assert_eq!(array![0, 1, 2, 3, 4, 5].subarray_deep(1.., None), array![1, 2, 3, 4, 5]);
588
+ /// ```
589
+ ///
552
590
/// If specified, `step` is the relative index between source elements. It can be negative,
553
- /// in which case `begin` must be higher than `end`. For example,
554
- /// `Array::from(&[0, 1, 2, 3, 4, 5]).slice(5, 1, -2)` returns `[5, 3]`.
591
+ /// in which case `begin` must be higher than `end`.
592
+ ///
593
+ /// # Example
594
+ /// ```no_run
595
+ /// # use godot::builtin::array;
596
+ /// assert_eq!(array![0, 1, 2, 3, 4, 5].subarray_deep(-1..-5, Some(-2)), array![5, 3]);
597
+ /// ```
555
598
///
556
599
/// All nested arrays and dictionaries are duplicated and will not be shared with the original
557
600
/// array. Note that any `Object`-derived elements will still be shallow copied. To create a
558
601
/// shallow copy, use [`subarray_shallow()`][Self::subarray_shallow] instead.
559
602
///
560
603
/// _Godot equivalent: `slice`_
561
604
#[ doc( alias = "slice" ) ]
562
- // TODO(v0.3): change to i32 like NodePath::slice/subpath() and support+test negative indices.
563
- pub fn subarray_deep ( & self , begin : usize , end : usize , step : Option < isize > ) -> Self {
564
- self . subarray_impl ( begin, end, step, true )
605
+ pub fn subarray_deep ( & self , range : impl RangeBounds < i32 > , step : Option < i32 > ) -> Self {
606
+ self . subarray_impl ( range, step, true )
565
607
}
566
608
567
- fn subarray_impl ( & self , begin : usize , end : usize , step : Option < isize > , deep : bool ) -> Self {
609
+ // Note: Godot will clamp values by itself.
610
+ fn subarray_impl ( & self , range : impl GodotRange < i32 > , step : Option < i32 > , deep : bool ) -> Self {
568
611
assert_ne ! ( step, Some ( 0 ) , "subarray: step cannot be zero" ) ;
569
612
570
- let len = self . len ( ) ;
571
- let begin = begin. min ( len) ;
572
- let end = end. min ( len) ;
573
613
let step = step. unwrap_or ( 1 ) ;
614
+ let ( begin, end) = range. to_godot_range_fromto ( ) ;
615
+
616
+ // Unbounded upper bounds are represented by `i32::MAX` instead of `i64::MAX`,
617
+ // since Godot treats some indexes as 32-bit despite being declared `i64` in GDExtension API.
618
+ let end = end. unwrap_or ( i32:: MAX as i64 ) ;
574
619
575
620
// SAFETY: The type of the array is `T` and we convert the returned array to an `Array<T>` immediately.
576
- let subarray: VariantArray = unsafe {
577
- self . as_inner ( )
578
- . slice ( to_i64 ( begin) , to_i64 ( end) , step. try_into ( ) . unwrap ( ) , deep)
579
- } ;
621
+ let subarray: VariantArray =
622
+ unsafe { self . as_inner ( ) . slice ( begin, end, step as i64 , deep) } ;
580
623
581
624
// SAFETY: slice() returns a typed array with the same type as Self.
582
625
let result = unsafe { subarray. assume_type ( ) } ;
0 commit comments