diff --git a/src/libcollections/range.rs b/src/libcollections/range.rs index 4e39191b472ee..adc9ac75cc3d4 100644 --- a/src/libcollections/range.rs +++ b/src/libcollections/range.rs @@ -15,7 +15,7 @@ //! Range syntax. use core::option::Option::{self, None, Some}; -use core::ops::{RangeFull, Range, RangeTo, RangeFrom}; +use core::ops::{RangeFull, Range, RangeTo, RangeFrom, RangeInclusive, RangeToInclusive}; /// **RangeArgument** is implemented by Rust's built-in range types, produced /// by range syntax like `..`, `a..`, `..b` or `c..d`. @@ -23,39 +23,75 @@ pub trait RangeArgument { /// Start index (inclusive) /// /// Return start value if present, else `None`. - fn start(&self) -> Option<&T> { + fn start(&self) -> Option { None } /// End index (exclusive) /// /// Return end value if present, else `None`. - fn end(&self) -> Option<&T> { + fn end(&self) -> Option { None } } -// FIXME add inclusive ranges to RangeArgument - impl RangeArgument for RangeFull {} -impl RangeArgument for RangeFrom { - fn start(&self) -> Option<&T> { - Some(&self.start) +impl RangeArgument for RangeFrom { + fn start(&self) -> Option { + Some(self.start) } } -impl RangeArgument for RangeTo { - fn end(&self) -> Option<&T> { - Some(&self.end) +impl RangeArgument for RangeTo { + fn end(&self) -> Option { + Some(self.end) } } -impl RangeArgument for Range { - fn start(&self) -> Option<&T> { - Some(&self.start) +impl RangeArgument for Range { + fn start(&self) -> Option { + Some(self.start) + } + fn end(&self) -> Option { + Some(self.end) } - fn end(&self) -> Option<&T> { - Some(&self.end) +} + +macro_rules! inclusive { + ($Int: ty) => { + impl RangeArgument<$Int> for RangeToInclusive<$Int> { + fn end(&self) -> Option<$Int> { + Some(self.end.checked_add(1).expect("inclusive range to maximum usize")) + } + } + + impl RangeArgument<$Int> for RangeInclusive<$Int> { + fn start(&self) -> Option<$Int> { + match *self { + RangeInclusive::Empty { at } => Some(at), + RangeInclusive::NonEmpty { start, .. } => Some(start), + } + } + fn end(&self) -> Option<$Int> { + match *self { + RangeInclusive::Empty { at } => Some(at), + RangeInclusive::NonEmpty { end, .. } => { + Some(end.checked_add(1).expect("inclusive range to maximum usize")) + } + } + } + } } } + +inclusive!(u8); +inclusive!(u16); +inclusive!(u32); +inclusive!(u64); +inclusive!(usize); +inclusive!(i8); +inclusive!(i16); +inclusive!(i32); +inclusive!(i64); +inclusive!(isize); diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index c84d84959dbc2..af51f263643b1 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1269,8 +1269,8 @@ impl String { // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. let len = self.len(); - let start = *range.start().unwrap_or(&0); - let end = *range.end().unwrap_or(&len); + let start = range.start().unwrap_or(0); + let end = range.end().unwrap_or(len); // Take out two simultaneous borrows. The &mut String won't be accessed // until iteration is over, in Drop. diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index dde5cbb508e1b..77f86c0f3c2dd 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -805,8 +805,8 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let start = *range.start().unwrap_or(&0); - let end = *range.end().unwrap_or(&len); + let start = range.start().unwrap_or(0); + let end = range.end().unwrap_or(len); assert!(start <= end); assert!(end <= len); diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 9e2b25d178fb9..6768059640b8c 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -813,8 +813,8 @@ impl VecDeque { // and the head/tail values will be restored correctly. // let len = self.len(); - let start = *range.start().unwrap_or(&0); - let end = *range.end().unwrap_or(&len); + let start = range.start().unwrap_or(0); + let end = range.end().unwrap_or(len); assert!(start <= end, "drain lower bound was too large"); assert!(end <= len, "drain upper bound was too large"); diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 62fefaa10f677..87d28deeee5c2 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -20,6 +20,7 @@ #![feature(const_fn)] #![feature(fn_traits)] #![feature(enumset)] +#![feature(inclusive_range_syntax)] #![feature(iter_arith)] #![feature(map_entry_keys)] #![feature(pattern)] diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index ccdbf1092ff1e..9f027c7b01623 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -438,6 +438,25 @@ fn test_drain_range() { assert_eq!(v, &[(), ()]); } +#[test] +fn test_drain_range_inclusive() { + let mut vec = vec![1, 2, 3, 4, 5]; + let mut vec2 = vec![]; + for i in vec.drain(1...3) { + vec2.push(i); + } + assert_eq!(vec, [1, 5]); + assert_eq!(vec2, [2, 3, 4]); + + let mut vec = vec![1, 2, 3, 4, 5]; + let mut vec2 = vec![]; + for i in vec.drain(...3) { + vec2.push(i); + } + assert_eq!(vec, [5]); + assert_eq!(vec2, [1, 2, 3, 4]); +} + #[test] fn test_into_boxed_slice() { let xs = vec![1, 2, 3]; diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index aa555b44e899f..0819bf8e82c55 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -534,8 +534,6 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! { panic!("slice index starts at {} but ends at {}", index, end); } -// FIXME implement indexing with inclusive ranges - /// Implements slicing with syntax `&self[begin .. end]`. /// /// Returns a slice of self for the index range [`begin`..`end`).