]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #15289 : aturon/rust/libstd-stability, r=alexcrichton
authorbors <bors@rust-lang.org>
Tue, 1 Jul 2014 10:11:34 +0000 (10:11 +0000)
committerbors <bors@rust-lang.org>
Tue, 1 Jul 2014 10:11:34 +0000 (10:11 +0000)
Earlier commits have established a baseline of `experimental` stability
for all crates under the facade (so their contents are considered
experimental within libstd). Since `experimental` is `allow` by
default, we should use the same baseline stability for libstd itself.

This commit adds `experimental` tags to all of the modules defined in
`std`, and `unstable` to `std` itself.

24 files changed:
src/doc/guide.md
src/libcollections/str.rs
src/libcore/fmt/mod.rs
src/libcore/slice.rs
src/librustc/lint/builtin.rs
src/librustc/metadata/encoder.rs
src/librustc/middle/stability.rs
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/builder.rs
src/librustc/middle/trans/callee.rs
src/librustc/middle/trans/meth.rs
src/librustc/middle/typeck/check/method.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/core.rs
src/librustdoc/doctree.rs
src/librustdoc/fold.rs
src/librustdoc/html/format.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/main.css
src/librustdoc/visit_ast.rs
src/test/run-fail/by-value-self-objects-fail.rs [new file with mode: 0644]
src/test/run-pass/by-value-self-objects.rs [new file with mode: 0644]
src/test/run-pass/ifmt.rs

index f8af50213b98e9daff56d96426bf1df1d14d09f3..4577c5a86d77582d18c8f9bf19e243d1a6ddb439 100644 (file)
@@ -160,7 +160,7 @@ Save the file, and then type this into your terminal window:
 
 ```{bash}
 $ rustc hello_world.rs
-$ ./hello_world # just 'hello_world' on Windows
+$ ./hello_world # or hello_world.exe on Windows
 Hello, world
 ```
 
@@ -243,7 +243,7 @@ There are now two files: our source code, with the `.rs` extension, and the
 executable (`hello_world.exe` on Windows, `hello_world` everywhere else)
 
 ```{bash}
-$ ./hello_world  # or ./hello_world.exe on Windows
+$ ./hello_world  # or hello_world.exe on Windows
 ```
 
 This prints out our `Hello, world!` text to our terminal.
index 10309adef20d9faafa8c8de2d610b66e30eeef9e..7e47f02d21a0ce043546bd51281c19b03026fec6 100644 (file)
@@ -106,6 +106,14 @@ pub fn from_utf8_owned(vv: Vec<u8>) -> Result<String, Vec<u8>> {
 /// # Failure
 ///
 /// Fails if invalid UTF-8
+///
+/// # Example
+///
+/// ```rust
+/// use std::str;
+/// let string = str::from_byte(66u8);
+/// assert_eq!(string.as_slice(), "B");
+/// ```
 pub fn from_byte(b: u8) -> String {
     assert!(b < 128u8);
     String::from_char(1, b as char)
index ff7d7827fbb8ef932c8ab949438d67eade40dcce..7b84c005db548667c25f635e76d14888138858b9 100644 (file)
@@ -518,6 +518,9 @@ fn fmt(&self, f: &mut Formatter) -> Result { secret_show(*self, f) }
 impl<'a, T: Show> Show for &'a mut T {
     fn fmt(&self, f: &mut Formatter) -> Result { secret_show(&**self, f) }
 }
+impl<'a> Show for &'a Show {
+    fn fmt(&self, f: &mut Formatter) -> Result { (*self).fmt(f) }
+}
 
 impl Bool for bool {
     fn fmt(&self, f: &mut Formatter) -> Result {
index a9e7efdf05a5ada6177858be6609b33f093ee568..0178c0318b81c2afde7be72eec396e4cfc55a425 100644 (file)
 
 #![doc(primitive = "slice")]
 
+// How this module is organized.
+//
+// The library infrastructure for slices is fairly messy. There's
+// a lot of stuff defined here. Let's keep it clean.
+//
+// Since slices don't support inherent methods; all operations
+// on them are defined on traits, which are then reexported from
+// the prelude for convenience. So there are a lot of traits here.
+//
+// The layout of this file is thus:
+//
+// * Slice-specific 'extension' traits and their implementations. This
+//   is where most of the slice API resides.
+// * Implementations of a few common traits with important slice ops.
+// * Definitions of a bunch of iterators.
+// * Free functions.
+// * The `raw` and `bytes` submodules.
+// * Boilerplate trait implementations.
+
 use mem::transmute;
 use clone::Clone;
 use collections::Collection;
-use cmp::{PartialEq, Ord, Ordering, Less, Equal, Greater};
+use cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering, Less, Equal, Greater, Equiv};
 use cmp;
 use default::Default;
 use iter::*;
 use kinds::marker;
 use raw::{Repr, Slice};
 
-/**
- * Converts a pointer to A into a slice of length 1 (without copying).
- */
-pub fn ref_slice<'a, A>(s: &'a A) -> &'a [A] {
-    unsafe {
-        transmute(Slice { data: s, len: 1 })
-    }
+//
+// Extension traits
+//
+
+/// Extension methods for vectors
+pub trait ImmutableVector<'a, T> {
+    /**
+     * Returns a slice of self spanning the interval [`start`, `end`).
+     *
+     * Fails when the slice (or part of it) is outside the bounds of self,
+     * or when `start` > `end`.
+     */
+    fn slice(&self, start: uint, end: uint) -> &'a [T];
+
+    /**
+     * Returns a slice of self from `start` to the end of the vec.
+     *
+     * Fails when `start` points outside the bounds of self.
+     */
+    fn slice_from(&self, start: uint) -> &'a [T];
+
+    /**
+     * Returns a slice of self from the start of the vec to `end`.
+     *
+     * Fails when `end` points outside the bounds of self.
+     */
+    fn slice_to(&self, end: uint) -> &'a [T];
+    /// Returns an iterator over the vector
+    fn iter(self) -> Items<'a, T>;
+    /// Returns an iterator over the subslices of the vector which are
+    /// separated by elements that match `pred`.  The matched element
+    /// is not contained in the subslices.
+    fn split(self, pred: |&T|: 'a -> bool) -> Splits<'a, T>;
+    /// Returns an iterator over the subslices of the vector which are
+    /// separated by elements that match `pred`, limited to splitting
+    /// at most `n` times.  The matched element is not contained in
+    /// the subslices.
+    fn splitn(self, n: uint, pred: |&T|: 'a -> bool) -> SplitsN<'a, T>;
+    /// Returns an iterator over the subslices of the vector which are
+    /// separated by elements that match `pred` limited to splitting
+    /// at most `n` times. This starts at the end of the vector and
+    /// works backwards.  The matched element is not contained in the
+    /// subslices.
+    fn rsplitn(self,  n: uint, pred: |&T|: 'a -> bool) -> SplitsN<'a, T>;
+
+    /**
+     * Returns an iterator over all contiguous windows of length
+     * `size`. The windows overlap. If the vector is shorter than
+     * `size`, the iterator returns no values.
+     *
+     * # Failure
+     *
+     * Fails if `size` is 0.
+     *
+     * # Example
+     *
+     * Print the adjacent pairs of a vector (i.e. `[1,2]`, `[2,3]`,
+     * `[3,4]`):
+     *
+     * ```rust
+     * let v = &[1i, 2, 3, 4];
+     * for win in v.windows(2) {
+     *     println!("{}", win);
+     * }
+     * ```
+     *
+     */
+    fn windows(self, size: uint) -> Windows<'a, T>;
+    /**
+     *
+     * Returns an iterator over `size` elements of the vector at a
+     * time. The chunks do not overlap. If `size` does not divide the
+     * length of the vector, then the last chunk will not have length
+     * `size`.
+     *
+     * # Failure
+     *
+     * Fails if `size` is 0.
+     *
+     * # Example
+     *
+     * Print the vector two elements at a time (i.e. `[1,2]`,
+     * `[3,4]`, `[5]`):
+     *
+     * ```rust
+     * let v = &[1i, 2, 3, 4, 5];
+     * for win in v.chunks(2) {
+     *     println!("{}", win);
+     * }
+     * ```
+     *
+     */
+    fn chunks(self, size: uint) -> Chunks<'a, T>;
+
+    /// Returns the element of a vector at the given index, or `None` if the
+    /// index is out of bounds
+    fn get(&self, index: uint) -> Option<&'a T>;
+    /// Returns the first element of a vector, or `None` if it is empty
+    fn head(&self) -> Option<&'a T>;
+    /// Returns all but the first element of a vector
+    fn tail(&self) -> &'a [T];
+    /// Returns all but the first `n' elements of a vector
+    fn tailn(&self, n: uint) -> &'a [T];
+    /// Returns all but the last element of a vector
+    fn init(&self) -> &'a [T];
+    /// Returns all but the last `n' elements of a vector
+    fn initn(&self, n: uint) -> &'a [T];
+    /// Returns the last element of a vector, or `None` if it is empty.
+    fn last(&self) -> Option<&'a T>;
+
+    /// Returns a pointer to the element at the given index, without doing
+    /// bounds checking.
+    unsafe fn unsafe_ref(self, index: uint) -> &'a T;
+
+    /**
+     * Returns an unsafe pointer to the vector's buffer
+     *
+     * The caller must ensure that the vector outlives the pointer this
+     * function returns, or else it will end up pointing to garbage.
+     *
+     * Modifying the vector may cause its buffer to be reallocated, which
+     * would also make any pointers to it invalid.
+     */
+    fn as_ptr(&self) -> *const T;
+
+    /**
+     * Binary search a sorted vector with a comparator function.
+     *
+     * The comparator function should implement an order consistent
+     * with the sort order of the underlying vector, returning an
+     * order code that indicates whether its argument is `Less`,
+     * `Equal` or `Greater` the desired target.
+     *
+     * Returns the index where the comparator returned `Equal`, or `None` if
+     * not found.
+     */
+    fn bsearch(&self, f: |&T| -> Ordering) -> Option<uint>;
+
+    /**
+     * Returns an immutable reference to the first element in this slice
+     * and adjusts the slice in place so that it no longer contains
+     * that element. O(1).
+     *
+     * Equivalent to:
+     *
+     * ```ignore
+     *     if self.len() == 0 { return None }
+     *     let head = &self[0];
+     *     *self = self.slice_from(1);
+     *     Some(head)
+     * ```
+     *
+     * Returns `None` if vector is empty
+     */
+    fn shift_ref(&mut self) -> Option<&'a T>;
+
+    /**
+     * Returns an immutable reference to the last element in this slice
+     * and adjusts the slice in place so that it no longer contains
+     * that element. O(1).
+     *
+     * Equivalent to:
+     *
+     * ```ignore
+     *     if self.len() == 0 { return None; }
+     *     let tail = &self[self.len() - 1];
+     *     *self = self.slice_to(self.len() - 1);
+     *     Some(tail)
+     * ```
+     *
+     * Returns `None` if slice is empty.
+     */
+    fn pop_ref(&mut self) -> Option<&'a T>;
 }
 
-/**
- * Converts a pointer to A into a slice of length 1 (without copying).
- */
-pub fn mut_ref_slice<'a, A>(s: &'a mut A) -> &'a mut [A] {
-    unsafe {
-        let ptr: *const A = transmute(s);
-        transmute(Slice { data: ptr, len: 1 })
+impl<'a,T> ImmutableVector<'a, T> for &'a [T] {
+    #[inline]
+    fn slice(&self, start: uint, end: uint) -> &'a [T] {
+        assert!(start <= end);
+        assert!(end <= self.len());
+        unsafe {
+            transmute(Slice {
+                    data: self.as_ptr().offset(start as int),
+                    len: (end - start)
+                })
+        }
     }
-}
 
-/// An iterator over the slices of a vector separated by elements that
-/// match a predicate function.
-pub struct Splits<'a, T> {
-    v: &'a [T],
-    pred: |t: &T|: 'a -> bool,
-    finished: bool
-}
+    #[inline]
+    fn slice_from(&self, start: uint) -> &'a [T] {
+        self.slice(start, self.len())
+    }
 
-impl<'a, T> Iterator<&'a [T]> for Splits<'a, T> {
     #[inline]
-    fn next(&mut self) -> Option<&'a [T]> {
-        if self.finished { return None; }
+    fn slice_to(&self, end: uint) -> &'a [T] {
+        self.slice(0, end)
+    }
 
-        match self.v.iter().position(|x| (self.pred)(x)) {
-            None => {
-                self.finished = true;
-                Some(self.v)
-            }
-            Some(idx) => {
-                let ret = Some(self.v.slice(0, idx));
-                self.v = self.v.slice(idx + 1, self.v.len());
-                ret
+    #[inline]
+    fn iter(self) -> Items<'a, T> {
+        unsafe {
+            let p = self.as_ptr();
+            if mem::size_of::<T>() == 0 {
+                Items{ptr: p,
+                      end: (p as uint + self.len()) as *const T,
+                      marker: marker::ContravariantLifetime::<'a>}
+            } else {
+                Items{ptr: p,
+                      end: p.offset(self.len() as int),
+                      marker: marker::ContravariantLifetime::<'a>}
             }
         }
     }
 
     #[inline]
-    fn size_hint(&self) -> (uint, Option<uint>) {
-        if self.finished {
-            (0, Some(0))
-        } else {
-            (1, Some(self.v.len() + 1))
+    fn split(self, pred: |&T|: 'a -> bool) -> Splits<'a, T> {
+        Splits {
+            v: self,
+            pred: pred,
+            finished: false
         }
     }
-}
 
-impl<'a, T> DoubleEndedIterator<&'a [T]> for Splits<'a, T> {
     #[inline]
-    fn next_back(&mut self) -> Option<&'a [T]> {
-        if self.finished { return None; }
-
-        match self.v.iter().rposition(|x| (self.pred)(x)) {
-            None => {
-                self.finished = true;
-                Some(self.v)
-            }
-            Some(idx) => {
-                let ret = Some(self.v.slice(idx + 1, self.v.len()));
-                self.v = self.v.slice(0, idx);
-                ret
-            }
+    fn splitn(self, n: uint, pred: |&T|: 'a -> bool) -> SplitsN<'a, T> {
+        SplitsN {
+            iter: self.split(pred),
+            count: n,
+            invert: false
         }
     }
-}
 
-/// An iterator over the slices of a vector separated by elements that
-/// match a predicate function, splitting at most a fixed number of times.
-pub struct SplitsN<'a, T> {
-    iter: Splits<'a, T>,
-    count: uint,
-    invert: bool
-}
-
-impl<'a, T> Iterator<&'a [T]> for SplitsN<'a, T> {
     #[inline]
-    fn next(&mut self) -> Option<&'a [T]> {
-        if self.count == 0 {
-            if self.iter.finished {
-                None
-            } else {
-                self.iter.finished = true;
-                Some(self.iter.v)
-            }
-        } else {
-            self.count -= 1;
-            if self.invert { self.iter.next_back() } else { self.iter.next() }
+    fn rsplitn(self, n: uint, pred: |&T|: 'a -> bool) -> SplitsN<'a, T> {
+        SplitsN {
+            iter: self.split(pred),
+            count: n,
+            invert: true
         }
     }
 
     #[inline]
-    fn size_hint(&self) -> (uint, Option<uint>) {
-        if self.iter.finished {
-            (0, Some(0))
-        } else {
-            (1, Some(cmp::min(self.count, self.iter.v.len()) + 1))
-        }
+    fn windows(self, size: uint) -> Windows<'a, T> {
+        assert!(size != 0);
+        Windows { v: self, size: size }
     }
-}
-
-// Functional utilities
 
-/// An iterator over the (overlapping) slices of length `size` within
-/// a vector.
-#[deriving(Clone)]
-pub struct Windows<'a, T> {
-    v: &'a [T],
-    size: uint
-}
+    #[inline]
+    fn chunks(self, size: uint) -> Chunks<'a, T> {
+        assert!(size != 0);
+        Chunks { v: self, size: size }
+    }
 
-impl<'a, T> Iterator<&'a [T]> for Windows<'a, T> {
     #[inline]
-    fn next(&mut self) -> Option<&'a [T]> {
-        if self.size > self.v.len() {
-            None
-        } else {
-            let ret = Some(self.v.slice(0, self.size));
-            self.v = self.v.slice(1, self.v.len());
-            ret
-        }
+    fn get(&self, index: uint) -> Option<&'a T> {
+        if index < self.len() { Some(&self[index]) } else { None }
     }
 
     #[inline]
-    fn size_hint(&self) -> (uint, Option<uint>) {
-        if self.size > self.v.len() {
-            (0, Some(0))
-        } else {
-            let x = self.v.len() - self.size;
-            (x.saturating_add(1), x.checked_add(&1u))
-        }
+    fn head(&self) -> Option<&'a T> {
+        if self.len() == 0 { None } else { Some(&self[0]) }
     }
-}
 
-/// An iterator over a vector in (non-overlapping) chunks (`size`
-/// elements at a time).
-///
-/// When the vector len is not evenly divided by the chunk size,
-/// the last slice of the iteration will be the remainder.
-#[deriving(Clone)]
-pub struct Chunks<'a, T> {
-    v: &'a [T],
-    size: uint
-}
+    #[inline]
+    fn tail(&self) -> &'a [T] { self.slice(1, self.len()) }
 
-impl<'a, T> Iterator<&'a [T]> for Chunks<'a, T> {
     #[inline]
-    fn next(&mut self) -> Option<&'a [T]> {
-        if self.v.len() == 0 {
-            None
-        } else {
-            let chunksz = cmp::min(self.v.len(), self.size);
-            let (fst, snd) = (self.v.slice_to(chunksz),
-                              self.v.slice_from(chunksz));
-            self.v = snd;
-            Some(fst)
-        }
-    }
+    fn tailn(&self, n: uint) -> &'a [T] { self.slice(n, self.len()) }
 
     #[inline]
