From b86a7808c74fa0da1f1fcb9b7df760314f9e4104 Mon Sep 17 00:00:00 2001
From: Huon Wilson <dbau.pp+github@gmail.com>
Date: Sat, 15 Nov 2014 14:44:55 +1100
Subject: [PATCH] Add methods to go from a slice iterators to a slice.

A slice iterator is isomorphic to a slice, just with a slightly
different form: storing start and end pointers rather than start pointer
and length. This patch reflects this by making converting between them
as easy as `iter.as_slice()` (or even `iter[]` if the shorter lifetime
is ok). That is, `slice.iter().as_slice() == slice`.
---
 src/libcore/slice.rs     | 96 ++++++++++++++++++++++++++++++++++++++++
 src/libcoretest/slice.rs | 49 ++++++++++++++++++++
 2 files changed, 145 insertions(+)

diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs
index 665b6705dad..65f61791127 100644
--- a/src/libcore/slice.rs
+++ b/src/libcore/slice.rs
@@ -1092,6 +1092,21 @@ macro_rules! iterator {
     }
 }
 
+macro_rules! make_slice {
+    ($t: ty -> $result: ty: $start: expr, $end: expr) => {{
+        let diff = $end as uint - $start as uint;
+        let len = if mem::size_of::<T>() == 0 {
+            diff
+        } else {
+            diff / mem::size_of::<$t>()
+        };
+        unsafe {
+            transmute::<_, $result>(RawSlice { data: $start as *const T, len: len })
+        }
+    }}
+}
+
+
 /// Immutable slice iterator
 #[experimental = "needs review"]
 pub struct Items<'a, T: 'a> {
@@ -1100,6 +1115,36 @@ pub struct Items<'a, T: 'a> {
     marker: marker::ContravariantLifetime<'a>
 }
 
+#[experimental]
+impl<'a, T> ops::Slice<uint, [T]> for Items<'a, T> {
+    fn as_slice_(&self) -> &[T] {
+        self.as_slice()
+    }
+    fn slice_from_or_fail<'b>(&'b self, from: &uint) -> &'b [T] {
+        use ops::Slice;
+        self.as_slice().slice_from_or_fail(from)
+    }
+    fn slice_to_or_fail<'b>(&'b self, to: &uint) -> &'b [T] {
+        use ops::Slice;
+        self.as_slice().slice_to_or_fail(to)
+    }
+    fn slice_or_fail<'b>(&'b self, from: &uint, to: &uint) -> &'b [T] {
+        use ops::Slice;
+        self.as_slice().slice_or_fail(from, to)
+    }
+}
+
+impl<'a, T> Items<'a, T> {
+    /// View the underlying data as a subslice of the original data.
+    ///
+    /// This has the same lifetime as the original slice, and so the
+    /// iterator can continue to be used while this exists.
+    #[experimental]
+    pub fn as_slice(&self) -> &'a [T] {
+        make_slice!(T -> &'a [T]: self.ptr, self.end)
+    }
+}
+
 iterator!{struct Items -> *const T, &'a T}
 
 #[experimental = "needs review"]
@@ -1144,6 +1189,57 @@ pub struct MutItems<'a, T: 'a> {
     marker2: marker::NoCopy
 }
 
+#[experimental]
+impl<'a, T> ops::Slice<uint, [T]> for MutItems<'a, T> {
+    fn as_slice_<'b>(&'b self) -> &'b [T] {
+        make_slice!(T -> &'b [T]: self.ptr, self.end)
+    }
+    fn slice_from_or_fail<'b>(&'b self, from: &uint) -> &'b [T] {
+        use ops::Slice;
+        self.as_slice_().slice_from_or_fail(from)
+    }
+    fn slice_to_or_fail<'b>(&'b self, to: &uint) -> &'b [T] {
+        use ops::Slice;
+        self.as_slice_().slice_to_or_fail(to)
+    }
+    fn slice_or_fail<'b>(&'b self, from: &uint, to: &uint) -> &'b [T] {
+        use ops::Slice;
+        self.as_slice_().slice_or_fail(from, to)
+    }
+}
+
+#[experimental]
+impl<'a, T> ops::SliceMut<uint, [T]> for MutItems<'a, T> {
+    fn as_mut_slice_<'b>(&'b mut self) -> &'b mut [T] {
+        make_slice!(T -> &'b mut [T]: self.ptr, self.end)
+    }
+    fn slice_from_or_fail_mut<'b>(&'b mut self, from: &uint) -> &'b mut [T] {
+        use ops::SliceMut;
+        self.as_mut_slice_().slice_from_or_fail_mut(from)
+    }
+    fn slice_to_or_fail_mut<'b>(&'b mut self, to: &uint) -> &'b mut [T] {
+        use ops::SliceMut;
+        self.as_mut_slice_().slice_to_or_fail_mut(to)
+    }
+    fn slice_or_fail_mut<'b>(&'b mut self, from: &uint, to: &uint) -> &'b mut [T] {
+        use ops::SliceMut;
+        self.as_mut_slice_().slice_or_fail_mut(from, to)
+    }
+}
+
+impl<'a, T> MutItems<'a, T> {
+    /// View the underlying data as a subslice of the original data.
+    ///
+    /// To avoid creating `&mut` references that alias, this is forced
+    /// to consume the iterator. Consider using the `Slice` and
+    /// `SliceMut` implementations for obtaining slices with more
+    /// restricted lifetimes that do not consume the iterator.
+    #[experimental]
+    pub fn into_slice(self) -> &'a mut [T] {
+        make_slice!(T -> &'a mut [T]: self.ptr, self.end)
+    }
+}
+
 iterator!{struct MutItems -> *mut T, &'a mut T}
 
 #[experimental = "needs review"]
diff --git a/src/libcoretest/slice.rs b/src/libcoretest/slice.rs
index 1288756dea4..29253c50ed0 100644
--- a/src/libcoretest/slice.rs
+++ b/src/libcoretest/slice.rs
@@ -33,3 +33,52 @@ fn binary_search_not_found() {
     let b = [1i, 2, 4, 5, 6, 8];
     assert!(b.binary_search(|v| v.cmp(&9)) == NotFound(6));
 }
+
+#[test]
+fn iterator_to_slice() {
+    macro_rules! test {
+        ($data: expr) => {{
+            let data: &mut [_] = &mut $data;
+            let other_data: &mut [_] = &mut $data;
+
+            {
+                let mut iter = data.iter();
+                assert_eq!(iter[], other_data[]);
+
+                iter.next();
+                assert_eq!(iter[], other_data[1..]);
+
+                iter.next_back();
+                assert_eq!(iter[], other_data[1..2]);
+
+                let s = iter.as_slice();
+                iter.next();
+                assert_eq!(s, other_data[1..2]);
+            }
+            {
+                let mut iter = data.iter_mut();
+                assert_eq!(iter[], other_data[]);
+                // mutability:
+                assert!(iter[mut] == other_data);
+
+                iter.next();
+                assert_eq!(iter[], other_data[1..]);
+                assert!(iter[mut] == other_data[mut 1..]);
+
+                iter.next_back();
+
+                assert_eq!(iter[], other_data[1..2]);
+                assert!(iter[mut] == other_data[mut 1..2]);
+
+                let s = iter.into_slice();
+                assert!(s == other_data[mut 1..2]);
+            }
+        }}
+    }
+
+    // try types of a variety of sizes
+    test!([(1u64, 1u64, 1u8), (2, 2, 2), (3, 3, 3)]);
+    test!([1u64,2,3]);
+    test!([1u8,2,3]);
+    test!([(),(),()]);
+}