77
88use std:: cell:: OnceCell ;
99use std:: marker:: PhantomData ;
10- use std:: ops:: RangeBounds ;
1110use std:: { cmp, fmt} ;
1211
1312use godot_ffi as sys;
@@ -16,7 +15,7 @@ use sys::{ffi_methods, interface_fn, GodotFfi};
1615use crate :: builtin:: * ;
1716use crate :: meta;
1817use crate :: meta:: error:: { ConvertError , FromGodotError , FromVariantError } ;
19- use crate :: meta:: godot_range :: GodotRange ;
18+ use crate :: meta:: signed_range :: SignedRange ;
2019use crate :: meta:: {
2120 element_godot_type_name, element_variant_type, ArrayElement , AsArg , ClassName , ElementType ,
2221 ExtVariantType , FromGodot , GodotConvert , GodotFfiVariant , GodotType , PropertyHintInfo , RefArg ,
@@ -110,6 +109,35 @@ use crate::registry::property::{BuiltinExport, Export, Var};
110109/// // ...and so on.
111110/// ```
112111///
112+ /// # Working with signed ranges and steps
113+ ///
114+ /// For negative indices, use [`wrapped()`](crate::meta::wrapped).
115+ ///
116+ /// ```no_run
117+ /// # use godot::builtin::array;
118+ /// # use godot::meta::wrapped;
119+ /// let arr = array![0, 1, 2, 3, 4, 5];
120+ ///
121+ /// // The values of `begin` (inclusive) and `end` (exclusive) will be clamped to the array size.
122+ /// let clamped_array = arr.subarray_deep(999..99999, None);
123+ /// assert_eq!(clamped_array, array![]);
124+ ///
125+ /// // If either `begin` or `end` is negative, its value is relative to the end of the array.
126+ /// let sub = arr.subarray_shallow(wrapped(-1..-5), None);
127+ /// assert_eq!(sub, array![5, 3]);
128+ ///
129+ /// // If `end` is not specified, the range spans through whole array.
130+ /// let sub = arr.subarray_deep(1.., None);
131+ /// assert_eq!(sub, array![1, 2, 3, 4, 5]);
132+ /// let other_clamped_array = arr.subarray_shallow(5.., Some(2));
133+ /// assert_eq!(other_clamped_array, array![5]);
134+ ///
135+ /// // If specified, `step` is the relative index between source elements. It can be negative,
136+ /// // in which case `begin` must be higher than `end`.
137+ /// let sub = arr.subarray_shallow(wrapped(-1..-5), Some(-2));
138+ /// assert_eq!(sub, array![5, 3]);
139+ /// ```
140+ ///
113141/// # Thread safety
114142///
115143/// Usage is safe if the `Array` is used on a single thread only. Concurrent reads on
@@ -530,91 +558,34 @@ impl<T: ArrayElement> Array<T> {
530558
531559 /// Returns a sub-range `begin..end` as a new `Array`.
532560 ///
533- /// The values of `begin` (inclusive) and `end` (exclusive) will be clamped to the array size.
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- ///
551- /// If specified, `step` is the relative index between source elements. It can be negative,
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- /// ```
559- ///
560561 /// Array elements are copied to the slice, but any reference types (such as `Array`,
561562 /// `Dictionary` and `Object`) will still refer to the same value. To create a deep copy, use
562563 /// [`subarray_deep()`][Self::subarray_deep] instead.
563564 ///
564565 /// _Godot equivalent: `slice`_
565566 #[ doc( alias = "slice" ) ]
566- pub fn subarray_shallow ( & self , range : impl RangeBounds < i32 > , step : Option < i32 > ) -> Self {
567+ pub fn subarray_shallow ( & self , range : impl SignedRange , step : Option < i32 > ) -> Self {
567568 self . subarray_impl ( range, step, false )
568569 }
569570
570571 /// Returns a sub-range `begin..end` as a new `Array`.
571572 ///
572- /// The values of `begin` (inclusive) and `end` (exclusive) will be clamped to the array size.
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- ///
590- /// If specified, `step` is the relative index between source elements. It can be negative,
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- /// ```
598- ///
599573 /// All nested arrays and dictionaries are duplicated and will not be shared with the original
600574 /// array. Note that any `Object`-derived elements will still be shallow copied. To create a
601575 /// shallow copy, use [`subarray_shallow()`][Self::subarray_shallow] instead.
602576 ///
603577 /// _Godot equivalent: `slice`_
604578 #[ doc( alias = "slice" ) ]
605- pub fn subarray_deep ( & self , range : impl RangeBounds < i32 > , step : Option < i32 > ) -> Self {
579+ pub fn subarray_deep ( & self , range : impl SignedRange , step : Option < i32 > ) -> Self {
606580 self . subarray_impl ( range, step, true )
607581 }
608582
609583 // Note: Godot will clamp values by itself.
610- fn subarray_impl ( & self , range : impl GodotRange < i32 > , step : Option < i32 > , deep : bool ) -> Self {
584+ fn subarray_impl ( & self , range : impl SignedRange , step : Option < i32 > , deep : bool ) -> Self {
611585 assert_ne ! ( step, Some ( 0 ) , "subarray: step cannot be zero" ) ;
612586
613587 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.
588+ let ( begin, end) = range. signed ( ) ;
618589 let end = end. unwrap_or ( i32:: MAX as i64 ) ;
619590
620591 // SAFETY: The type of the array is `T` and we convert the returned array to an `Array<T>` immediately.
0 commit comments