-    fn size_hint(&self) -> (uint, Option<uint>) {
-        if self.v.len() == 0 {
-            (0, Some(0))
-        } else {
-            let (n, rem) = div_rem(self.v.len(), self.size);
-            let n = if rem > 0 { n+1 } else { n };
-            (n, Some(n))
-        }
+    fn init(&self) -> &'a [T] {
+        self.slice(0, self.len() - 1)
     }
-}
 
-impl<'a, T> DoubleEndedIterator<&'a [T]> for Chunks<'a, T> {
     #[inline]
-    fn next_back(&mut self) -> Option<&'a [T]> {
-        if self.v.len() == 0 {
-            None
-        } else {
-            let remainder = self.v.len() % self.size;
-            let chunksz = if remainder != 0 { remainder } else { self.size };
-            let (fst, snd) = (self.v.slice_to(self.v.len() - chunksz),
-                              self.v.slice_from(self.v.len() - chunksz));
-            self.v = fst;
-            Some(snd)
-        }
+    fn initn(&self, n: uint) -> &'a [T] {
+        self.slice(0, self.len() - n)
     }
-}
 
-impl<'a, T> RandomAccessIterator<&'a [T]> for Chunks<'a, T> {
     #[inline]
-    fn indexable(&self) -> uint {
-        self.v.len()/self.size + if self.v.len() % self.size != 0 { 1 } else { 0 }
+    fn last(&self) -> Option<&'a T> {
+            if self.len() == 0 { None } else { Some(&self[self.len() - 1]) }
     }
 
     #[inline]
-    fn idx(&mut self, index: uint) -> Option<&'a [T]> {
-        if index < self.indexable() {
-            let lo = index * self.size;
-            let mut hi = lo + self.size;
-            if hi < lo || hi > self.v.len() { hi = self.v.len(); }
-
-            Some(self.v.slice(lo, hi))
-        } else {
-            None
-        }
+    unsafe fn unsafe_ref(self, index: uint) -> &'a T {
+        transmute(self.repr().data.offset(index as int))
     }
-}
 
-// Equality
+    #[inline]
+    fn as_ptr(&self) -> *const T {
+        self.repr().data
+    }
 
-#[allow(missing_doc)]
-pub mod traits {
-    use super::*;
 
-    use cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering, Equiv};
-    use iter::order;
-    use collections::Collection;
-    use option::Option;
+    fn bsearch(&self, f: |&T| -> Ordering) -> Option<uint> {
+        let mut base : uint = 0;
+        let mut lim : uint = self.len();
 
-    impl<'a,T:PartialEq> PartialEq for &'a [T] {
-        fn eq(&self, other: & &'a [T]) -> bool {
-            self.len() == other.len() &&
-                order::eq(self.iter(), other.iter())
-        }
-        fn ne(&self, other: & &'a [T]) -> bool {
-            self.len() != other.len() ||
-                order::ne(self.iter(), other.iter())
+        while lim != 0 {
+            let ix = base + (lim >> 1);
+            match f(&self[ix]) {
+                Equal => return Some(ix),
+                Less => {
+                    base = ix + 1;
+                    lim -= 1;
+                }
+                Greater => ()
+            }
+            lim >>= 1;
         }
+        return None;
     }
 
-    impl<'a,T:Eq> Eq for &'a [T] {}
-
-    impl<'a,T:PartialEq, V: Vector<T>> Equiv<V> for &'a [T] {
-        #[inline]
-        fn equiv(&self, other: &V) -> bool { self.as_slice() == other.as_slice() }
-    }
-
-    impl<'a,T:Ord> Ord for &'a [T] {
-        fn cmp(&self, other: & &'a [T]) -> Ordering {
-            order::cmp(self.iter(), other.iter())
+    fn shift_ref(&mut self) -> Option<&'a T> {
+        unsafe {
+            let s: &mut Slice<T> = transmute(self);
+            match raw::shift_ptr(s) {
+                Some(p) => Some(&*p),
+                None => None
+            }
         }
     }
 
-    impl<'a, T: PartialOrd> PartialOrd for &'a [T] {
-        #[inline]
-        fn partial_cmp(&self, other: &&'a [T]) -> Option<Ordering> {
-            order::partial_cmp(self.iter(), other.iter())
-        }
-        #[inline]
-        fn lt(&self, other: & &'a [T]) -> bool {
-            order::lt(self.iter(), other.iter())
-        }
-        #[inline]
-        fn le(&self, other: & &'a [T]) -> bool {
-            order::le(self.iter(), other.iter())
-        }
-        #[inline]
-        fn ge(&self, other: & &'a [T]) -> bool {
-            order::ge(self.iter(), other.iter())
-        }
-        #[inline]
-        fn gt(&self, other: & &'a [T]) -> bool {
-            order::gt(self.iter(), other.iter())
+    fn pop_ref(&mut self) -> Option<&'a T> {
+        unsafe {
+            let s: &mut Slice<T> = transmute(self);
+            match raw::pop_ptr(s) {
+                Some(p) => Some(&*p),
+                None => None
+            }
         }
     }
 }
 
-/// Any vector that can be represented as a slice.
-pub trait Vector<T> {
-    /// Work with `self` as a slice.
-    fn as_slice<'a>(&'a self) -> &'a [T];
-}
-
-impl<'a,T> Vector<T> for &'a [T] {
-    #[inline(always)]
-    fn as_slice<'a>(&'a self) -> &'a [T] { *self }
-}
-
-impl<'a, T> Collection for &'a [T] {
-    /// Returns the length of a vector
-    #[inline]
-    fn len(&self) -> uint {
-        self.repr().len
-    }
-}
+/// Extension methods for vectors such that their elements are
+/// mutable.
+pub trait MutableVector<'a, T> {
+    /// Returns a mutable reference to the element at the given index,
+    /// or `None` if the index is out of bounds
+    fn get_mut(self, index: uint) -> Option<&'a mut T>;
+    /// Work with `self` as a mut slice.
+    /// Primarily intended for getting a &mut [T] from a [T, ..N].
+    fn as_mut_slice(self) -> &'a mut [T];
 
-/// Extension methods for vectors
-pub trait ImmutableVector<'a, T> {
-    /**
-     * Returns a slice of self spanning the interval [`start`, `end`).
-     *
-     * Fails when the slice (or part of it) is outside the bounds of self,
-     * or when `start` > `end`.
-     */
-    fn slice(&self, start: uint, end: uint) -> &'a [T];
+    /// Return a slice that points into another slice.
+    fn mut_slice(self, start: uint, end: uint) -> &'a mut [T];
 
     /**
      * Returns a slice of self from `start` to the end of the vec.
      *
      * Fails when `start` points outside the bounds of self.
      */
-    fn slice_from(&self, start: uint) -> &'a [T];
+    fn mut_slice_from(self, start: uint) -> &'a mut [T];
 
     /**
      * Returns a slice of self from the start of the vec to `end`.
      *
      * Fails when `end` points outside the bounds of self.
      */
-    fn slice_to(&self, end: uint) -> &'a [T];
-    /// Returns an iterator over the vector
-    fn iter(self) -> Items<'a, T>;
-    /// Returns an iterator over the subslices of the vector which are
-    /// separated by elements that match `pred`.  The matched element
-    /// is not contained in the subslices.
-    fn split(self, pred: |&T|: 'a -> bool) -> Splits<'a, T>;
-    /// Returns an iterator over the subslices of the vector which are
-    /// separated by elements that match `pred`, limited to splitting
-    /// at most `n` times.  The matched element is not contained in
-    /// the subslices.
-    fn splitn(self, n: uint, pred: |&T|: 'a -> bool) -> SplitsN<'a, T>;
-    /// Returns an iterator over the subslices of the vector which are
-    /// separated by elements that match `pred` limited to splitting
-    /// at most `n` times. This starts at the end of the vector and
-    /// works backwards.  The matched element is not contained in the
-    /// subslices.
-    fn rsplitn(self,  n: uint, pred: |&T|: 'a -> bool) -> SplitsN<'a, T>;
+    fn mut_slice_to(self, end: uint) -> &'a mut [T];
+
+    /// Returns an iterator that allows modifying each value
+    fn mut_iter(self) -> MutItems<'a, T>;
+
+    /// Returns a mutable pointer to the last item in the vector.
+    fn mut_last(self) -> Option<&'a mut T>;
+
+    /// Returns an iterator over the mutable subslices of the vector
+    /// which are separated by elements that match `pred`.  The
+    /// matched element is not contained in the subslices.
+    fn mut_split(self, pred: |&T|: 'a -> bool) -> MutSplits<'a, T>;
 
     /**
-     * Returns an iterator over all contiguous windows of length
-     * `size`. The windows overlap. If the vector is shorter than
-     * `size`, the iterator returns no values.
-     *
-     * # Failure
-     *
-     * Fails if `size` is 0.
-     *
-     * # Example
-     *
-     * Print the adjacent pairs of a vector (i.e. `[1,2]`, `[2,3]`,
-     * `[3,4]`):
-     *
-     * ```rust
-     * let v = &[1i, 2, 3, 4];
-     * for win in v.windows(2) {
-     *     println!("{}", win);
-     * }
-     * ```
-     *
-     */
-    fn windows(self, size: uint) -> Windows<'a, T>;
-    /**
-     *
-     * Returns an iterator over `size` elements of the vector at a
-     * time. The chunks do not overlap. If `size` does not divide the
+     * Returns an iterator over `size` elements of the vector at a time.
+     * The chunks are mutable and do not overlap. If `size` does not divide the
      * length of the vector, then the last chunk will not have length
      * `size`.
      *
      * # Failure
      *
      * Fails if `size` is 0.
-     *
-     * # Example
-     *
-     * Print the vector two elements at a time (i.e. `[1,2]`,
-     * `[3,4]`, `[5]`):
-     *
-     * ```rust
-     * let v = &[1i, 2, 3, 4, 5];
-     * for win in v.chunks(2) {
-     *     println!("{}", win);
-     * }
-     * ```
-     *
-     */
-    fn chunks(self, size: uint) -> Chunks<'a, T>;
-
-    /// Returns the element of a vector at the given index, or `None` if the
-    /// index is out of bounds
-    fn get(&self, index: uint) -> Option<&'a T>;
-    /// Returns the first element of a vector, or `None` if it is empty
-    fn head(&self) -> Option<&'a T>;
-    /// Returns all but the first element of a vector
-    fn tail(&self) -> &'a [T];
-    /// Returns all but the first `n' elements of a vector
-    fn tailn(&self, n: uint) -> &'a [T];
-    /// Returns all but the last element of a vector
-    fn init(&self) -> &'a [T];
-    /// Returns all but the last `n' elements of a vector
-    fn initn(&self, n: uint) -> &'a [T];
-    /// Returns the last element of a vector, or `None` if it is empty.
-    fn last(&self) -> Option<&'a T>;
-
-    /// Returns a pointer to the element at the given index, without doing
-    /// bounds checking.
-    unsafe fn unsafe_ref(self, index: uint) -> &'a T;
-
-    /**
-     * Returns an unsafe pointer to the vector's buffer
-     *
-     * The caller must ensure that the vector outlives the pointer this
-     * function returns, or else it will end up pointing to garbage.
-     *
-     * Modifying the vector may cause its buffer to be reallocated, which
-     * would also make any pointers to it invalid.
-     */
-    fn as_ptr(&self) -> *const T;
-
-    /**
-     * Binary search a sorted vector with a comparator function.
-     *
-     * The comparator function should implement an order consistent
-     * with the sort order of the underlying vector, returning an
-     * order code that indicates whether its argument is `Less`,
-     * `Equal` or `Greater` the desired target.
-     *
-     * Returns the index where the comparator returned `Equal`, or `None` if
-     * not found.
      */
-    fn bsearch(&self, f: |&T| -> Ordering) -> Option<uint>;
+    fn mut_chunks(self, chunk_size: uint) -> MutChunks<'a, T>;
 
     /**
-     * Returns an immutable reference to the first element in this slice
+     * Returns a mutable reference to the first element in this slice
      * and adjusts the slice in place so that it no longer contains
      * that element. O(1).
      *
      * Equivalent to:
      *
      * ```ignore
-     *     if self.len() == 0 { return None }
-     *     let head = &self[0];
-     *     *self = self.slice_from(1);
+     *     if self.len() == 0 { return None; }
+     *     let head = &mut self[0];
+     *     *self = self.mut_slice_from(1);
      *     Some(head)
      * ```
      *
-     * Returns `None` if vector is empty
+     * Returns `None` if slice is empty
      */
-    fn shift_ref(&mut self) -> Option<&'a T>;
+    fn mut_shift_ref(&mut self) -> Option<&'a mut T>;
 
     /**
-     * Returns an immutable reference to the last element in this slice
+     * Returns a mutable reference to the last element in this slice
      * and adjusts the slice in place so that it no longer contains
      * that element. O(1).
      *
@@ -483,174 +461,282 @@ pub trait ImmutableVector<'a, T> {
      *
      * ```ignore
      *     if self.len() == 0 { return None; }
-     *     let tail = &self[self.len() - 1];
-     *     *self = self.slice_to(self.len() - 1);
+     *     let tail = &mut self[self.len() - 1];
+     *     *self = self.mut_slice_to(self.len() - 1);
      *     Some(tail)
      * ```
      *
      * Returns `None` if slice is empty.
      */
-    fn pop_ref(&mut self) -> Option<&'a T>;
-}
-
-impl<'a,T> ImmutableVector<'a, T> for &'a [T] {
-    #[inline]
-    fn slice(&self, start: uint, end: uint) -> &'a [T] {
-        assert!(start <= end);
-        assert!(end <= self.len());
-        unsafe {
-            transmute(Slice {
-                    data: self.as_ptr().offset(start as int),
-                    len: (end - start)
-                })
-        }
-    }
+    fn mut_pop_ref(&mut self) -> Option<&'a mut T>;
 
-    #[inline]
-    fn slice_from(&self, start: uint) -> &'a [T] {
-        self.slice(start, self.len())
-    }
+    /// Swaps two elements in a vector.
+    ///
+    /// Fails if `a` or `b` are out of bounds.
+    ///
+    /// # Arguments
+    ///
+    /// * a - The index of the first element
+    /// * b - The index of the second element
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// let mut v = ["a", "b", "c", "d"];
+    /// v.swap(1, 3);
+    /// assert!(v == ["a", "d", "c", "b"]);
+    /// ```
+    fn swap(self, a: uint, b: uint);
 
-    #[inline]
-    fn slice_to(&self, end: uint) -> &'a [T] {
-        self.slice(0, end)
-    }
 
-    #[inline]
-    fn iter(self) -> Items<'a, T> {
-        unsafe {
-            let p = self.as_ptr();
-            if mem::size_of::<T>() == 0 {
-                Items{ptr: p,
-                      end: (p as uint + self.len()) as *const T,
-                      marker: marker::ContravariantLifetime::<'a>}
-            } else {
-                Items{ptr: p,
-                      end: p.offset(self.len() as int),
-                      marker: marker::ContravariantLifetime::<'a>}
-            }
-        }
-    }
+    /// Divides one `&mut` into two at an index.
+    ///
+    /// The first will contain all indices from `[0, mid)` (excluding
+    /// the index `mid` itself) and the second will contain all
+    /// indices from `[mid, len)` (excluding the index `len` itself).
+    ///
+    /// Fails if `mid > len`.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// let mut v = [1i, 2, 3, 4, 5, 6];
+    ///
+    /// // scoped to restrict the lifetime of the borrows
+    /// {
+    ///    let (left, right) = v.mut_split_at(0);
+    ///    assert!(left == &mut []);
+    ///    assert!(right == &mut [1i, 2, 3, 4, 5, 6]);
+    /// }
+    ///
+    /// {
+    ///     let (left, right) = v.mut_split_at(2);
+    ///     assert!(left == &mut [1i, 2]);
+    ///     assert!(right == &mut [3i, 4, 5, 6]);
+    /// }
+    ///
+    /// {
+    ///     let (left, right) = v.mut_split_at(6);
+    ///     assert!(left == &mut [1i, 2, 3, 4, 5, 6]);
+    ///     assert!(right == &mut []);
+    /// }
+    /// ```
+    fn mut_split_at(self, mid: uint) -> (&'a mut [T], &'a mut [T]);
 
-    #[inline]
-    fn split(self, pred: |&T|: 'a -> bool) -> Splits<'a, T> {
-        Splits {
-            v: self,
-            pred: pred,
-            finished: false
-        }
-    }
+    /// Reverse the order of elements in a vector, in place.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// let mut v = [1i, 2, 3];
+    /// v.reverse();
+    /// assert!(v == [3i, 2, 1]);
+    /// ```
+    fn reverse(self);
 
-    #[inline]
-    fn splitn(self, n: uint, pred: |&T|: 'a -> bool) -> SplitsN<'a, T> {
-        SplitsN {
-            iter: self.split(pred),
-            count: n,
-            invert: false
-        }
-    }
+    /// Returns an unsafe mutable pointer to the element in index
+    unsafe fn unsafe_mut_ref(self, index: uint) -> &'a mut T;
 
+    /// Return an unsafe mutable pointer to the vector's buffer.
+    ///
+    /// The caller must ensure that the vector outlives the pointer this
+    /// function returns, or else it will end up pointing to garbage.
+    ///
+    /// Modifying the vector may cause its buffer to be reallocated, which
+    /// would also make any pointers to it invalid.
     #[inline]
-    fn rsplitn(self, n: uint, pred: |&T|: 'a -> bool) -> SplitsN<'a, T> {
-        SplitsN {
-            iter: self.split(pred),
-            count: n,
-            invert: true
-        }
-    }
+    fn as_mut_ptr(self) -> *mut T;
 
-    #[inline]
-    fn windows(self, size: uint) -> Windows<'a, T> {
-        assert!(size != 0);
-        Windows { v: self, size: size }
-    }
+    /// Unsafely sets the element in index to the value.
+    ///
+    /// This performs no bounds checks, and it is undefined behaviour
+    /// if `index` is larger than the length of `self`. However, it
+    /// does run the destructor at `index`. It is equivalent to
+    /// `self[index] = val`.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// let mut v = ["foo".to_string(), "bar".to_string(), "baz".to_string()];
+    ///
+    /// unsafe {
+    ///     // `"baz".to_string()` is deallocated.
+    ///     v.unsafe_set(2, "qux".to_string());
+    ///
+    ///     // Out of bounds: could cause a crash, or overwriting
+    ///     // other data, or something else.
+    ///     // v.unsafe_set(10, "oops".to_string());
+    /// }
+    /// ```
+    unsafe fn unsafe_set(self, index: uint, val: T);
 
-    #[inline]
-    fn chunks(self, size: uint) -> Chunks<'a, T> {
-        assert!(size != 0);
-        Chunks { v: self, size: size }
-    }
+    /// Unchecked vector index assignment.  Does not drop the
+    /// old value and hence is only suitable when the vector
+    /// is newly allocated.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// let mut v = ["foo".to_string(), "bar".to_string()];
+    ///
+    /// // memory leak! `"bar".to_string()` is not deallocated.
+    /// unsafe { v.init_elem(1, "baz".to_string()); }
+    /// ```
+    unsafe fn init_elem(self, i: uint, val: T);
 
-    #[inline]
-    fn get(&self, index: uint) -> Option<&'a T> {
-        if index < self.len() { Some(&self[index]) } else { None }
-    }
+    /// Copies raw bytes from `src` to `self`.
+    ///
+    /// This does not run destructors on the overwritten elements, and
+    /// ignores move semantics. `self` and `src` must not
+    /// overlap. Fails if `self` is shorter than `src`.
+    unsafe fn copy_memory(self, src: &[T]);
+}
 
+impl<'a,T> MutableVector<'a, T> for &'a mut [T] {
     #[inline]
-    fn head(&self) -> Option<&'a T> {
-        if self.len() == 0 { None } else { Some(&self[0]) }
+    fn get_mut(self, index: uint) -> Option<&'a mut T> {
+        if index < self.len() { Some(&mut self[index]) } else { None }
     }
 
     #[inline]
