From c94adfb4786c24ccd46c30c3184ad89b1ed4dc72 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 2 Apr 2016 15:39:36 +0200 Subject: [PATCH 1/3] Remove obsolete comment Indexing with inclusive ranges was added in 7eb7c56bd43b2ae12ef8b92e7258d520099a5347 --- src/libcore/slice.rs | 2 -- 1 file changed, 2 deletions(-) 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`). From 66b87e079e8665bc2cbdb971d0322afe153e3231 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 2 Apr 2016 16:02:53 +0200 Subject: [PATCH 2/3] Change RangeArgument methods to retur copies rather than references This is because the `end()` method for inclusive ranges (to be added next) needs to add one, and therefore can not return a reference. --- src/libcollections/range.rs | 26 +++++++++++++------------- src/libcollections/string.rs | 4 ++-- src/libcollections/vec.rs | 4 ++-- src/libcollections/vec_deque.rs | 4 ++-- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/libcollections/range.rs b/src/libcollections/range.rs index 4e39191b472ee..f8ab45f1deb28 100644 --- a/src/libcollections/range.rs +++ b/src/libcollections/range.rs @@ -23,14 +23,14 @@ 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 } } @@ -39,23 +39,23 @@ pub trait 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<&T> { - Some(&self.end) + fn end(&self) -> Option { + Some(self.end) } } 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"); From fccee742f67db4bafbcb075339b4fe2b0199146b Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 2 Apr 2016 16:04:00 +0200 Subject: [PATCH 3/3] Implement RangeArgument for RangeInclusive and RangeInclusiveTo The impls use `checked_add`. Since there is no trait for that method, the trait is implemented for each primitive integer type rather than generically. --- src/libcollections/range.rs | 42 ++++++++++++++++++++++++++++++++--- src/libcollectionstest/lib.rs | 1 + src/libcollectionstest/vec.rs | 19 ++++++++++++++++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/libcollections/range.rs b/src/libcollections/range.rs index f8ab45f1deb28..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`. @@ -35,8 +35,6 @@ pub trait RangeArgument { } } -// FIXME add inclusive ranges to RangeArgument - impl RangeArgument for RangeFull {} impl RangeArgument for RangeFrom { @@ -59,3 +57,41 @@ impl RangeArgument for Range { 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/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];