From f74cc0d100b10667ab88df5437e1ca472a0a4481 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Mon, 12 Jan 2015 16:49:11 +0100 Subject: [PATCH 1/4] drain_range --- text/0000-drain-range.md | 66 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 text/0000-drain-range.md diff --git a/text/0000-drain-range.md b/text/0000-drain-range.md new file mode 100644 index 00000000000..13cfa1eadde --- /dev/null +++ b/text/0000-drain-range.md @@ -0,0 +1,66 @@ +- Start Date: 2015-01-12 +- RFC PR #: (leave this empty) +- Rust Issue #: (leave this empty) + +# Summary + +Replace `Vec::drain` by a method that accepts a range parameter. + +# Motivation + +Allowing a range parameter is strictly more powerful than the current version. +E.g., see the following implementations of some `Vec` methods via the hypothetical +`drain_range` method: + +```rust +fn truncate(x: &mut Vec, len: usize) { + if len <= x.len() { + x.drain_range(len..); + } +} + +fn remove(x: &mut Vec, index: usize) -> u8 { + x.drain_range(index).next().unwrap() +} + +fn pop(x: &mut Vec) -> Option { + match x.len() { + 0 => None, + n => x.drain_range(n-1).next() + } +} + +fn drain(x: &mut Vec) -> DrainRange { + x.drain_range(0..) +} + +fn clear(x: &mut Vec) { + x.drain_range(0..); +} +``` + +With optimization enabled, those methods will produce code that runs as fast +as the current versions. (They should not be implemented this way.) + +In particular, this method allows the user to remove a slice from a vector in +`O(Vec::len)` instead of `O(Slice::len * Vec::len)`. + +# Detailed design + +Remove `Vec::drain` and add the following method: + +```rust +/// Creates a draining iterator that clears the specified range in the Vec and +/// iterates over the removed items from start to end. +/// +/// # Panics +/// +/// Panics if the range is decreasing or if the upper bound is larger than the +/// length of the vector. +pub fn drain(&mut self, range: T) -> RangeIter { + range.drain(self) +} +``` + +Where `Drainer` should be implemented for `Range`, `RangeTo`, +`RangeFrom`, `FullRange`, and `usize`. From ec3ea51b629aad9ef900e2434747a1ef003b9b30 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 13 Feb 2015 12:50:23 +0100 Subject: [PATCH 2/4] add String method --- text/0000-drain-range.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/text/0000-drain-range.md b/text/0000-drain-range.md index 13cfa1eadde..85cd289d7b9 100644 --- a/text/0000-drain-range.md +++ b/text/0000-drain-range.md @@ -4,7 +4,8 @@ # Summary -Replace `Vec::drain` by a method that accepts a range parameter. +Replace `Vec::drain` by a method that accepts a range parameter. Add +`String::drain` with similar functionality. # Motivation @@ -64,3 +65,19 @@ pub fn drain(&mut self, range: T) -> RangeIter { Where `Drainer` should be implemented for `Range`, `RangeTo`, `RangeFrom`, `FullRange`, and `usize`. + +Add `String::drain`: + +```rust +/// Creates a draining iterator that clears the specified range in the String +/// and iterates over the characters contained in the range. +/// +/// # Panics +/// +/// Panics if the range is decreasing, if the upper bound is larger than the +/// length of the String, or if the start and the end of the range don't lie on +/// character boundaries. +pub fn drain(&mut self, range: /* ? */) -> /* ? */ { + // ? +} +``` From 1a57d20621bccb4dc4d05ce3e174a139c06448ca Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 13 Feb 2015 13:38:42 +0100 Subject: [PATCH 3/4] add drawbacks --- text/0000-drain-range.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/text/0000-drain-range.md b/text/0000-drain-range.md index 85cd289d7b9..b3e3f739a34 100644 --- a/text/0000-drain-range.md +++ b/text/0000-drain-range.md @@ -81,3 +81,10 @@ pub fn drain(&mut self, range: /* ? */) -> /* ? */ { // ? } ``` + +# Drawbacks + +- The function signature differs from other collections. +- It's not clear from the signature that `..` can be used to get the old behavior. +- The trait documentation will link to the `std::ops` module. It's not immediately apparent how the types in there are related to the `N..M` syntax. +- Some of these problems can be mitigated by solid documentation of the function itself. From 24f772d5ec314e823f06fb46083ac3c30c1de67e Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Wed, 18 Feb 2015 09:26:22 +0100 Subject: [PATCH 4/4] update detailed design --- text/0000-drain-range.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/text/0000-drain-range.md b/text/0000-drain-range.md index b3e3f739a34..adbd22dcc15 100644 --- a/text/0000-drain-range.md +++ b/text/0000-drain-range.md @@ -58,13 +58,14 @@ Remove `Vec::drain` and add the following method: /// /// Panics if the range is decreasing or if the upper bound is larger than the /// length of the vector. -pub fn drain(&mut self, range: T) -> RangeIter { - range.drain(self) -} +pub fn drain(&mut self, range: T) -> /* ... */; ``` -Where `Drainer` should be implemented for `Range`, `RangeTo`, -`RangeFrom`, `FullRange`, and `usize`. +Where `Trait` is some trait that is implemented for at least `Range`, +`RangeTo`, `RangeFrom`, `FullRange`, and `usize`. + +The precise nature of the return value is to be determined during implementation +and may or may not depend on `T`. Add `String::drain`: @@ -77,11 +78,11 @@ Add `String::drain`: /// Panics if the range is decreasing, if the upper bound is larger than the /// length of the String, or if the start and the end of the range don't lie on /// character boundaries. -pub fn drain(&mut self, range: /* ? */) -> /* ? */ { - // ? -} +pub fn drain(&mut self, range: T) -> /* ... */; ``` +Where `Trait` and the return value are as above but need not be the same. + # Drawbacks - The function signature differs from other collections.