-    fn tail(&self) -> &'a [T] { self.slice(1, self.len()) }
+    fn as_mut_slice(self) -> &'a mut [T] { self }
 
-    #[inline]
-    fn tailn(&self, n: uint) -> &'a [T] { self.slice(n, self.len()) }
+    fn mut_slice(self, start: uint, end: uint) -> &'a mut [T] {
+        assert!(start <= end);
+        assert!(end <= self.len());
+        unsafe {
+            transmute(Slice {
+                    data: self.as_mut_ptr().offset(start as int) as *const T,
+                    len: (end - start)
+                })
+        }
+    }
 
     #[inline]
-    fn init(&self) -> &'a [T] {
-        self.slice(0, self.len() - 1)
+    fn mut_slice_from(self, start: uint) -> &'a mut [T] {
+        let len = self.len();
+        self.mut_slice(start, len)
     }
 
     #[inline]
-    fn initn(&self, n: uint) -> &'a [T] {
-        self.slice(0, self.len() - n)
+    fn mut_slice_to(self, end: uint) -> &'a mut [T] {
+        self.mut_slice(0, end)
     }
 
     #[inline]
-    fn last(&self) -> Option<&'a T> {
-            if self.len() == 0 { None } else { Some(&self[self.len() - 1]) }
+    fn mut_split_at(self, mid: uint) -> (&'a mut [T], &'a mut [T]) {
+        unsafe {
+            let len = self.len();
+            let self2: &'a mut [T] = mem::transmute_copy(&self);
+            (self.mut_slice(0, mid), self2.mut_slice(mid, len))
+        }
     }
 
     #[inline]
-    unsafe fn unsafe_ref(self, index: uint) -> &'a T {
-        transmute(self.repr().data.offset(index as int))
+    fn mut_iter(self) -> MutItems<'a, T> {
+        unsafe {
+            let p = self.as_mut_ptr();
+            if mem::size_of::<T>() == 0 {
+                MutItems{ptr: p,
+                         end: (p as uint + self.len()) as *mut T,
+                         marker: marker::ContravariantLifetime::<'a>,
+                         marker2: marker::NoCopy}
+            } else {
+                MutItems{ptr: p,
+                         end: p.offset(self.len() as int),
+                         marker: marker::ContravariantLifetime::<'a>,
+                         marker2: marker::NoCopy}
+            }
+        }
     }
 
     #[inline]
-    fn as_ptr(&self) -> *const T {
-        self.repr().data
+    fn mut_last(self) -> Option<&'a mut T> {
+        let len = self.len();
+        if len == 0 { return None; }
+        Some(&mut self[len - 1])
     }
 
+    #[inline]
+    fn mut_split(self, pred: |&T|: 'a -> bool) -> MutSplits<'a, T> {
+        MutSplits { v: self, pred: pred, finished: false }
+    }
 
-    fn bsearch(&self, f: |&T| -> Ordering) -> Option<uint> {
-        let mut base : uint = 0;
-        let mut lim : uint = self.len();
-
-        while lim != 0 {
-            let ix = base + (lim >> 1);
-            match f(&self[ix]) {
-                Equal => return Some(ix),
-                Less => {
-                    base = ix + 1;
-                    lim -= 1;
-                }
-                Greater => ()
-            }
-            lim >>= 1;
-        }
-        return None;
+    #[inline]
+    fn mut_chunks(self, chunk_size: uint) -> MutChunks<'a, T> {
+        assert!(chunk_size > 0);
+        MutChunks { v: self, chunk_size: chunk_size }
     }
 
-    fn shift_ref(&mut self) -> Option<&'a T> {
+    fn mut_shift_ref(&mut self) -> Option<&'a mut T> {
         unsafe {
             let s: &mut Slice<T> = transmute(self);
             match raw::shift_ptr(s) {
-                Some(p) => Some(&*p),
-                None => None
+                // FIXME #13933: this `&` -> `&mut` cast is a little
+                // dubious
+                Some(p) => Some(&mut *(p as *mut _)),
+                None => None,
             }
         }
     }
 
-    fn pop_ref(&mut self) -> Option<&'a T> {
+    fn mut_pop_ref(&mut self) -> Option<&'a mut T> {
         unsafe {
             let s: &mut Slice<T> = transmute(self);
             match raw::pop_ptr(s) {
-                Some(p) => Some(&*p),
-                None => None
+                // FIXME #13933: this `&` -> `&mut` cast is a little
+                // dubious
+                Some(p) => Some(&mut *(p as *mut _)),
+                None => None,
             }
         }
     }
+
+    fn swap(self, a: uint, b: uint) {
+        unsafe {
+            // Can't take two mutable loans from one vector, so instead just cast
+            // them to their raw pointers to do the swap
+            let pa: *mut T = &mut self[a];
+            let pb: *mut T = &mut self[b];
+            ptr::swap(pa, pb);
+        }
+    }
+
+    fn reverse(self) {
+        let mut i: uint = 0;
+        let ln = self.len();
+        while i < ln / 2 {
+            self.swap(i, ln - i - 1);
+            i += 1;
+        }
+    }
+
+    #[inline]
+    unsafe fn unsafe_mut_ref(self, index: uint) -> &'a mut T {
+        transmute((self.repr().data as *mut T).offset(index as int))
+    }
+
+    #[inline]
+    fn as_mut_ptr(self) -> *mut T {
+        self.repr().data as *mut T
+    }
+
+    #[inline]
+    unsafe fn unsafe_set(self, index: uint, val: T) {
+        *self.unsafe_mut_ref(index) = val;
+    }
+
+    #[inline]
+    unsafe fn init_elem(self, i: uint, val: T) {
+        ptr::write(&mut (*self.as_mut_ptr().offset(i as int)), val);
+    }
+
+    #[inline]
+    unsafe fn copy_memory(self, src: &[T]) {
+        let len_src = src.len();
+        assert!(self.len() >= len_src);
+        ptr::copy_nonoverlapping_memory(self.as_mut_ptr(), src.as_ptr(), len_src)
+    }
 }
 
 /// Extension methods for vectors contain `PartialEq` elements.
@@ -716,395 +802,523 @@ fn bsearch_elem(&self, x: &T) -> Option<uint> {
     }
 }
 
-/// Extension methods for vectors such that their elements are
-/// mutable.
-pub trait MutableVector<'a, T> {
-    /// Returns a mutable reference to the element at the given index,
-    /// or `None` if the index is out of bounds
-    fn get_mut(self, index: uint) -> Option<&'a mut T>;
-    /// Work with `self` as a mut slice.
-    /// Primarily intended for getting a &mut [T] from a [T, ..N].
-    fn as_mut_slice(self) -> &'a mut [T];
+/// Trait for &[T] where T is Cloneable
+pub trait MutableCloneableVector<T> {
+    /// Copies as many elements from `src` as it can into `self` (the
+    /// shorter of `self.len()` and `src.len()`). Returns the number
+    /// of elements copied.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use std::slice::MutableCloneableVector;
+    ///
+    /// let mut dst = [0i, 0, 0];
+    /// let src = [1i, 2];
+    ///
+    /// assert!(dst.copy_from(src) == 2);
+    /// assert!(dst == [1, 2, 0]);
+    ///
+    /// let src2 = [3i, 4, 5, 6];
+    /// assert!(dst.copy_from(src2) == 3);
+    /// assert!(dst == [3i, 4, 5]);
+    /// ```
+    fn copy_from(self, &[T]) -> uint;
+}
 
-    /// Return a slice that points into another slice.
-    fn mut_slice(self, start: uint, end: uint) -> &'a mut [T];
+impl<'a, T:Clone> MutableCloneableVector<T> for &'a mut [T] {
+    #[inline]
+    fn copy_from(self, src: &[T]) -> uint {
+        for (a, b) in self.mut_iter().zip(src.iter()) {
+            a.clone_from(b);
+        }
+        cmp::min(self.len(), src.len())
+    }
+}
 
-    /**
-     * Returns a slice of self from `start` to the end of the vec.
-     *
-     * Fails when `start` points outside the bounds of self.
-     */
-    fn mut_slice_from(self, start: uint) -> &'a mut [T];
 
-    /**
-     * Returns a slice of self from the start of the vec to `end`.
-     *
-     * Fails when `end` points outside the bounds of self.
-     */
-    fn mut_slice_to(self, end: uint) -> &'a mut [T];
 
-    /// Returns an iterator that allows modifying each value
-    fn mut_iter(self) -> MutItems<'a, T>;
 
-    /// Returns a mutable pointer to the last item in the vector.
-    fn mut_last(self) -> Option<&'a mut T>;
+//
+// Common traits
+//
 
-    /// Returns an iterator over the mutable subslices of the vector
-    /// which are separated by elements that match `pred`.  The
-    /// matched element is not contained in the subslices.
-    fn mut_split(self, pred: |&T|: 'a -> bool) -> MutSplits<'a, T>;
+/// Any vector that can be represented as a slice.
+pub trait Vector<T> {
+    /// Work with `self` as a slice.
+    fn as_slice<'a>(&'a self) -> &'a [T];
+}
 
-    /**
-     * Returns an iterator over `size` elements of the vector at a time.
-     * The chunks are mutable and do not overlap. If `size` does not divide the
-     * length of the vector, then the last chunk will not have length
-     * `size`.
-     *
-     * # Failure
-     *
-     * Fails if `size` is 0.
-     */
-    fn mut_chunks(self, chunk_size: uint) -> MutChunks<'a, T>;
+impl<'a,T> Vector<T> for &'a [T] {
+    #[inline(always)]
+    fn as_slice<'a>(&'a self) -> &'a [T] { *self }
+}
 
-    /**
-     * Returns a mutable reference to the first element in this slice
-     * and adjusts the slice in place so that it no longer contains
-     * that element. O(1).
-     *
-     * Equivalent to:
-     *
-     * ```ignore
-     *     if self.len() == 0 { return None; }
-     *     let head = &mut self[0];
-     *     *self = self.mut_slice_from(1);
-     *     Some(head)
-     * ```
-     *
-     * Returns `None` if slice is empty
-     */
-    fn mut_shift_ref(&mut self) -> Option<&'a mut T>;
+impl<'a, T> Collection for &'a [T] {
+    /// Returns the length of a vector
+    #[inline]
+    fn len(&self) -> uint {
+        self.repr().len
+    }
+}
 
-    /**
-     * Returns a mutable reference to the last element in this slice
-     * and adjusts the slice in place so that it no longer contains
-     * that element. O(1).
-     *
-     * Equivalent to:
-     *
-     * ```ignore
-     *     if self.len() == 0 { return None; }
-     *     let tail = &mut self[self.len() - 1];
-     *     *self = self.mut_slice_to(self.len() - 1);
-     *     Some(tail)
-     * ```
-     *
-     * Returns `None` if slice is empty.
-     */
-    fn mut_pop_ref(&mut self) -> Option<&'a mut T>;
+impl<'a, T> Default for &'a [T] {
+    fn default() -> &'a [T] { &[] }
+}
 
-    /// Swaps two elements in a vector.
-    ///
-    /// Fails if `a` or `b` are out of bounds.
-    ///
-    /// # Arguments
-    ///
-    /// * a - The index of the first element
-    /// * b - The index of the second element
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// let mut v = ["a", "b", "c", "d"];
-    /// v.swap(1, 3);
-    /// assert!(v == ["a", "d", "c", "b"]);
-    /// ```
-    fn swap(self, a: uint, b: uint);
 
 
-    /// Divides one `&mut` into two at an index.
-    ///
-    /// The first will contain all indices from `[0, mid)` (excluding
-    /// the index `mid` itself) and the second will contain all
-    /// indices from `[mid, len)` (excluding the index `len` itself).
-    ///
-    /// Fails if `mid > len`.
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// let mut v = [1i, 2, 3, 4, 5, 6];
-    ///
-    /// // scoped to restrict the lifetime of the borrows
-    /// {
-    ///    let (left, right) = v.mut_split_at(0);
-    ///    assert!(left == &mut []);
-    ///    assert!(right == &mut [1i, 2, 3, 4, 5, 6]);
-    /// }
-    ///
-    /// {
-    ///     let (left, right) = v.mut_split_at(2);
-    ///     assert!(left == &mut [1i, 2]);
-    ///     assert!(right == &mut [3i, 4, 5, 6]);
-    /// }
-    ///
-    /// {
-    ///     let (left, right) = v.mut_split_at(6);
-    ///     assert!(left == &mut [1i, 2, 3, 4, 5, 6]);
-    ///     assert!(right == &mut []);
-    /// }
-    /// ```
-    fn mut_split_at(self, mid: uint) -> (&'a mut [T], &'a mut [T]);
 
-    /// Reverse the order of elements in a vector, in place.
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// let mut v = [1i, 2, 3];
-    /// v.reverse();
-    /// assert!(v == [3i, 2, 1]);
-    /// ```
-    fn reverse(self);
+//
+// Iterators
+//
 
-    /// Returns an unsafe mutable pointer to the element in index
-    unsafe fn unsafe_mut_ref(self, index: uint) -> &'a mut T;
+// The shared definition of the `Item` and `MutItems` iterators
+macro_rules! iterator {
+    (struct $name:ident -> $ptr:ty, $elem:ty) => {
+        impl<'a, T> Iterator<$elem> for $name<'a, T> {
+            #[inline]
+            fn next(&mut self) -> Option<$elem> {
+                // could be implemented with slices, but this avoids bounds checks
+                unsafe {
+                    if self.ptr == self.end {
+                        None
+                    } else {
+                        let old = self.ptr;
+                        self.ptr = if mem::size_of::<T>() == 0 {
+                            // purposefully don't use 'ptr.offset' because for
+                            // vectors with 0-size elements this would return the
+                            // same pointer.
+                            transmute(self.ptr as uint + 1)
+                        } else {
+                            self.ptr.offset(1)
+                        };
 
-    /// Return an unsafe mutable pointer to the vector's buffer.
-    ///
-    /// The caller must ensure that the vector outlives the pointer this
-    /// function returns, or else it will end up pointing to garbage.
-    ///
-    /// Modifying the vector may cause its buffer to be reallocated, which
-    /// would also make any pointers to it invalid.
+                        Some(transmute(old))
+                    }
+                }
+            }
+
+            #[inline]
+            fn size_hint(&self) -> (uint, Option<uint>) {
+                let diff = (self.end as uint) - (self.ptr as uint);
+                let size = mem::size_of::<T>();
+                let exact = diff / (if size == 0 {1} else {size});
+                (exact, Some(exact))
+            }
+        }
+
+        impl<'a, T> DoubleEndedIterator<$elem> for $name<'a, T> {
+            #[inline]
+            fn next_back(&mut self) -> Option<$elem> {
+                // could be implemented with slices, but this avoids bounds checks
+                unsafe {
+                    if self.end == self.ptr {
+                        None
+                    } else {
+                        self.end = if mem::size_of::<T>() == 0 {
+                            // See above for why 'ptr.offset' isn't used
+                            transmute(self.end as uint - 1)
+                        } else {
+                            self.end.offset(-1)
+                        };
+                        Some(transmute(self.end))
+                    }
+                }
+            }
+        }
+    }
+}
+
+/// Immutable slice iterator
+pub struct Items<'a, T> {
+    ptr: *const T,
+    end: *const T,
+    marker: marker::ContravariantLifetime<'a>
+}
+
+iterator!{struct Items -> *const T, &'a T}
+
+impl<'a, T> ExactSize<&'a T> for Items<'a, T> {}
+
+impl<'a, T> Clone for Items<'a, T> {
+    fn clone(&self) -> Items<'a, T> { *self }
+}
+
+impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> {
     #[inline]
-    fn as_mut_ptr(self) -> *mut T;
+    fn indexable(&self) -> uint {
+        let (exact, _) = self.size_hint();
+        exact
+    }
 
-    /// Unsafely sets the element in index to the value.
-    ///
-    /// This performs no bounds checks, and it is undefined behaviour
-    /// if `index` is larger than the length of `self`. However, it
-    /// does run the destructor at `index`. It is equivalent to
-    /// `self[index] = val`.
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// let mut v = ["foo".to_string(), "bar".to_string(), "baz".to_string()];
-    ///
-    /// unsafe {
-    ///     // `"baz".to_string()` is deallocated.
-    ///     v.unsafe_set(2, "qux".to_string());
-    ///
-    ///     // Out of bounds: could cause a crash, or overwriting
-    ///     // other data, or something else.
-    ///     // v.unsafe_set(10, "oops".to_string());
-    /// }
-    /// ```
-    unsafe fn unsafe_set(self, index: uint, val: T);
+    #[inline]
+    fn idx(&mut self, index: uint) -> Option<&'a T> {
+        unsafe {
+            if index < self.indexable() {
+                transmute(self.ptr.offset(index as int))
+            } else {
+                None
+            }
+        }
+    }
+}
 
