Change:
Where we would normally put "^^^ did you mean Up" under mistyped names, I noticed that we don't do that for enum variants. Here's an example I just saw: !
Taking a look.

Discussion:
#![feature(slice_get_slice)] #![feature(slice_patterns)] #![feature(slice_rsplit)] <ins> #![feature(slice_sort_by_cached_key)] </ins> #![feature(specialization)] #![feature(staged_api)] #![feature(str_internals)]

use core::mem; use core::ptr; use core::slice as core_slice; <ins> use core::{u8, u16, u32}; </ins> use borrow::{Borrow, BorrowMut, ToOwned}; use boxed::Box;

/// Sorts the slice with a key extraction function. /// <del> /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case. </del> <ins> /// This sort is stable (i.e. does not reorder equal elements) and `O(m n log m n)` /// worst-case, where the key function is `O(m)`. /// /// For expensive key functions (e.g. functions that are not simple property accesses or /// basic operations), [`sort_by_cached_key`](#method.sort_by_cached_key) is likely to be /// significantly faster, as it does not recompute element keys. </ins> /// /// When applicable, unstable sorting is preferred because it is generally faster than stable /// sorting and it doesn't allocate auxiliary memory.

/// ``` #[stable(feature = "slice_sort_by_key", since = "1.7.0")] #[inline] <del> pub fn sort_by_key<B, F>(&mut self, mut f: F) where F: FnMut(&T) -> B, B: Ord </del> <ins> pub fn sort_by_key<K, F>(&mut self, mut f: F) where F: FnMut(&T) -> K, K: Ord </ins> { merge_sort(self, |a, b| f(a).lt(&f(b))); } <ins> /// Sorts the slice with a key extraction function. /// /// During sorting, the key function is called only once per element. /// /// This sort is stable (i.e. does not reorder equal elements) and `O(m n + n log n)` /// worst-case, where the key function is `O(m)`. /// /// For simple key functions (e.g. functions that are property accesses or /// basic operations), [`sort_by_key`](#method.sort_by_key) is likely to be /// faster. /// /// # Current implementation /// /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, /// which combines the fast average case of randomized quicksort with the fast worst case of /// heapsort, while achieving linear time on slices with certain patterns. It uses some /// randomization to avoid degenerate cases, but with a fixed seed to always provide /// deterministic behavior. /// /// In the worst case, the algorithm allocates temporary storage in a `Vec<(K, usize)>` the /// length of the slice. /// /// # Examples /// /// ``` /// let mut v = [-5i32, 4, 32, -3, 2]; /// /// v.sort_by_cached_key(|k| k.to_string()); /// assert!(v == [-3, -5, 2, 32, 4]); /// ``` /// /// [pdqsort]: https://github.com/orlp/pdqsort #[unstable(feature = "slice_sort_by_cached_key", issue = "34447")] #[inline] pub fn sort_by_cached_key<K, F>(&mut self, f: F) where F: FnMut(&T) -> K, K: Ord { // Helper macro for indexing our vector by the smallest possible type, to reduce allocation. macro_rules! sort_by_key { ($t:ty, $slice:ident, $f:ident) => ({ let mut indices: Vec<_> = $slice.iter().map($f).enumerate().map(|(i, k)| (k, i as $t)).collect(); // The elements of `indices` are unique, as they are indexed, so any sort will be // stable with respect to the original slice. We use `sort_unstable` here because it // requires less memory allocation. indices.sort_unstable(); for i in 0..$slice.len() { let mut index = indices[i].1; while (index as usize) < i { index = indices[index as usize].1; } indices[i].1 = index; $slice.swap(i, index as usize); } }) } let len = self.len(); if len <= ( u8::MAX as usize) { return sort_by_key!( u8, self, f) } if len <= (u16::MAX as usize) { return sort_by_key!(u16, self, f) } if len <= (u32::MAX as usize) { return sort_by_key!(u32, self, f) } sort_by_key!(usize, self, f) } </ins> /// Sorts the slice, but may not preserve the order of equal elements. /// /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate),

/// elements. /// /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), <del> /// and `O(n log n)` worst-case. </del> <ins> /// and `O(m n log m n)` worst-case, where the key function is `O(m)`. </ins> /// /// # Current implementation ///

/// randomization to avoid degenerate cases, but with a fixed seed to always provide /// deterministic behavior. /// <del> /// It is typically faster than stable sorting, except in a few special cases, e.g. when the /// slice consists of several concatenated sorted sequences. </del> <ins> /// Due to its key calling strategy, [`sort_unstable_by_key`](#method.sort_unstable_by_key) /// is likely to be slower than [`sort_by_cached_key`](#method.sort_by_cached_key) in /// cases where the key function is expensive. </ins> /// /// # Examples ///

/// [pdqsort]: https://github.com/orlp/pdqsort #[stable(feature = "sort_unstable", since = "1.20.0")] #[inline] <del> pub fn sort_unstable_by_key<B, F>(&mut self, f: F) where F: FnMut(&T) -> B, B: Ord </del> <ins> pub fn sort_unstable_by_key<K, F>(&mut self, f: F) where F: FnMut(&T) -> K, K: Ord </ins> { core_slice::SliceExt::sort_unstable_by_key(self, f); }

#![feature(pattern)] #![feature(placement_in_syntax)] #![feature(rand)] <ins> #![feature(slice_sort_by_cached_key)] </ins> #![feature(splice)] #![feature(str_escape)] #![feature(string_retain)]

v.sort_by(|a, b| b.cmp(a)); assert!(v.windows(2).all(|w| w[0] >= w[1])); <ins> // Sort in lexicographic order. let mut v1 = orig.clone(); let mut v2 = orig.clone(); v1.sort_by_key(|x| x.to_string()); v2.sort_by_cached_key(|x| x.to_string()); assert!(v1.windows(2).all(|w| w[0].to_string() <= w[1].to_string())); assert!(v1 == v2); </ins> // Sort with many pre-sorted runs. let mut v = orig.clone(); v.sort();