-    /// Unchecked vector index assignment.  Does not drop the
-    /// old value and hence is only suitable when the vector
-    /// is newly allocated.
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// let mut v = ["foo".to_string(), "bar".to_string()];
-    ///
-    /// // memory leak! `"bar".to_string()` is not deallocated.
-    /// unsafe { v.init_elem(1, "baz".to_string()); }
-    /// ```
-    unsafe fn init_elem(self, i: uint, val: T);
+/// Mutable slice iterator
+pub struct MutItems<'a, T> {
+    ptr: *mut T,
+    end: *mut T,
+    marker: marker::ContravariantLifetime<'a>,
+    marker2: marker::NoCopy
+}
 
-    /// Copies raw bytes from `src` to `self`.
-    ///
-    /// This does not run destructors on the overwritten elements, and
-    /// ignores move semantics. `self` and `src` must not
-    /// overlap. Fails if `self` is shorter than `src`.
-    unsafe fn copy_memory(self, src: &[T]);
+iterator!{struct MutItems -> *mut T, &'a mut T}
+
+impl<'a, T> ExactSize<&'a mut T> for MutItems<'a, T> {}
+
+/// An iterator over the slices of a vector separated by elements that
+/// match a predicate function.
+pub struct Splits<'a, T> {
+    v: &'a [T],
+    pred: |t: &T|: 'a -> bool,
+    finished: bool
 }
 
-impl<'a,T> MutableVector<'a, T> for &'a mut [T] {
+impl<'a, T> Iterator<&'a [T]> for Splits<'a, T> {
     #[inline]
-    fn get_mut(self, index: uint) -> Option<&'a mut T> {
-        if index < self.len() { Some(&mut self[index]) } else { None }
+    fn next(&mut self) -> Option<&'a [T]> {
+        if self.finished { return None; }
+
+        match self.v.iter().position(|x| (self.pred)(x)) {
+            None => {
+                self.finished = true;
+                Some(self.v)
+            }
+            Some(idx) => {
+                let ret = Some(self.v.slice(0, idx));
+                self.v = self.v.slice(idx + 1, self.v.len());
+                ret
+            }
+        }
     }
 
     #[inline]
-    fn as_mut_slice(self) -> &'a mut [T] { self }
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        if self.finished {
+            (0, Some(0))
+        } else {
+            (1, Some(self.v.len() + 1))
+        }
+    }
+}
 
-    fn mut_slice(self, start: uint, end: uint) -> &'a mut [T] {
-        assert!(start <= end);
-        assert!(end <= self.len());
-        unsafe {
-            transmute(Slice {
-                    data: self.as_mut_ptr().offset(start as int) as *const T,
-                    len: (end - start)
-                })
+impl<'a, T> DoubleEndedIterator<&'a [T]> for Splits<'a, T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a [T]> {
+        if self.finished { return None; }
+
+        match self.v.iter().rposition(|x| (self.pred)(x)) {
+            None => {
+                self.finished = true;
+                Some(self.v)
+            }
+            Some(idx) => {
+                let ret = Some(self.v.slice(idx + 1, self.v.len()));
+                self.v = self.v.slice(0, idx);
+                ret
+            }
+        }
+    }
+}
+
+/// An iterator over the subslices of the vector which are separated
+/// by elements that match `pred`.
+pub struct MutSplits<'a, T> {
+    v: &'a mut [T],
+    pred: |t: &T|: 'a -> bool,
+    finished: bool
+}
+
+impl<'a, T> Iterator<&'a mut [T]> for MutSplits<'a, T> {
+    #[inline]
+    fn next(&mut self) -> Option<&'a mut [T]> {
+        if self.finished { return None; }
+
+        let pred = &mut self.pred;
+        match self.v.iter().position(|x| (*pred)(x)) {
+            None => {
+                self.finished = true;
+                let tmp = mem::replace(&mut self.v, &mut []);
+                let len = tmp.len();
+                let (head, tail) = tmp.mut_split_at(len);
+                self.v = tail;
+                Some(head)
+            }
+            Some(idx) => {
+                let tmp = mem::replace(&mut self.v, &mut []);
+                let (head, tail) = tmp.mut_split_at(idx);
+                self.v = tail.mut_slice_from(1);
+                Some(head)
+            }
         }
     }
 
     #[inline]
-    fn mut_slice_from(self, start: uint) -> &'a mut [T] {
-        let len = self.len();
-        self.mut_slice(start, len)
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        if self.finished {
+            (0, Some(0))
+        } else {
+            // if the predicate doesn't match anything, we yield one slice
+            // if it matches every element, we yield len+1 empty slices.
+            (1, Some(self.v.len() + 1))
+        }
     }
+}
 
+impl<'a, T> DoubleEndedIterator<&'a mut [T]> for MutSplits<'a, T> {
     #[inline]
-    fn mut_slice_to(self, end: uint) -> &'a mut [T] {
-        self.mut_slice(0, end)
-    }
+    fn next_back(&mut self) -> Option<&'a mut [T]> {
+        if self.finished { return None; }
 
-    #[inline]
-    fn mut_split_at(self, mid: uint) -> (&'a mut [T], &'a mut [T]) {
-        unsafe {
-            let len = self.len();
-            let self2: &'a mut [T] = mem::transmute_copy(&self);
-            (self.mut_slice(0, mid), self2.mut_slice(mid, len))
+        let pred = &mut self.pred;
+        match self.v.iter().rposition(|x| (*pred)(x)) {
+            None => {
+                self.finished = true;
+                let tmp = mem::replace(&mut self.v, &mut []);
+                Some(tmp)
+            }
+            Some(idx) => {
+                let tmp = mem::replace(&mut self.v, &mut []);
+                let (head, tail) = tmp.mut_split_at(idx);
+                self.v = head;
+                Some(tail.mut_slice_from(1))
+            }
         }
     }
+}
+
+/// An iterator over the slices of a vector separated by elements that
+/// match a predicate function, splitting at most a fixed number of times.
+pub struct SplitsN<'a, T> {
+    iter: Splits<'a, T>,
+    count: uint,
+    invert: bool
+}
 
+impl<'a, T> Iterator<&'a [T]> for SplitsN<'a, T> {
     #[inline]
-    fn mut_iter(self) -> MutItems<'a, T> {
-        unsafe {
-            let p = self.as_mut_ptr();
-            if mem::size_of::<T>() == 0 {
-                MutItems{ptr: p,
-                         end: (p as uint + self.len()) as *mut T,
-                         marker: marker::ContravariantLifetime::<'a>,
-                         marker2: marker::NoCopy}
+    fn next(&mut self) -> Option<&'a [T]> {
+        if self.count == 0 {
+            if self.iter.finished {
+                None
             } else {
-                MutItems{ptr: p,
-                         end: p.offset(self.len() as int),
-                         marker: marker::ContravariantLifetime::<'a>,
-                         marker2: marker::NoCopy}
+                self.iter.finished = true;
+                Some(self.iter.v)
             }
+        } else {
+            self.count -= 1;
+            if self.invert { self.iter.next_back() } else { self.iter.next() }
         }
     }
 
     #[inline]
-    fn mut_last(self) -> Option<&'a mut T> {
-        let len = self.len();
-        if len == 0 { return None; }
-        Some(&mut self[len - 1])
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        if self.iter.finished {
+            (0, Some(0))
+        } else {
+            (1, Some(cmp::min(self.count, self.iter.v.len()) + 1))
+        }
     }
+}
 
-    #[inline]
-    fn mut_split(self, pred: |&T|: 'a -> bool) -> MutSplits<'a, T> {
-        MutSplits { v: self, pred: pred, finished: false }
-    }
+/// An iterator over the (overlapping) slices of length `size` within
+/// a vector.
+#[deriving(Clone)]
+pub struct Windows<'a, T> {
+    v: &'a [T],
+    size: uint
+}
 
+impl<'a, T> Iterator<&'a [T]> for Windows<'a, T> {
     #[inline]
-    fn mut_chunks(self, chunk_size: uint) -> MutChunks<'a, T> {
-        assert!(chunk_size > 0);
-        MutChunks { v: self, chunk_size: chunk_size }
+    fn next(&mut self) -> Option<&'a [T]> {
+        if self.size > self.v.len() {
+            None
+        } else {
+            let ret = Some(self.v.slice(0, self.size));
+            self.v = self.v.slice(1, self.v.len());
+            ret
+        }
     }
 
-    fn mut_shift_ref(&mut self) -> Option<&'a mut T> {
-        unsafe {
-            let s: &mut Slice<T> = transmute(self);
-            match raw::shift_ptr(s) {
-                // FIXME #13933: this `&` -> `&mut` cast is a little
-                // dubious
-                Some(p) => Some(&mut *(p as *mut _)),
-                None => None,
-            }
+    #[inline]
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        if self.size > self.v.len() {
+            (0, Some(0))
+        } else {
+            let x = self.v.len() - self.size;
+            (x.saturating_add(1), x.checked_add(&1u))
         }
     }
+}
 
-    fn mut_pop_ref(&mut self) -> Option<&'a mut T> {
-        unsafe {
-            let s: &mut Slice<T> = transmute(self);
-            match raw::pop_ptr(s) {
-                // FIXME #13933: this `&` -> `&mut` cast is a little
-                // dubious
-                Some(p) => Some(&mut *(p as *mut _)),
-                None => None,
-            }
+/// An iterator over a vector in (non-overlapping) chunks (`size`
+/// elements at a time).
+///
+/// When the vector len is not evenly divided by the chunk size,
+/// the last slice of the iteration will be the remainder.
+#[deriving(Clone)]
+pub struct Chunks<'a, T> {
+    v: &'a [T],
+    size: uint
+}
+
+impl<'a, T> Iterator<&'a [T]> for Chunks<'a, T> {
+    #[inline]
+    fn next(&mut self) -> Option<&'a [T]> {
+        if self.v.len() == 0 {
+            None
+        } else {
+            let chunksz = cmp::min(self.v.len(), self.size);
+            let (fst, snd) = (self.v.slice_to(chunksz),
+                              self.v.slice_from(chunksz));
+            self.v = snd;
+            Some(fst)
         }
     }
 
-    fn swap(self, a: uint, b: uint) {
-        unsafe {
-            // Can't take two mutable loans from one vector, so instead just cast
-            // them to their raw pointers to do the swap
-            let pa: *mut T = &mut self[a];
-            let pb: *mut T = &mut self[b];
-            ptr::swap(pa, pb);
+    #[inline]
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        if self.v.len() == 0 {
+            (0, Some(0))
+        } else {
+            let (n, rem) = div_rem(self.v.len(), self.size);
+            let n = if rem > 0 { n+1 } else { n };
+            (n, Some(n))
         }
     }
+}
 
-    fn reverse(self) {
-        let mut i: uint = 0;
-        let ln = self.len();
-        while i < ln / 2 {
-            self.swap(i, ln - i - 1);
-            i += 1;
+impl<'a, T> DoubleEndedIterator<&'a [T]> for Chunks<'a, T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a [T]> {
+        if self.v.len() == 0 {
+            None
+        } else {
+            let remainder = self.v.len() % self.size;
+            let chunksz = if remainder != 0 { remainder } else { self.size };
+            let (fst, snd) = (self.v.slice_to(self.v.len() - chunksz),
+                              self.v.slice_from(self.v.len() - chunksz));
+            self.v = fst;
+            Some(snd)
         }
     }
+}
 
+impl<'a, T> RandomAccessIterator<&'a [T]> for Chunks<'a, T> {
     #[inline]
-    unsafe fn unsafe_mut_ref(self, index: uint) -> &'a mut T {
-        transmute((self.repr().data as *mut T).offset(index as int))
+    fn indexable(&self) -> uint {
+        self.v.len()/self.size + if self.v.len() % self.size != 0 { 1 } else { 0 }
     }
 
     #[inline]
-    fn as_mut_ptr(self) -> *mut T {
-        self.repr().data as *mut T
+    fn idx(&mut self, index: uint) -> Option<&'a [T]> {
+        if index < self.indexable() {
+            let lo = index * self.size;
+            let mut hi = lo + self.size;
+            if hi < lo || hi > self.v.len() { hi = self.v.len(); }
+
+            Some(self.v.slice(lo, hi))
+        } else {
+            None
+        }
     }
+}
+
+/// An iterator over a vector in (non-overlapping) mutable chunks (`size`  elements at a time). When
+/// the vector len is not evenly divided by the chunk size, the last slice of the iteration will be
+/// the remainder.
+pub struct MutChunks<'a, T> {
+    v: &'a mut [T],
+    chunk_size: uint
+}
 
+impl<'a, T> Iterator<&'a mut [T]> for MutChunks<'a, T> {
     #[inline]
-    unsafe fn unsafe_set(self, index: uint, val: T) {
-        *self.unsafe_mut_ref(index) = val;
+    fn next(&mut self) -> Option<&'a mut [T]> {
+        if self.v.len() == 0 {
+            None
+        } else {
+            let sz = cmp::min(self.v.len(), self.chunk_size);
+            let tmp = mem::replace(&mut self.v, &mut []);
+            let (head, tail) = tmp.mut_split_at(sz);
+            self.v = tail;
+            Some(head)
+        }
     }
 
     #[inline]
-    unsafe fn init_elem(self, i: uint, val: T) {
-        ptr::write(&mut (*self.as_mut_ptr().offset(i as int)), val);
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        if self.v.len() == 0 {
+            (0, Some(0))
+        } else {
+            let (n, rem) = div_rem(self.v.len(), self.chunk_size);
+            let n = if rem > 0 { n + 1 } else { n };
+            (n, Some(n))
+        }
     }
+}
 
+impl<'a, T> DoubleEndedIterator<&'a mut [T]> for MutChunks<'a, T> {
     #[inline]
-    unsafe fn copy_memory(self, src: &[T]) {
-        let len_src = src.len();
-        assert!(self.len() >= len_src);
-        ptr::copy_nonoverlapping_memory(self.as_mut_ptr(), src.as_ptr(), len_src)
+    fn next_back(&mut self) -> Option<&'a mut [T]> {
+        if self.v.len() == 0 {
+            None
+        } else {
+            let remainder = self.v.len() % self.chunk_size;
+            let sz = if remainder != 0 { remainder } else { self.chunk_size };
+            let tmp = mem::replace(&mut self.v, &mut []);
+            let tmp_len = tmp.len();
+            let (head, tail) = tmp.mut_split_at(tmp_len - sz);
+            self.v = head;
+            Some(tail)
+        }
     }
 }
 
-/// Trait for &[T] where T is Cloneable
-pub trait MutableCloneableVector<T> {
-    /// Copies as many elements from `src` as it can into `self` (the
-    /// shorter of `self.len()` and `src.len()`). Returns the number
-    /// of elements copied.
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// use std::slice::MutableCloneableVector;
-    ///
-    /// let mut dst = [0i, 0, 0];
-    /// let src = [1i, 2];
-    ///
-    /// assert!(dst.copy_from(src) == 2);
-    /// assert!(dst == [1, 2, 0]);
-    ///
-    /// let src2 = [3i, 4, 5, 6];
-    /// assert!(dst.copy_from(src2) == 3);
-    /// assert!(dst == [3i, 4, 5]);
-    /// ```
-    fn copy_from(self, &[T]) -> uint;
+
+
+
+//
+// Free functions
+//
+
+/**
+ * Converts a pointer to A into a slice of length 1 (without copying).
+ */
+pub fn ref_slice<'a, A>(s: &'a A) -> &'a [A] {
+    unsafe {
+        transmute(Slice { data: s, len: 1 })
+    }
 }
 
-impl<'a, T:Clone> MutableCloneableVector<T> for &'a mut [T] {
-    #[inline]
-    fn copy_from(self, src: &[T]) -> uint {
-        for (a, b) in self.mut_iter().zip(src.iter()) {
-            a.clone_from(b);
-        }
-        cmp::min(self.len(), src.len())
+/**
+ * Converts a pointer to A into a slice of length 1 (without copying).
+ */
+pub fn mut_ref_slice<'a, A>(s: &'a mut A) -> &'a mut [A] {
+    unsafe {
+        let ptr: *const A = transmute(s);
+        transmute(Slice { data: ptr, len: 1 })
     }
 }
 
+
+
+
+//
+// Submodules
+//
+
 /// Unsafe operations
 pub mod raw {
     use mem::transmute;
@@ -1201,224 +1415,56 @@ pub fn copy_memory(dst: &mut [u8], src: &[u8]) {
     }
 }
 
-/// Immutable slice iterator
-pub struct Items<'a, T> {
-    ptr: *const T,
-    end: *const T,
-    marker: marker::ContravariantLifetime<'a>
-}
-
-/// Mutable slice iterator
-pub struct MutItems<'a, T> {
-    ptr: *mut T,
-    end: *mut T,
-    marker: marker::ContravariantLifetime<'a>,
-    marker2: marker::NoCopy
-}
-
-macro_rules! iterator {
-    (struct $name:ident -> $ptr:ty, $elem:ty) => {
-        impl<'a, T> Iterator<$elem> for $name<'a, T> {
-            #[inline]
-            fn next(&mut self) -> Option<$elem> {
-                // could be implemented with slices, but this avoids bounds checks
-                unsafe {
-                    if self.ptr == self.end {
-                        None
-                    } else {
-                        let old = self.ptr;
-                        self.ptr = if mem::size_of::<T>() == 0 {
-                            // purposefully don't use 'ptr.offset' because for
-                            // vectors with 0-size elements this would return the
-                            // same pointer.
-                            transmute(self.ptr as uint + 1)
-                        } else {
-                            self.ptr.offset(1)
-                        };
 
-                        Some(transmute(old))
-                    }
-                }
-            }
 
-            #[inline]
-            fn size_hint(&self) -> (uint, Option<uint>) {
-                let diff = (self.end as uint) - (self.ptr as uint);
-                let size = mem::size_of::<T>();
-                let exact = diff / (if size == 0 {1} else {size});
-                (exact, Some(exact))
-            }
-        }
 
-        impl<'a, T> DoubleEndedIterator<$elem> for $name<'a, T> {
-            #[inline]
-            fn next_back(&mut self) -> Option<$elem> {
-                // could be implemented with slices, but this avoids bounds checks
-                unsafe {
-                    if self.end == self.ptr {
-                        None
-                    } else {
-                        self.end = if mem::size_of::<T>() == 0 {
-                            // See above for why 'ptr.offset' isn't used
-                            transmute(self.end as uint - 1)
-                        } else {
-                            self.end.offset(-1)
-                        };
-                        Some(transmute(self.end))
-                    }
-                }
-            }
-        }
-    }
-}
+//
+// Boilerplate traits
+//
 
-impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> {
-    #[inline]
-    fn indexable(&self) -> uint {
-        let (exact, _) = self.size_hint();
-        exact
+impl<'a,T:PartialEq> PartialEq for &'a [T] {
+    fn eq(&self, other: & &'a [T]) -> bool {
+        self.len() == other.len() &&
+            order::eq(self.iter(), other.iter())
     }
-
-    #[inline]
-    fn idx(&mut self, index: uint) -> Option<&'a T> {
-        unsafe {
-            if index < self.indexable() {
-                transmute(self.ptr.offset(index as int))
-            } else {
-                None
-            }
-        }
+    fn ne(&self, other: & &'a [T]) -> bool {
+        self.len() != other.len() ||
+            order::ne(self.iter(), other.iter())
     }
 }
 
-iterator!{struct Items -> *const T, &'a T}
-
-impl<'a, T> ExactSize<&'a T> for Items<'a, T> {}
-impl<'a, T> ExactSize<&'a mut T> for MutItems<'a, T> {}
-
-impl<'a, T> Clone for Items<'a, T> {
-    fn clone(&self) -> Items<'a, T> { *self }
-}
-
-iterator!{struct MutItems -> *mut T, &'a mut T}
-
-/// An iterator over the subslices of the vector which are separated
-/// by elements that match `pred`.
-pub struct MutSplits<'a, T> {
-    v: &'a mut [T],
-    pred: |t: &T|: 'a -> bool,
-    finished: bool
-}
+impl<'a,T:Eq> Eq for &'a [T] {}
 
-impl<'a, T> Iterator<&'a mut [T]> for MutSplits<'a, T> {
+impl<'a,T:PartialEq, V: Vector<T>> Equiv<V> for &'a [T] {
     #[inline]
-    fn next(&mut self) -> Option<&'a mut [T]> {
-        if self.finished { return None; }
+    fn equiv(&self, other: &V) -> bool { self.as_slice() == other.as_slice() }
+}
 
-        let pred = &mut self.pred;
-        match self.v.iter().position(|x| (*pred)(x)) {
-            None => {
-                self.finished = true;
-                let tmp = mem::replace(&mut self.v, &mut []);
-                let len = tmp.len();
-                let (head, tail) = tmp.mut_split_at(len);
-                self.v = tail;
-                Some(head)
-            }
-            Some(idx) => {
-                let tmp = mem::replace(&mut self.v, &mut []);
-                let (head, tail) = tmp.mut_split_at(idx);
-                self.v = tail.mut_slice_from(1);
-                Some(head)
-            }
-        }
+impl<'a,T:Ord> Ord for &'a [T] {
+    fn cmp(&self, other: & &'a [T]) -> Ordering {
+        order::cmp(self.iter(), other.iter())
     }
+}
 
+impl<'a, T: PartialOrd> PartialOrd for &'a [T] {
     #[inline]
-    fn size_hint(&self) -> (uint, Option<uint>) {
-        if self.finished {
-            (0, Some(0))
-        } else {
-            // if the predicate doesn't match anything, we yield one slice
-            // if it matches every element, we yield len+1 empty slices.
-            (1, Some(self.v.len() + 1))
-        }
+    fn partial_cmp(&self, other: &&'a [T]) -> Option<Ordering> {
+        order::partial_cmp(self.iter(), other.iter())
     }
-}
-
-impl<'a, T> DoubleEndedIterator<&'a mut [T]> for MutSplits<'a, T> {
     #[inline]
-    fn next_back(&mut self) -> Option<&'a mut [T]> {
-        if self.finished { return None; }
-
-        let pred = &mut self.pred;
-        match self.v.iter().rposition(|x| (*pred)(x)) {
-            None => {
-                self.finished = true;
-                let tmp = mem::replace(&mut self.v, &mut []);
-                Some(tmp)
-            }
-            Some(idx) => {
-                let tmp = mem::replace(&mut self.v, &mut []);
-                let (head, tail) = tmp.mut_split_at(idx);
-                self.v = head;
-                Some(tail.mut_slice_from(1))
-            }
-        }
+    fn lt(&self, other: & &'a [T]) -> bool {
+        order::lt(self.iter(), other.iter())
     }
-}
-
-/// An iterator over a vector in (non-overlapping) mutable chunks (`size`  elements at a time). When
-/// the vector len is not evenly divided by the chunk size, the last slice of the iteration will be
-/// the remainder.
-pub struct MutChunks<'a, T> {
-    v: &'a mut [T],
-    chunk_size: uint
-}
-
-impl<'a, T> Iterator<&'a mut [T]> for MutChunks<'a, T> {
     #[inline]
-    fn next(&mut self) -> Option<&'a mut [T]> {
-        if self.v.len() == 0 {
-            None
-        } else {
-            let sz = cmp::min(self.v.len(), self.chunk_size);
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let (head, tail) = tmp.mut_split_at(sz);
-            self.v = tail;
-            Some(head)
-        }
+    fn le(&self, other: & &'a [T]) -> bool {
+        order::le(self.iter(), other.iter())
     }
-
     #[inline]
-    fn size_hint(&self) -> (uint, Option<uint>) {
-        if self.v.len() == 0 {
-            (0, Some(0))
-        } else {
-            let (n, rem) = div_rem(self.v.len(), self.chunk_size);
-            let n = if rem > 0 { n + 1 } else { n };
-            (n, Some(n))
-        }
+    fn ge(&self, other: & &'a [T]) -> bool {
+        order::ge(self.iter(), other.iter())
     }
-}
-
-impl<'a, T> DoubleEndedIterator<&'a mut [T]> for MutChunks<'a, T> {
     #[inline]
-    fn next_back(&mut self) -> Option<&'a mut [T]> {
-        if self.v.len() == 0 {
-            None
-        } else {
-            let remainder = self.v.len() % self.chunk_size;
-            let sz = if remainder != 0 { remainder } else { self.chunk_size };
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let tmp_len = tmp.len();
-            let (head, tail) = tmp.mut_split_at(tmp_len - sz);
-            self.v = head;
-            Some(tail)
-        }
+    fn gt(&self, other: & &'a [T]) -> bool {
+        order::gt(self.iter(), other.iter())
     }
 }
-
-impl<'a, T> Default for &'a [T] {
-    fn default() -> &'a [T] { &[] }
-}
index b562d48f49d32ce7eb93b9a3ce010f962b8c3a0d..30296cb318617af1fdc0a544374596a44e5a37c8 100644 (file)
@@ -30,7 +30,7 @@
 use middle::trans::adt; // for `adt::is_ffi_safe`
 use middle::typeck::astconv::ast_ty_to_ty;
 use middle::typeck::infer;
-use middle::{typeck, ty, def, pat_util};
+use middle::{typeck, ty, def, pat_util, stability};
 use util::ppaux::{ty_to_str};
 use util::nodemap::NodeSet;
 use lint::{Context, LintPass, LintArray};
@@ -1426,11 +1426,7 @@ fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
                     Some(method) => {
                         match method.origin {
                             typeck::MethodStatic(def_id) => {
-                                // If this implements a trait method, get def_id
-                                // of the method inside trait definition.
-                                // Otherwise, use the current def_id (which refers
-                                // to the method inside impl).
-                                ty::trait_method_of_method(cx.tcx, def_id).unwrap_or(def_id)
+                                def_id
                             }
                             typeck::MethodParam(typeck::MethodParam {
                                 trait_id: trait_id,
@@ -1454,8 +1450,7 @@ fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
         // check anything for crate-local usage.
         if ast_util::is_local(id) { return }
 
-        let stability = cx.tcx.stability.borrow_mut().lookup(&cx.tcx.sess.cstore, id);
-
+        let stability = stability::lookup(cx.tcx, id);
         let (lint, label) = match stability {
             // no stability attributes == Unstable
             None => (UNSTABLE, "unmarked"),
index c5789e4442a9d20e955af7b784dab36418718019..96284f8de261a78254f0faa3ff837c660049cf2b 100644 (file)
@@ -24,6 +24,7 @@
 use middle::astencode;
 use middle::ty;
 use middle::typeck;
+use middle::stability;
 use middle;
 use util::nodemap::{NodeMap, NodeSet};
 
@@ -328,7 +329,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext,
         encode_visibility(ebml_w, variant.node.vis);
         encode_attributes(ebml_w, variant.node.attrs.as_slice());
 
-        let stab = ecx.tcx.stability.borrow().lookup_local(variant.node.id);
+        let stab = stability::lookup(ecx.tcx, ast_util::local_def(variant.node.id));
         encode_stability(ebml_w, stab);
 
         match variant.node.kind {
@@ -592,7 +593,9 @@ fn encode_info_for_mod(ecx: &EncodeContext,
 
     encode_path(ebml_w, path.clone());
     encode_visibility(ebml_w, vis);
-    encode_stability(ebml_w, ecx.tcx.stability.borrow().lookup_local(id));
+
+    let stab = stability::lookup(ecx.tcx, ast_util::local_def(id));
+    encode_stability(ebml_w, stab);
 
     // Encode the reexports of this module, if this module is public.
     if vis == Public {
@@ -722,7 +725,8 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext,
         encode_symbol(ecx, ebml_w, ctor_id);
     }
 
-    encode_stability(ebml_w, ecx.tcx.stability.borrow().lookup_local(ctor_id));
+    let stab = stability::lookup(ecx.tcx, ast_util::local_def(ctor_id));
+    encode_stability(ebml_w, stab);
 
     // indicate that this is a tuple struct ctor, because downstream users will normally want
     // the tuple struct definition, but without this there is no way for them to tell that
@@ -768,7 +772,7 @@ fn encode_info_for_method(ecx: &EncodeContext,
     encode_method_ty_fields(ecx, ebml_w, m);
     encode_parent_item(ebml_w, local_def(parent_id));
 
-    let stab = ecx.tcx.stability.borrow().lookup_local(m.def_id.node);
+    let stab = stability::lookup(ecx.tcx, m.def_id);
     encode_stability(ebml_w, stab);
 
     // The type for methods gets encoded twice, which is unfortunate.
@@ -915,10 +919,10 @@ fn add_to_index(item: &Item, ebml_w: &Encoder,
     }
 
     debug!("encoding info for item at {}",
-           ecx.tcx.sess.codemap().span_to_str(item.span));
+           tcx.sess.codemap().span_to_str(item.span));
 
     let def_id = local_def(item.id);
-    let stab = tcx.stability.borrow().lookup_local(item.id);
+    let stab = stability::lookup(tcx, ast_util::local_def(item.id));
 
     match item.node {
       ItemStatic(_, m, _) => {
@@ -1206,7 +1210,7 @@ fn add_to_index(item: &Item, ebml_w: &Encoder,
             encode_method_ty_fields(ecx, ebml_w, &*method_ty);
             encode_parent_item(ebml_w, def_id);
 
-            let stab = tcx.stability.borrow().lookup_local(method_def_id.node);
+            let stab = stability::lookup(tcx, method_def_id);
             encode_stability(ebml_w, stab);
 
             let elem = ast_map::PathName(method_ty.ident.name);
index fc76648ec5524c411768c2a1314a2d06809fec39..ac17bd07503521212b46b40f71055095d86649e3 100644 (file)
@@ -20,7 +20,8 @@
 use syntax::ast_util::is_local;
 use syntax::attr::Stability;
 use syntax::visit::{FnKind, FkMethod, Visitor};
-use metadata::{cstore, csearch};
+use middle::ty;
+use metadata::csearch;
 
 /// A stability index, giving the stability level for items and methods.
 pub struct Index {
@@ -105,21 +106,24 @@ pub fn build(krate: &Crate) -> Index {
                           attr::find_stability(krate.attrs.as_slice()));
         annotator.index
     }
+}
 
-    /// Lookup the stability for a node, loading external crate
-    /// metadata as necessary.
-    pub fn lookup(&mut self, cstore: &cstore::CStore, id: DefId) -> Option<Stability> {
-        if is_local(id) {
-            self.lookup_local(id.node)
-        } else {
-            let stab = csearch::get_stability(cstore, id);
-            self.extern_cache.insert(id, stab.clone());
+/// Lookup the stability for a node, loading external crate
+/// metadata as necessary.
+pub fn lookup(tcx: &ty::ctxt,  id: DefId) -> Option<Stability> {
+    // is this definition the implementation of a trait method?
+    match ty::trait_method_of_method(tcx, id) {
+        Some(trait_method_id) if trait_method_id != id => {
+            lookup(tcx, trait_method_id)
+        }
+        _ if is_local(id) => {
+            tcx.stability.borrow().local.find_copy(&id.node)
+        }
+        _ => {
+            let stab = csearch::get_stability(&tcx.sess.cstore, id);
+            let mut index = tcx.stability.borrow_mut();
+            (*index).extern_cache.insert(id, stab.clone());
             stab
         }
     }
-
-    /// Lookup the stability for a local node without loading any external crates
-    pub fn lookup_local(&self, id: NodeId) -> Option<Stability> {
-        self.local.find_copy(&id)
-    }
 }
index 210de1946c9e6f9ec8deef4faf185821439b460c..75271804b7911b32be2380cbfffc9d8015e824dc 100644 (file)
@@ -1220,7 +1220,7 @@ pub fn init_function<'a>(fcx: &'a FunctionContext<'a>,
 //  - new_fn_ctxt
 //  - trans_args
 
-fn arg_kind(cx: &FunctionContext, t: ty::t) -> datum::Rvalue {
+pub fn arg_kind(cx: &FunctionContext, t: ty::t) -> datum::Rvalue {
     use middle::trans::datum::{ByRef, ByValue};
 
     datum::Rvalue {
index c64f4cfa8779887d8d341457866027e896379573..a9c1adac3d7cf01e07c3926d4706708e8a087367 100644 (file)
@@ -159,6 +159,14 @@ pub fn invoke(&self,
                   attributes: &[(uint, u64)])
                   -> ValueRef {
         self.count_insn("invoke");
+
+        debug!("Invoke {} with args ({})",
+               self.ccx.tn.val_to_str(llfn),
+               args.iter()
+                   .map(|&v| self.ccx.tn.val_to_str(v))
+                   .collect::<Vec<String>>()
+                   .connect(", "));
+
         unsafe {
             let v = llvm::LLVMBuildInvoke(self.llbuilder,
                                           llfn,
index 8b484e90898c97d2846080b80ca88efaa123b879..116b2e6b421b81e41e1c5a94064853528c57897a 100644 (file)
@@ -16,7 +16,9 @@
  * closure.
  */
 
+use arena::TypedArena;
 use back::abi;
+use back::link;
 use driver::session;
 use lib::llvm::ValueRef;
 use lib::llvm::llvm;
 use middle::trans::common;
 use middle::trans::common::*;
 use middle::trans::datum::*;
-use middle::trans::datum::Datum;
+use middle::trans::datum::{Datum, KindOps};
 use middle::trans::expr;
 use middle::trans::glue;
 use middle::trans::inline;
+use middle::trans::foreign;
 use middle::trans::meth;
 use middle::trans::monomorphize;
+use middle::trans::type_::Type;
 use middle::trans::type_of;
-use middle::trans::foreign;
 use middle::ty;
 use middle::typeck;
 use middle::typeck::coherence::make_substs_for_receiver_types;
 use middle::typeck::MethodCall;
 use util::ppaux::Repr;
 
-use middle::trans::type_::Type;
-
+use std::gc::Gc;
 use syntax::ast;
 use synabi = syntax::abi;
 use syntax::ast_map;
 
-use std::gc::Gc;
-
 pub struct MethodData {
     pub llfn: ValueRef,
     pub llself: ValueRef,
@@ -224,6 +224,134 @@ fn resolve_default_method_vtables(bcx: &Block,
     param_vtables
 }
 
+/// Translates the adapter that deconstructs a `Box<Trait>` object into
+/// `Trait` so that a by-value self method can be called.
+pub fn trans_unboxing_shim(bcx: &Block,
+                           llshimmedfn: ValueRef,
+                           method: &ty::Method,
+                           method_id: ast::DefId,
+                           substs: subst::Substs)
+                           -> ValueRef {
+    let _icx = push_ctxt("trans_unboxing_shim");
+    let ccx = bcx.ccx();
+    let tcx = bcx.tcx();
+
+    // Transform the self type to `Box<self_type>`.
+    let self_type = *method.fty.sig.inputs.get(0);
+    let boxed_self_type = ty::mk_uniq(tcx, self_type);
+    let boxed_function_type = ty::FnSig {
+        binder_id: method.fty.sig.binder_id,
+        inputs: method.fty.sig.inputs.iter().enumerate().map(|(i, typ)| {
+            if i == 0 {
+                boxed_self_type
+            } else {
+                *typ
+            }
+        }).collect(),
+        output: method.fty.sig.output,
+        variadic: false,
+    };
+    let boxed_function_type = ty::BareFnTy {
+        fn_style: method.fty.fn_style,
+        abi: method.fty.abi,
+        sig: boxed_function_type,
+    };
+    let boxed_function_type =
+        ty::mk_bare_fn(tcx, boxed_function_type).subst(tcx, &substs);
+    let function_type =
+        ty::mk_bare_fn(tcx, method.fty.clone()).subst(tcx, &substs);
+
+    let function_name = tcx.map.with_path(method_id.node, |path| {
+        link::mangle_internal_name_by_path_and_seq(path, "unboxing_shim")
+    });
+    let llfn = decl_internal_rust_fn(ccx,
+                                     boxed_function_type,
+                                     function_name.as_slice());
+
+    let block_arena = TypedArena::new();
+    let empty_param_substs = param_substs::empty();
+    let return_type = ty::ty_fn_ret(boxed_function_type);
+    let fcx = new_fn_ctxt(ccx,
+                          llfn,
+                          -1,
+                          false,
+                          return_type,
+                          &empty_param_substs,
+                          None,
+                          &block_arena);
+    init_function(&fcx, false, return_type);
+
+    // Create the substituted versions of the self type.
+    let mut bcx = fcx.entry_bcx.borrow().clone().unwrap();
+    let arg_scope = fcx.push_custom_cleanup_scope();
+    let arg_scope_id = cleanup::CustomScope(arg_scope);
+    let boxed_arg_types = ty::ty_fn_args(boxed_function_type);
+    let boxed_self_type = *boxed_arg_types.get(0);
+    let arg_types = ty::ty_fn_args(function_type);
+    let self_type = *arg_types.get(0);
+    let boxed_self_kind = arg_kind(&fcx, boxed_self_type);
+
+    // Create a datum for self.
+    let llboxedself = unsafe {
+        llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(0) as u32)
+    };
+    let llboxedself = Datum::new(llboxedself,
+                                 boxed_self_type,
+                                 boxed_self_kind);
+    let boxed_self =
+        unpack_datum!(bcx,
+                      llboxedself.to_lvalue_datum_in_scope(bcx,
+                                                           "boxedself",
+                                                           arg_scope_id));
+
+    // This `Load` is needed because lvalue data are always by-ref.
+    let llboxedself = Load(bcx, boxed_self.val);
+
+    let llself = if type_is_immediate(ccx, self_type) {
+        let llboxedself = Load(bcx, llboxedself);
+        immediate_rvalue(llboxedself, self_type)
+    } else {
+        let llself = rvalue_scratch_datum(bcx, self_type, "self");
+        memcpy_ty(bcx, llself.val, llboxedself, self_type);
+        llself
+    };
+
+    // Make sure we don't free the box twice!
+    boxed_self.kind.post_store(bcx, boxed_self.val, boxed_self_type);
+
+    // Schedule a cleanup to free the box.
+    fcx.schedule_free_value(arg_scope_id,
+                            llboxedself,
+                            cleanup::HeapExchange,
+                            self_type);
+
+    // Now call the function.
+    let mut llshimmedargs = vec!(llself.val);
+    for i in range(1, arg_types.len()) {
+        llshimmedargs.push(unsafe {
+            llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(i) as u32)
+        });
+    }
+    bcx = trans_call_inner(bcx,
+                           None,
+                           function_type,
+                           |bcx, _| {
+                               Callee {
+                                   bcx: bcx,
+                                   data: Fn(llshimmedfn),
+                               }
+                           },
+                           ArgVals(llshimmedargs.as_slice()),
+                           match fcx.llretptr.get() {
+                               None => None,
+                               Some(llretptr) => Some(expr::SaveIn(llretptr)),
+                           }).bcx;
+
+    bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_scope);
+    finish_fn(&fcx, bcx);
+
+    llfn
+}
 
 pub fn trans_fn_ref_with_vtables(
     bcx: &Block,                 //
index 85660cd2eb540c880d13f0ebedf74f7ca67d679a..e1d43c5240059ee03fd51e40f451269ec123f17d 100644 (file)
@@ -492,14 +492,24 @@ fn emit_vtable_methods(bcx: &Block,
                m.repr(tcx),
                substs.repr(tcx));
         if m.generics.has_type_params(subst::FnSpace) ||
-           ty::type_has_self(ty::mk_bare_fn(tcx, m.fty.clone()))
-        {
+           ty::type_has_self(ty::mk_bare_fn(tcx, m.fty.clone())) {
             debug!("(making impl vtable) method has self or type params: {}",
                    token::get_ident(ident));
             C_null(Type::nil(ccx).ptr_to())
         } else {
-            trans_fn_ref_with_vtables(bcx, m_id, ExprId(0),
-                                      substs.clone(), vtables.clone())
+            let mut fn_ref = trans_fn_ref_with_vtables(bcx,
+                                                       m_id,
+                                                       ExprId(0),
+                                                       substs.clone(),
+                                                       vtables.clone());
+            if m.explicit_self == ast::SelfValue {
+                fn_ref = trans_unboxing_shim(bcx,
+                                             fn_ref,
+                                             &*m,
+                                             m_id,
+                                             substs.clone());
+            }
+            fn_ref
         }
     }).collect()
 }
index 4270ff1e7952d450967f652e4d4f29f616789059..c3b2756bdbff2f7f165af2718ec6a1fe293a7452 100644 (file)
@@ -271,7 +271,9 @@ fn construct_transformed_self_ty_for_object(
             tcx.sess.span_bug(span, "static method for object type receiver");
         }
         ast::SelfValue => {
-            ty::mk_err() // error reported in `enforce_object_limitations()`
+            let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
+                                  ty::empty_builtin_bounds());
+            ty::mk_uniq(tcx, tr)
         }
         ast::SelfRegion(..) | ast::SelfUniq => {
             let transformed_self_ty = *method_ty.fty.sig.inputs.get(0);
@@ -1225,14 +1227,7 @@ fn enforce_object_limitations(&self, candidate: &Candidate) {
                      through an object");
             }
 
-            ast::SelfValue => { // reason (a) above
-                self.tcx().sess.span_err(
-                    self.span,
-                    "cannot call a method with a by-value receiver \
-                     through an object");
-            }
-
-            ast::SelfRegion(..) | ast::SelfUniq => {}
+            ast::SelfValue | ast::SelfRegion(..) | ast::SelfUniq => {}
         }
 
         // reason (a) above
@@ -1302,7 +1297,26 @@ fn is_relevant(&self, rcvr_ty: ty::t, candidate: &Candidate) -> bool {
             }
 
             SelfValue => {
-                rcvr_matches_ty(self.fcx, rcvr_ty, candidate)
+                debug!("(is relevant?) explicit self is by-value");
+                match ty::get(rcvr_ty).sty {
+                    ty::ty_uniq(typ) => {
+                        match ty::get(typ).sty {
+                            ty::ty_trait(box ty::TyTrait {
+                                def_id: self_did,
+                                ..
+                            }) => {
+                                rcvr_matches_object(self_did, candidate) ||
+                                    rcvr_matches_ty(self.fcx,
+                                                    rcvr_ty,
+                                                    candidate)
+                            }
+                            _ => {
+                                rcvr_matches_ty(self.fcx, rcvr_ty, candidate)
+                            }
+                        }
+                    }
+                    _ => rcvr_matches_ty(self.fcx, rcvr_ty, candidate)
+                }
             }
 
             SelfRegion(_, m) => {
index d243c61ddaff8ba3d91bdab8fb135e9888352d12..2d498e7f302d3fca3330b0182ea547608eac6c68 100644 (file)
@@ -18,6 +18,7 @@
 use rustc::metadata::decoder;
 use rustc::middle::def;
 use rustc::middle::ty;
+use rustc::middle::stability;
 
 use core;
 use doctree;
@@ -102,6 +103,7 @@ fn try_inline_def(cx: &core::DocContext,
         attrs: load_attrs(tcx, did),
         inner: inner,
         visibility: Some(ast::Public),
+        stability: stability::lookup(tcx, did).clean(),
         def_id: did,
     });
     Some(ret)
@@ -317,6 +319,7 @@ fn build_impl(cx: &core::DocContext,
         name: None,
         attrs: attrs,
         visibility: Some(ast::Inherited),
+        stability: stability::lookup(tcx, did).clean(),
         def_id: did,
     })
 }
index d7bbb439dbb7788f175130fbf9f8a1db2ae771a3..87151708812e54a5f106291d5a04fd851bf6a0dc 100644 (file)
@@ -29,6 +29,7 @@
 use rustc::middle::subst;
 use rustc::middle::subst::VecPerParamSpace;
 use rustc::middle::ty;
+use rustc::middle::stability;
 
 use std::rc::Rc;
 use std::u32;
 
 mod inline;
 
+// load the current DocContext from TLD
+fn get_cx() -> Gc<core::DocContext> {
+    *super::ctxtkey.get().unwrap()
+}
+
+// extract the stability index for a node from TLD, if possible
+fn get_stability(def_id: ast::DefId) -> Option<Stability> {
+    get_cx().tcx_opt().and_then(|tcx| stability::lookup(tcx, def_id))
+            .map(|stab| stab.clean())
+}
+
 pub trait Clean<T> {
     fn clean(&self) -> T;
 }
@@ -97,7 +109,7 @@ pub struct Crate {
 
 impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
     fn clean(&self) -> Crate {
-        let cx = super::ctxtkey.get().unwrap();
+        let cx = get_cx();
 
         let mut externs = Vec::new();
         cx.sess().cstore.iter_crate_data(|n, meta| {
@@ -158,6 +170,7 @@ fn clean(&self) -> Crate {
                     name: Some(prim.to_url_str().to_string()),
                     attrs: Vec::new(),
                     visibility: None,
+                    stability: None,
                     def_id: ast_util::local_def(prim.to_node_id()),
                     inner: PrimitiveItem(prim),
                 };
@@ -193,25 +206,18 @@ pub struct ExternalCrate {
 impl Clean<ExternalCrate> for cstore::crate_metadata {
     fn clean(&self) -> ExternalCrate {
         let mut primitives = Vec::new();
-        let cx = super::ctxtkey.get().unwrap();
-        match cx.maybe_typed {
-            core::Typed(ref tcx) => {
-                csearch::each_top_level_item_of_crate(&tcx.sess.cstore,
-                                                      self.cnum,
-                                                      |def, _, _| {
-                    let did = match def {
-                        decoder::DlDef(def::DefMod(did)) => did,
-                        _ => return
-                    };
-                    let attrs = inline::load_attrs(tcx, did);
-                    match Primitive::find(attrs.as_slice()) {
-                        Some(prim) => primitives.push(prim),
-                        None => {}
-                    }
-                });
-            }
-            core::NotTyped(..) => {}
-        }
+        get_cx().tcx_opt().map(|tcx| {
+            csearch::each_top_level_item_of_crate(&tcx.sess.cstore,
+                                                  self.cnum,
+                                                  |def, _, _| {
+                let did = match def {
+                    decoder::DlDef(def::DefMod(did)) => did,
+                    _ => return
+                };
+                let attrs = inline::load_attrs(tcx, did);
+                Primitive::find(attrs.as_slice()).map(|prim| primitives.push(prim));
+            })
+        });
         ExternalCrate {
             name: self.name.to_string(),
             attrs: decoder::get_crate_attributes(self.data()).clean(),
@@ -233,6 +239,7 @@ pub struct Item {
     pub inner: ItemEnum,
     pub visibility: Option<Visibility>,
     pub def_id: ast::DefId,
+    pub stability: Option<Stability>,
 }
 
 impl Item {
@@ -380,6 +387,7 @@ fn clean(&self) -> Item {
             attrs: self.attrs.clean(),
             source: where.clean(),
             visibility: self.vis.clean(),
+            stability: self.stab.clean(),
             def_id: ast_util::local_def(self.id),
             inner: ModuleItem(Module {
                is_crate: self.is_crate,
@@ -465,9 +473,8 @@ fn clean(&self) -> TyParam {
 
 impl Clean<TyParam> for ty::TypeParameterDef {
     fn clean(&self) -> TyParam {
-        let cx = super::ctxtkey.get().unwrap();
-        cx.external_typarams.borrow_mut().get_mut_ref().insert(self.def_id,
-                                                               self.ident.clean());
+        get_cx().external_typarams.borrow_mut().get_mut_ref()
+                .insert(self.def_id, self.ident.clean());
         TyParam {
             name: self.ident.clean(),
             did: self.def_id,
@@ -515,7 +522,7 @@ fn external_path(name: &str, substs: &subst::Substs) -> Path {
 
 impl Clean<TyParamBound> for ty::BuiltinBound {
     fn clean(&self) -> TyParamBound {
-        let cx = super::ctxtkey.get().unwrap();
+        let cx = get_cx();
         let tcx = match cx.maybe_typed {
             core::Typed(ref tcx) => tcx,
             core::NotTyped(_) => return RegionBound,
@@ -550,7 +557,7 @@ fn clean(&self) -> TyParamBound {
 
 impl Clean<TyParamBound> for ty::TraitRef {
     fn clean(&self) -> TyParamBound {
-        let cx = super::ctxtkey.get().unwrap();
+        let cx = get_cx();
         let tcx = match cx.maybe_typed {
             core::Typed(ref tcx) => tcx,
             core::NotTyped(_) => return RegionBound,
@@ -709,8 +716,9 @@ fn clean(&self) -> Item {
             name: Some(self.ident.clean()),
             attrs: self.attrs.clean().move_iter().collect(),
             source: self.span.clean(),
-            def_id: ast_util::local_def(self.id.clone()),
+            def_id: ast_util::local_def(self.id),
             visibility: self.vis.clean(),
+            stability: get_stability(ast_util::local_def(self.id)),
             inner: MethodItem(Method {
                 generics: self.generics.clean(),
                 self_: self.explicit_self.node.clean(),
@@ -749,6 +757,7 @@ fn clean(&self) -> Item {
             source: self.span.clean(),
             def_id: ast_util::local_def(self.id),
             visibility: None,
+            stability: get_stability(ast_util::local_def(self.id)),
             inner: TyMethodItem(TyMethod {
                 fn_style: self.fn_style.clone(),
                 decl: decl,
@@ -792,6 +801,7 @@ fn clean(&self) -> Item {
             attrs: self.attrs.clean(),
             source: self.where.clean(),
             visibility: self.vis.clean(),
+            stability: self.stab.clean(),
             def_id: ast_util::local_def(self.id),
             inner: FunctionItem(Function {
                 decl: self.decl.clean(),
@@ -854,14 +864,10 @@ fn clean(&self) -> FnDecl {
 
 impl<'a> Clean<FnDecl> for (ast::DefId, &'a ty::FnSig) {
     fn clean(&self) -> FnDecl {
-        let cx = super::ctxtkey.get().unwrap();
-        let tcx = match cx.maybe_typed {
-            core::Typed(ref tcx) => tcx,
-            core::NotTyped(_) => unreachable!(),
-        };
+        let cx = get_cx();
         let (did, sig) = *self;
         let mut names = if did.node != 0 {
-            csearch::get_method_arg_names(&tcx.sess.cstore, did).move_iter()
+            csearch::get_method_arg_names(&cx.tcx().sess.cstore, did).move_iter()
         } else {
             Vec::new().move_iter()
         }.peekable();
@@ -932,6 +938,7 @@ fn clean(&self) -> Item {
             source: self.where.clean(),
             def_id: ast_util::local_def(self.id),
             visibility: self.vis.clean(),
+            stability: self.stab.clean(),
             inner: TraitItem(Trait {
                 methods: self.methods.clean(),
                 generics: self.generics.clean(),
@@ -985,11 +992,7 @@ fn clean(&self) -> TraitMethod {
 
 impl Clean<Item> for ty::Method {
     fn clean(&self) -> Item {
-        let cx = super::ctxtkey.get().unwrap();
-        let tcx = match cx.maybe_typed {
-            core::Typed(ref tcx) => tcx,
-            core::NotTyped(_) => unreachable!(),
-        };
+        let cx = get_cx();
         let (self_, sig) = match self.explicit_self {
             ast::SelfStatic => (ast::SelfStatic.clean(), self.fty.sig.clone()),
             s => {
@@ -1015,8 +1018,9 @@ fn clean(&self) -> Item {
         Item {
             name: Some(self.ident.clean()),
             visibility: Some(ast::Inherited),
+            stability: get_stability(self.def_id),
             def_id: self.def_id,
-            attrs: inline::load_attrs(tcx, self.def_id),
+            attrs: inline::load_attrs(cx.tcx(), self.def_id),
             source: Span::empty(),
             inner: TyMethodItem(TyMethod {
                 fn_style: self.fty.fn_style,
@@ -1261,12 +1265,7 @@ fn clean(&self) -> Type {
             ty::ty_struct(did, ref substs) |
             ty::ty_enum(did, ref substs) |
             ty::ty_trait(box ty::TyTrait { def_id: did, ref substs, .. }) => {
-                let cx = super::ctxtkey.get().unwrap();
-                let tcx = match cx.maybe_typed {
-                    core::Typed(ref tycx) => tycx,
-                    core::NotTyped(_) => unreachable!(),
-                };
-                let fqn = csearch::get_item_path(tcx, did);
+                let fqn = csearch::get_item_path(get_cx().tcx(), did);
                 let fqn: Vec<String> = fqn.move_iter().map(|i| {
                     i.to_str()
                 }).collect();
@@ -1277,8 +1276,8 @@ fn clean(&self) -> Type {
                 };
                 let path = external_path(fqn.last().unwrap().to_str().as_slice(),
                                          substs);
-                cx.external_paths.borrow_mut().get_mut_ref().insert(did,
-                                                                    (fqn, kind));
+                get_cx().external_paths.borrow_mut().get_mut_ref()
+                                       .insert(did, (fqn, kind));
                 ResolvedPath {
                     path: path,
                     typarams: None,
@@ -1318,6 +1317,7 @@ fn clean(&self) -> Item {
             attrs: self.node.attrs.clean().move_iter().collect(),
             source: self.span.clean(),
             visibility: Some(vis),
+            stability: get_stability(ast_util::local_def(self.node.id)),
             def_id: ast_util::local_def(self.node.id),
             inner: StructFieldItem(TypedStructField(self.node.ty.clean())),
         }
@@ -1332,17 +1332,14 @@ fn clean(&self) -> Item {
         } else {
             Some(self.name)
         };
-        let cx = super::ctxtkey.get().unwrap();
-        let tcx = match cx.maybe_typed {
-            core::Typed(ref tycx) => tycx,
-            core::NotTyped(_) => unreachable!(),
-        };
-        let ty = ty::lookup_item_type(tcx, self.id);
+        let cx = get_cx();
+        let ty = ty::lookup_item_type(cx.tcx(), self.id);
         Item {
             name: name.clean(),
-            attrs: inline::load_attrs(tcx, self.id),
+            attrs: inline::load_attrs(cx.tcx(), self.id),
             source: Span::empty(),
             visibility: Some(self.vis),
+            stability: get_stability(self.id),
             def_id: self.id,
             inner: StructFieldItem(TypedStructField(ty.ty.clean())),
         }
@@ -1373,6 +1370,7 @@ fn clean(&self) -> Item {
             source: self.where.clean(),
             def_id: ast_util::local_def(self.id),
             visibility: self.vis.clean(),
+            stability: self.stab.clean(),
             inner: StructItem(Struct {
                 struct_type: self.struct_type,
                 generics: self.generics.clean(),
@@ -1418,6 +1416,7 @@ fn clean(&self) -> Item {
             source: self.where.clean(),
             def_id: ast_util::local_def(self.id),
             visibility: self.vis.clean(),
+            stability: self.stab.clean(),
             inner: EnumItem(Enum {
                 variants: self.variants.clean(),
                 generics: self.generics.clean(),
@@ -1439,6 +1438,7 @@ fn clean(&self) -> Item {
             attrs: self.attrs.clean(),
             source: self.where.clean(),
             visibility: self.vis.clean(),
+            stability: self.stab.clean(),
             def_id: ast_util::local_def(self.id),
             inner: VariantItem(Variant {
                 kind: self.kind.clean(),
@@ -1450,11 +1450,7 @@ fn clean(&self) -> Item {
 impl Clean<Item> for ty::VariantInfo {
     fn clean(&self) -> Item {
         // use syntax::parse::token::special_idents::unnamed_field;
-        let cx = super::ctxtkey.get().unwrap();
-        let tcx = match cx.maybe_typed {
-            core::Typed(ref tycx) => tycx,
-            core::NotTyped(_) => fail!("tcx not present"),
-        };
+        let cx = get_cx();
         let kind = match self.arg_names.as_ref().map(|s| s.as_slice()) {
             None | Some([]) if self.args.len() == 0 => CLikeVariant,
             None | Some([]) => {
@@ -1470,6 +1466,7 @@ fn clean(&self) -> Item {
                             name: Some(name.clean()),
                             attrs: Vec::new(),
                             visibility: Some(ast::Public),
+                            stability: get_stability(self.id),
                             // FIXME: this is not accurate, we need an id for
                             //        the specific field but we're using the id
                             //        for the whole variant. Nothing currently
@@ -1485,11 +1482,12 @@ fn clean(&self) -> Item {
         };
         Item {
             name: Some(self.name.clean()),
-            attrs: inline::load_attrs(tcx, self.id),
+            attrs: inline::load_attrs(cx.tcx(), self.id),
             source: Span::empty(),
             visibility: Some(ast::Public),
             def_id: self.id,
             inner: VariantItem(Variant { kind: kind }),
+            stability: None,
         }
     }
 }
@@ -1626,6 +1624,7 @@ fn clean(&self) -> Item {
             source: self.where.clean(),
             def_id: ast_util::local_def(self.id.clone()),
             visibility: self.vis.clean(),
+            stability: self.stab.clean(),
             inner: TypedefItem(Typedef {
                 type_: self.ty.clean(),
                 generics: self.gen.clean(),
@@ -1675,6 +1674,7 @@ fn clean(&self) -> Item {
             source: self.where.clean(),
             def_id: ast_util::local_def(self.id),
             visibility: self.vis.clean(),
+            stability: self.stab.clean(),
             inner: StaticItem(Static {
                 type_: self.type_.clean(),
                 mutability: self.mutability.clean(),
@@ -1720,6 +1720,7 @@ fn clean(&self) -> Item {
             source: self.where.clean(),
             def_id: ast_util::local_def(self.id),
             visibility: self.vis.clean(),
+            stability: self.stab.clean(),
             inner: ImplItem(Impl {
                 generics: self.generics.clean(),
                 trait_: self.trait_.clean(),
@@ -1754,6 +1755,7 @@ fn clean(&self) -> Vec<Item> {
                 source: self.span.clean(),
                 def_id: ast_util::local_def(0),
                 visibility: self.vis.clean(),
+                stability: None,
                 inner: ViewItemItem(ViewItem { inner: node.clean() }),
             }
         };
@@ -1895,6 +1897,7 @@ fn clean(&self) -> Item {
             source: self.span.clean(),
             def_id: ast_util::local_def(self.id),
             visibility: self.vis.clean(),
+            stability: None,
             inner: inner,
         }
     }
@@ -1977,7 +1980,7 @@ fn name_from_pat(p: &ast::Pat) -> String {
 /// Given a Type, resolve it using the def_map
 fn resolve_type(path: Path, tpbs: Option<Vec<TyParamBound>>,
                 id: ast::NodeId) -> Type {
-    let cx = super::ctxtkey.get().unwrap();
+    let cx = get_cx();
     let tycx = match cx.maybe_typed {
         core::Typed(ref tycx) => tycx,
         // If we're extracting tests, this return value doesn't matter.
@@ -2012,7 +2015,7 @@ fn resolve_type(path: Path, tpbs: Option<Vec<TyParamBound>>,
         def::DefTyParamBinder(i) => return TyParamBinder(i),
         _ => {}
     };
-    let did = register_def(&**cx, def);
+    let did = register_def(&*cx, def);
     ResolvedPath { path: path, typarams: tpbs, did: did }
 }
 
@@ -2051,13 +2054,9 @@ fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
 }
 
 fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> {
-    let cx = super::ctxtkey.get().unwrap();
-    match cx.maybe_typed {
-        core::Typed(ref tcx) => {
-            tcx.def_map.borrow().find(&id).map(|&def| register_def(&**cx, def))
-        }
-        core::NotTyped(_) => None
-    }
+    get_cx().tcx_opt().and_then(|tcx| {
+        tcx.def_map.borrow().find(&id).map(|&def| register_def(&*get_cx(), def))
+    })
 }
 
 #[deriving(Clone, Encodable, Decodable)]
@@ -2072,6 +2071,7 @@ fn clean(&self) -> Item {
             attrs: self.attrs.clean(),
             source: self.where.clean(),
             visibility: ast::Public.clean(),
+            stability: self.stab.clean(),
             def_id: ast_util::local_def(self.id),
             inner: MacroItem(Macro {
                 source: self.where.to_src(),
@@ -2079,3 +2079,19 @@ fn clean(&self) -> Item {
         }
     }
 }
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Stability {
+    pub level: attr::StabilityLevel,
+    pub text: String
+}
+
+impl Clean<Stability> for attr::Stability {
+    fn clean(&self) -> Stability {
+        Stability {
+            level: self.level,
+            text: self.text.as_ref().map_or("".to_string(),
+                                            |interned| interned.get().to_string()),
+        }
+    }
+}
index ba0161da7e664054f9affe3d72cfc5c6c932c030..245b2d162a77b02c76632dd77042628834119b65 100644 (file)
@@ -10,7 +10,7 @@
 
 use rustc;
 use rustc::{driver, middle};
-use rustc::middle::privacy;
+use rustc::middle::{privacy, ty};
 use rustc::lint;
 
 use syntax::ast;
@@ -26,6 +26,7 @@
 use clean;
 use clean::Clean;
 
+/// Are we generating documentation (`Typed`) or tests (`NotTyped`)?
 pub enum MaybeTyped {
     Typed(middle::ty::ctxt),
     NotTyped(driver::session::Session)
@@ -52,6 +53,18 @@ pub fn sess<'a>(&'a self) -> &'a driver::session::Session {
             NotTyped(ref sess) => sess
         }
     }
+
+    pub fn tcx_opt<'a>(&'a self) -> Option<&'a ty::ctxt> {
+        match self.maybe_typed {
+            Typed(ref tcx) => Some(tcx),
+            NotTyped(_) => None
+        }
+    }
+
+    pub fn tcx<'a>(&'a self) -> &'a ty::ctxt {
+        let tcx_opt = self.tcx_opt();
+        tcx_opt.expect("tcx not present")
+    }
 }
 
 pub struct CrateAnalysis {
index b8a2a6195b7a539ab09507485823bc492960c544..313f1c81c79e81ba8df55f0d5af5fb24b11cd01a 100644 (file)
@@ -14,6 +14,7 @@
 use syntax;
 use syntax::codemap::Span;
 use syntax::ast;
+use syntax::attr;
 use syntax::ast::{Ident, NodeId};
 
 use std::gc::Gc;
@@ -32,6 +33,7 @@ pub struct Module {
     pub statics: Vec<Static>,
     pub traits: Vec<Trait>,
     pub vis: ast::Visibility,
+    pub stab: Option<attr::Stability>,
     pub impls: Vec<Impl>,
     pub foreigns: Vec<ast::ForeignMod>,
     pub view_items: Vec<ast::ViewItem>,
@@ -45,6 +47,7 @@ pub fn new(name: Option<Ident>) -> Module {
             name       : name,
             id: 0,
             vis: ast::Inherited,
+            stab: None,
             where_outer: syntax::codemap::DUMMY_SP,
             where_inner: syntax::codemap::DUMMY_SP,
             attrs      : Vec::new(),
@@ -83,6 +86,7 @@ pub enum TypeBound {
 
 pub struct Struct {
     pub vis: ast::Visibility,
+    pub stab: Option<attr::Stability>,
     pub id: NodeId,
     pub struct_type: StructType,
     pub name: Ident,
@@ -94,6 +98,7 @@ pub struct Struct {
 
 pub struct Enum {
     pub vis: ast::Visibility,
+    pub stab: Option<attr::Stability>,
     pub variants: Vec<Variant>,
     pub generics: ast::Generics,
     pub attrs: Vec<ast::Attribute>,
@@ -108,6 +113,7 @@ pub struct Variant {
     pub kind: ast::VariantKind,
     pub id: ast::NodeId,
     pub vis: ast::Visibility,
+    pub stab: Option<attr::Stability>,
     pub where: Span,
 }
 
@@ -117,6 +123,7 @@ pub struct Function {
     pub id: NodeId,
     pub name: Ident,
     pub vis: ast::Visibility,
+    pub stab: Option<attr::Stability>,
     pub fn_style: ast::FnStyle,
     pub where: Span,
     pub generics: ast::Generics,
@@ -130,6 +137,7 @@ pub struct Typedef {
     pub attrs: Vec<ast::Attribute>,
     pub where: Span,
     pub vis: ast::Visibility,
+    pub stab: Option<attr::Stability>,
 }
 
 pub struct Static {
@@ -139,6 +147,7 @@ pub struct Static {
     pub name: Ident,
     pub attrs: Vec<ast::Attribute>,
     pub vis: ast::Visibility,
+    pub stab: Option<attr::Stability>,
     pub id: ast::NodeId,
     pub where: Span,
 }
@@ -152,6 +161,7 @@ pub struct Trait {
     pub id: ast::NodeId,
     pub where: Span,
     pub vis: ast::Visibility,
+    pub stab: Option<attr::Stability>,
 }
 
 pub struct Impl {
@@ -162,6 +172,7 @@ pub struct Impl {
     pub attrs: Vec<ast::Attribute>,
     pub where: Span,
     pub vis: ast::Visibility,
+    pub stab: Option<attr::Stability>,
     pub id: ast::NodeId,
 }
 
@@ -170,6 +181,7 @@ pub struct Macro {
     pub id: ast::NodeId,
     pub attrs: Vec<ast::Attribute>,
     pub where: Span,
+    pub stab: Option<attr::Stability>,
 }
 
 pub fn struct_type_from_def(sd: &ast::StructDef) -> StructType {
index 77b12aec97b41bd72357bd709b329212d696871a..60853f450ab329dcb0a5d3ad5a5bedaf5d33a509 100644 (file)
@@ -19,7 +19,7 @@ fn fold_item(&mut self, item: Item) -> Option<Item> {
 
     /// don't override!
     fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
-        let Item { attrs, name, source, visibility, def_id, inner } = item;
+        let Item { attrs, name, source, visibility, def_id, inner, stability } = item;
         let inner = inner;
         let inner = match inner {
             StructItem(mut i) => {
@@ -83,7 +83,7 @@ fn vtrm<T: DocFolder>(this: &mut T, trm: TraitMethod) -> Option<TraitMethod> {
         };
 
         Some(Item { attrs: attrs, name: name, source: source, inner: inner,
-                    visibility: visibility, def_id: def_id })
+                    visibility: visibility, stability: stability, def_id: def_id })
     }
 
     fn fold_mod(&mut self, m: Module) -> Module {
index fa18b6291be74140dce46cf3e5eba7f419fbc678..9677b9004cdf1a12e015b56191ab3426747f1e1d 100644 (file)
 pub struct Method<'a>(pub &'a clean::SelfTy, pub &'a clean::FnDecl);
 /// Similar to VisSpace, but used for mutability
 pub struct MutableSpace(pub clean::Mutability);
+/// Wrapper struct for properly emitting the stability level.
+pub struct Stability<'a>(pub &'a Option<clean::Stability>);
+/// Wrapper struct for emitting the stability level concisely.
+pub struct ConciseStability<'a>(pub &'a Option<clean::Stability>);
 
 impl VisSpace {
     pub fn get(&self) -> Option<ast::Visibility> {
@@ -596,3 +600,34 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         }
     }
 }
+
+impl<'a> fmt::Show for Stability<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let Stability(stab) = *self;
+        match *stab {
+            Some(ref stability) => {
+                write!(f, "<a class='stability {lvl}' title='{reason}'>{lvl}</a>",
+                       lvl = stability.level.to_str(),
+                       reason = stability.text)
+            }
+            None => Ok(())
+        }
+    }
+}
+
+impl<'a> fmt::Show for ConciseStability<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let ConciseStability(stab) = *self;
+        match *stab {
+            Some(ref stability) => {
+                write!(f, "<a class='stability {lvl}' title='{lvl}{colon}{reason}'></a>",
+                       lvl = stability.level.to_str(),
+                       colon = if stability.text.len() > 0 { ": " } else { "" },
+                       reason = stability.text)
+            }
+            None => {
+                write!(f, "<a class='stability Unmarked' title='No stability level'></a>")
+            }
+        }
+    }
+}
index f5d379c4bafa10844c903ec6789f3638ff0498e2..917eab4eeb9918e547fc2e42f105b85c83c2d516 100644 (file)
 use serialize::json::ToJson;
 use syntax::ast;
 use syntax::ast_util;
-use syntax::attr;
-use syntax::parse::token::InternedString;
 use rustc::util::nodemap::NodeSet;
 
 use clean;
 use doctree;
 use fold::DocFolder;
-use html::format::{VisSpace, Method, FnStyleSpace, MutableSpace};
+use html::format::{VisSpace, Method, FnStyleSpace, MutableSpace, Stability};
+use html::format::{ConciseStability};
 use html::highlight;
 use html::item_type::{ItemType, shortty};
 use html::item_type;
@@ -114,6 +113,15 @@ pub struct Implementor {
     generics: clean::Generics,
     trait_: clean::Type,
     for_: clean::Type,
+    stability: Option<clean::Stability>,
+}
+
+/// Metadata about implementations for a type.
+#[deriving(Clone)]
+pub struct Impl {
+    impl_: clean::Impl,
+    dox: Option<String>,
+    stability: Option<clean::Stability>,
 }
 
 /// This cache is used to store information about the `clean::Crate` being
@@ -137,7 +145,7 @@ pub struct Cache {
     ///
     /// The values of the map are a list of implementations and documentation
     /// found on that implementation.
-    pub impls: HashMap<ast::DefId, Vec<(clean::Impl, Option<String>)>>,
+    pub impls: HashMap<ast::DefId, Vec<Impl>>,
 
     /// Maintains a mapping of local crate node ids to the fully qualified name
     /// and "short type description" of that node. This is used when generating
@@ -550,7 +558,8 @@ fn collect(path: &Path, krate: &str,
             // going on). If they're in different crates then the crate defining
             // the trait will be interested in our implementation.
             if imp.def_id.krate == did.krate { continue }
-            try!(write!(&mut f, r#""impl{} {} for {}","#,
+            try!(write!(&mut f, r#""{}impl{} {} for {}","#,
+                        ConciseStability(&imp.stability),
                         imp.generics, imp.trait_, imp.for_));
         }
         try!(writeln!(&mut f, r"];"));
@@ -782,6 +791,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                             generics: i.generics.clone(),
                             trait_: i.trait_.get_ref().clone(),
                             for_: i.for_.clone(),
+                            stability: item.stability.clone(),
                         });
                     }
                     Some(..) | None => {}
@@ -967,7 +977,11 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                                 let v = self.impls.find_or_insert_with(did, |_| {
                                     Vec::new()
                                 });
-                                v.push((i, dox));
+                                v.push(Impl {
+                                    impl_: i,
+                                    dox: dox,
+                                    stability: item.stability.clone(),
+                                });
                             }
                             None => {}
                         }
@@ -1248,19 +1262,8 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         try!(write!(fmt, "<a class='{}' href=''>{}</a>",
                     shortty(self.item), self.item.name.get_ref().as_slice()));
 
-        // Write stability attributes
-        match attr::find_stability_generic(self.item.attrs.iter()) {
-            Some((ref stability, _)) => {
-                try!(write!(fmt,
-                       "<a class='stability {lvl}' title='{reason}'>{lvl}</a>",
-                       lvl = stability.level.to_str(),
-                       reason = match stability.text {
-                           Some(ref s) => (*s).clone(),
-                           None => InternedString::new(""),
-                       }));
-            }
-            None => {}
-        }
+        // Write stability level
+        try!(write!(fmt, "{}", Stability(&self.item.stability)));
 
         // Write `src` tag
         //
@@ -1454,10 +1457,11 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
                 try!(write!(w, "
                     <tr>
-                        <td><code>{}static {}{}: {}</code>{}</td>
+                        <td>{}<code>{}static {}{}: {}</code>{}</td>
                         <td class='docblock'>{}&nbsp;</td>
                     </tr>
                 ",
+                ConciseStability(&myitem.stability),
                 VisSpace(myitem.visibility),
                 MutableSpace(s.mutability),
                 *myitem.name.get_ref(),
@@ -1492,7 +1496,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 if myitem.name.is_none() { continue }
                 try!(write!(w, "
                     <tr>
-                        <td><a class='{class}' href='{href}'
+                        <td>{stab}<a class='{class}' href='{href}'
                                title='{title}'>{}</a></td>
                         <td class='docblock short'>{}</td>
                     </tr>
@@ -1501,7 +1505,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 Markdown(shorter(myitem.doc_value())),
                 class = shortty(myitem),
                 href = item_path(myitem),
-                title = full_path(cx, myitem)));
+                title = full_path(cx, myitem),
+                stab = ConciseStability(&myitem.stability)));
             }
         }
     }
@@ -1565,9 +1570,10 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     try!(document(w, it));
 
     fn meth(w: &mut fmt::Formatter, m: &clean::TraitMethod) -> fmt::Result {
-        try!(write!(w, "<h3 id='{}.{}' class='method'><code>",
-                      shortty(m.item()),
-                      *m.item().name.get_ref()));
+        try!(write!(w, "<h3 id='{}.{}' class='method'>{}<code>",
+                    shortty(m.item()),
+                    *m.item().name.get_ref(),
+                    ConciseStability(&m.item().stability)));
         try!(render_method(w, m.item()));
         try!(write!(w, "</code></h3>"));
         try!(document(w, m.item()));
@@ -1604,7 +1610,8 @@ fn meth(w: &mut fmt::Formatter, m: &clean::TraitMethod) -> fmt::Result {
     match cache.implementors.find(&it.def_id) {
         Some(implementors) => {
             for i in implementors.iter() {
-                try!(writeln!(w, "<li><code>impl{} {} for {}</code></li>",
+                try!(writeln!(w, "<li>{}<code>impl{} {} for {}</code></li>",
+                              ConciseStability(&i.stability),
                               i.generics, i.trait_, i.for_));
             }
         }
@@ -1677,7 +1684,8 @@ fn item_struct(w: &mut fmt::Formatter, it: &clean::Item,
             try!(write!(w, "<h2 class='fields'>Fields</h2>\n<table>"));
             for field in fields {
                 try!(write!(w, "<tr><td id='structfield.{name}'>\
-                                  <code>{name}</code></td><td>",
+                                  {stab}<code>{name}</code></td><td>",
+                              stab = ConciseStability(&field.stability),
                               name = field.name.get_ref().as_slice()));
                 try!(document(w, field));
                 try!(write!(w, "</td></tr>"));
@@ -1743,7 +1751,8 @@ fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
     if e.variants.len() > 0 {
         try!(write!(w, "<h2 class='variants'>Variants</h2>\n<table>"));
         for variant in e.variants.iter() {
-            try!(write!(w, "<tr><td id='variant.{name}'><code>{name}</code></td><td>",
+            try!(write!(w, "<tr><td id='variant.{name}'>{stab}<code>{name}</code></td><td>",
+                          stab = ConciseStability(&variant.stability),
                           name = variant.name.get_ref().as_slice()));
             try!(document(w, variant));
             match variant.inner {
@@ -1853,39 +1862,25 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
 fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
     match cache_key.get().unwrap().impls.find(&it.def_id) {
         Some(v) => {
-            let mut non_trait = v.iter().filter(|p| {
-                p.ref0().trait_.is_none()
-            });
-            let non_trait = non_trait.collect::<Vec<&(clean::Impl, Option<String>)>>();
-            let mut traits = v.iter().filter(|p| {
-                p.ref0().trait_.is_some()
-            });
-            let traits = traits.collect::<Vec<&(clean::Impl, Option<String>)>>();
-
+            let (non_trait, traits) = v.partitioned(|i| i.impl_.trait_.is_none());
             if non_trait.len() > 0 {
                 try!(write!(w, "<h2 id='methods'>Methods</h2>"));
-                for &(ref i, ref dox) in non_trait.move_iter() {
-                    try!(render_impl(w, i, dox));
+                for i in non_trait.iter() {
+                    try!(render_impl(w, i));
                 }
             }
             if traits.len() > 0 {
                 try!(write!(w, "<h2 id='implementations'>Trait \
                                   Implementations</h2>"));
-                let mut any_derived = false;
-                for & &(ref i, ref dox) in traits.iter() {
-                    if !i.derived {
-                        try!(render_impl(w, i, dox));
-                    } else {
-                        any_derived = true;
-                    }
+                let (derived, manual) = traits.partition(|i| i.impl_.derived);
+                for i in manual.iter() {
+                    try!(render_impl(w, i));
                 }
-                if any_derived {
+                if derived.len() > 0 {
                     try!(write!(w, "<h3 id='derived_implementations'>Derived Implementations \
                                 </h3>"));
-                    for &(ref i, ref dox) in traits.move_iter() {
-                        if i.derived {
-                            try!(render_impl(w, i, dox));
-                        }
+                    for i in derived.iter() {
+                        try!(render_impl(w, i));
                     }
                 }
             }
@@ -1895,15 +1890,16 @@ fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
     Ok(())
 }
 
-fn render_impl(w: &mut fmt::Formatter, i: &clean::Impl,
-               dox: &Option<String>) -> fmt::Result {
-    try!(write!(w, "<h3 class='impl'><code>impl{} ", i.generics));
-    match i.trait_ {
+fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
+    try!(write!(w, "<h3 class='impl'>{}<code>impl{} ",
+                ConciseStability(&i.stability),
+                i.impl_.generics));
+    match i.impl_.trait_ {
         Some(ref ty) => try!(write!(w, "{} for ", *ty)),
         None => {}
     }
-    try!(write!(w, "{}</code></h3>", i.for_));
-    match *dox {
+    try!(write!(w, "{}</code></h3>", i.impl_.for_));
+    match i.dox {
         Some(ref dox) => {
             try!(write!(w, "<div class='docblock'>{}</div>",
                           Markdown(dox.as_slice())));
@@ -1913,8 +1909,9 @@ fn render_impl(w: &mut fmt::Formatter, i: &clean::Impl,
 
     fn docmeth(w: &mut fmt::Formatter, item: &clean::Item,
                dox: bool) -> fmt::Result {
-        try!(write!(w, "<h4 id='method.{}' class='method'><code>",
-                      *item.name.get_ref()));
+        try!(write!(w, "<h4 id='method.{}' class='method'>{}<code>",
+                    *item.name.get_ref(),
+                    ConciseStability(&item.stability)));
         try!(render_method(w, item));
         try!(write!(w, "</code></h4>\n"));
         match item.doc_value() {
@@ -1926,8 +1923,8 @@ fn docmeth(w: &mut fmt::Formatter, item: &clean::Item,
         }
     }
 
-    try!(write!(w, "<div class='methods'>"));
-    for meth in i.methods.iter() {
+    try!(write!(w, "<div class='impl-methods'>"));
+    for meth in i.impl_.methods.iter() {
         try!(docmeth(w, meth, true));
     }
 
@@ -1948,11 +1945,11 @@ fn render_default_methods(w: &mut fmt::Formatter,
 
     // If we've implemented a trait, then also emit documentation for all
     // default methods which weren't overridden in the implementation block.
-    match i.trait_ {
+    match i.impl_.trait_ {
         Some(clean::ResolvedPath { did, .. }) => {
             try!({
                 match cache_key.get().unwrap().traits.find(&did) {
-                    Some(t) => try!(render_default_methods(w, t, i)),
+                    Some(t) => try!(render_default_methods(w, t, &i.impl_)),
                     None => {}
                 }
                 Ok(())
index a88992f6c4c508344f3ebac359ff0bdfb0f69072..97048229ac4c1842180a90c6ace19b7c5dff06a0 100644 (file)
@@ -258,8 +258,9 @@ nav.sub {
 .content .multi-column li { width: 100%; display: inline-block; }
 
 .content .method { font-size: 1em; }
-.content .methods { margin-left: 20px; }
-.content .methods .docblock { margin-left: 20px; }
+.content .methods .docblock { margin-left: 40px; }
+
+.content .impl-methods .docblock { margin-left: 40px; }
 
 nav {
     border-bottom: 1px solid #e0e0e0;
@@ -372,20 +373,29 @@ p a:hover { text-decoration: underline; }
 }
 
 .stability {
-    border-left: 6px solid #000;
+    border-left: 6px solid;
+    padding: 3px 6px;
     border-radius: 3px;
-    font-weight: 400;
-    padding: 4px 10px;
+}
+
+h1 .stability {
     text-transform: lowercase;
+    font-weight: 400;
     margin-left: 14px;
+    padding: 4px 10px;
+}
+
+.impl-methods .stability {
+    margin-right: 20px;
 }
 
-.stability.Deprecated { border-color: #D60027; color: #880017; }
-.stability.Experimental { border-color: #EC5315; color: #a53c0e; }
-.stability.Unstable { border-color: #FFD700; color: #b39800; }
-.stability.Stable { border-color: #AEC516; color: #7c8b10; }
+.stability.Deprecated { border-color: #A071A8; color: #82478C; }
+.stability.Experimental { border-color: #D46D6A; color: #AA3C39; }
+.stability.Unstable { border-color: #D4B16A; color: #AA8439; }
+.stability.Stable { border-color: #54A759; color: #2D8632; }
 .stability.Frozen { border-color: #009431; color: #007726; }
 .stability.Locked { border-color: #0084B6; color: #00668c; }
+.stability.Unmarked { border-color: #FFFFFF; }
 
 :target { background: #FDFFD3; }
 
index 00fe0134f00ee356907c2f725e4f7adf4116c9cb..b7ef0956a7c7640a57593b0fbf133405d1b570cc 100644 (file)
 use syntax::ast;
 use syntax::ast_util;
 use syntax::ast_map;
+use syntax::attr;
 use syntax::attr::AttrMetaMethods;
 use syntax::codemap::Span;
 
+use rustc::middle::stability;
+
 use std::gc::{Gc, GC};
 
 use core;
@@ -41,6 +44,14 @@ pub fn new<'b>(cx: &'b core::DocContext,
         }
     }
 
+    fn stability(&self, id: ast::NodeId) -> Option<attr::Stability> {
+        let tcx = match self.cx.maybe_typed {
+            core::Typed(ref tcx) => tcx,
+            core::NotTyped(_) => return None
+        };
+        stability::lookup(tcx, ast_util::local_def(id))
+    }
+
     pub fn visit(&mut self, krate: &ast::Crate) {
         self.attrs = krate.attrs.iter().map(|x| (*x).clone()).collect();
 
@@ -65,6 +76,7 @@ pub fn visit_struct_def(&mut self, item: &ast::Item, sd: Gc<ast::StructDef>,
             struct_type: struct_type,
             name: item.ident,
             vis: item.vis,
+            stab: self.stability(item.id),
             attrs: item.attrs.iter().map(|x| *x).collect(),
             generics: generics.clone(),
             fields: sd.fields.iter().map(|x| (*x).clone()).collect(),
@@ -81,6 +93,7 @@ pub fn visit_enum_def(&mut self, it: &ast::Item, def: &ast::EnumDef,
                 name: x.node.name,
                 attrs: x.node.attrs.iter().map(|x| *x).collect(),
                 vis: x.node.vis,
+                stab: self.stability(x.node.id),
                 id: x.node.id,
                 kind: x.node.kind.clone(),
                 where: x.span,
@@ -90,6 +103,7 @@ pub fn visit_enum_def(&mut self, it: &ast::Item, def: &ast::EnumDef,
             name: it.ident,
             variants: vars,
             vis: it.vis,
+            stab: self.stability(it.id),
             generics: params.clone(),
             attrs: it.attrs.iter().map(|x| *x).collect(),
             id: it.id,
@@ -104,6 +118,7 @@ pub fn visit_fn(&mut self, item: &ast::Item, fd: &ast::FnDecl,
         Function {
             id: item.id,
             vis: item.vis,
+            stab: self.stability(item.id),
             attrs: item.attrs.iter().map(|x| *x).collect(),
             decl: fd.clone(),
             name: item.ident,
@@ -125,6 +140,7 @@ pub fn visit_mod_contents(&mut self, span: Span, attrs: Vec<ast::Attribute> ,
         om.where_inner = m.inner;
         om.attrs = attrs;
         om.vis = vis;
+        om.stab = self.stability(id);
         om.id = id;
         for i in m.items.iter() {
             self.visit_item(&**i, &mut om);
@@ -258,6 +274,7 @@ pub fn visit_item(&mut self, item: &ast::Item, om: &mut Module) {
                     attrs: item.attrs.iter().map(|x| *x).collect(),
                     where: item.span,
                     vis: item.vis,
+                    stab: self.stability(item.id),
                 };
                 om.typedefs.push(t);
             },
@@ -271,6 +288,7 @@ pub fn visit_item(&mut self, item: &ast::Item, om: &mut Module) {
                     attrs: item.attrs.iter().map(|x| *x).collect(),
                     where: item.span,
                     vis: item.vis,
+                    stab: self.stability(item.id),
                 };
                 om.statics.push(s);
             },
@@ -284,6 +302,7 @@ pub fn visit_item(&mut self, item: &ast::Item, om: &mut Module) {
                     attrs: item.attrs.iter().map(|x| *x).collect(),
                     where: item.span,
                     vis: item.vis,
+                    stab: self.stability(item.id),
                 };
                 om.traits.push(t);
             },
@@ -297,6 +316,7 @@ pub fn visit_item(&mut self, item: &ast::Item, om: &mut Module) {
                     id: item.id,
                     where: item.span,
                     vis: item.vis,
+                    stab: self.stability(item.id),
                 };
                 om.impls.push(i);
             },
@@ -309,6 +329,7 @@ pub fn visit_item(&mut self, item: &ast::Item, om: &mut Module) {
                     attrs: item.attrs.iter().map(|x| *x).collect(),
                     name: item.ident,
                     where: item.span,
+                    stab: self.stability(item.id),
                 })
             }
         }
diff --git a/src/test/run-fail/by-value-self-objects-fail.rs b/src/test/run-fail/by-value-self-objects-fail.rs
new file mode 100644 (file)
index 0000000..7488926
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:explicit failure
+
+trait Foo {
+    fn foo(self, x: int);
+}
+
+struct S {
+    x: int,
+    y: int,
+    z: int,
+    s: String,
+}
+
+impl Foo for S {
+    fn foo(self, x: int) {
+        fail!()
+    }
+}
+
+impl Drop for S {
+    fn drop(&mut self) {
+        println!("bye 1!");
+    }
+}
+
+fn f() {
+    let s = S {
+        x: 2,
+        y: 3,
+        z: 4,
+        s: "hello".to_string(),
+    };
+    let st = box s as Box<Foo>;
+    st.foo(5);
+}
+
+fn main() {
+    f();
+}
+
+
diff --git a/src/test/run-pass/by-value-self-objects.rs b/src/test/run-pass/by-value-self-objects.rs
new file mode 100644 (file)
index 0000000..3a58836
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+static mut destructor_count: uint = 0;
+
+trait Foo {
+    fn foo(self, x: int);
+}
+
+struct S {
+    x: int,
+    y: int,
+    z: int,
+    s: String,
+}
+
+impl Foo for S {
+    fn foo(self, x: int) {
+        assert!(self.x == 2);
+        assert!(self.y == 3);
+        assert!(self.z == 4);
+        assert!(self.s.as_slice() == "hello");
+        assert!(x == 5);
+    }
+}
+
+impl Drop for S {
+    fn drop(&mut self) {
+        println!("bye 1!");
+        unsafe {
+            destructor_count += 1;
+        }
+    }
+}
+
+impl Foo for int {
+    fn foo(self, x: int) {
+        println!("{}", x * x);
+    }
+}
+
+fn f() {
+    let s = S {
+        x: 2,
+        y: 3,
+        z: 4,
+        s: "hello".to_string(),
+    };
+    let st = box s as Box<Foo>;
+    st.foo(5);
+    println!("bye 2!");
+}
+
+fn g() {
+    let s = 2i;
+    let st = box s as Box<Foo>;
+    st.foo(3);
+    println!("bye 3!");
+}
+
+fn main() {
+    f();
+
+    unsafe {
+        assert!(destructor_count == 1);
+    }
+
+    g();
+}
+
index 1258a498dacb4e4368918588176ebc2bfbf7be29..e349f91a309f7f301f1a4d04d6badff2948e16f0 100644 (file)
@@ -81,6 +81,9 @@ pub fn main() {
     t!(format!("{foo_bar}", foo_bar=1i), "1");
     t!(format!("{:d}", 5i + 5i), "10");
 
+    let a: &fmt::Show = &1i;
+    t!(format!("{}", a), "1");
+
     // Formatting strings and their arguments
     t!(format!("{:s}", "a"), "a");
     t!(format!("{:4s}", "a"), "a   ");