Auto merge of #54575 - pietroalbini:rollup, r=pietroalbini
Rollup of 12 pull requests Successful merges: - #53518 (Add doc for impl From in char_convert) - #54058 (Introduce the partition_dedup/by/by_key methods for slices) - #54281 (Search box) - #54368 (Reduce code block sides padding) - #54498 (The project moved under the Mozilla umbrella) - #54518 (resolve: Do not block derive helper resolutions on single import resolutions) - #54522 (Fixed three small typos.) - #54529 (aarch64-pc-windows-msvc: Don't link libpanic_unwind to libtest.) - #54537 (Rename slice::exact_chunks() to slice::chunks_exact()) - #54539 (Fix js error) - #54557 (incr.comp.: Don't automatically enable -Zshare-generics for incr. comp. builds.) - #54558 (Improvements to finding LLVM's FileCheck) Failed merges: r? @ghost
This commit is contained in:
commit
92aff72a05
27 changed files with 538 additions and 224 deletions
|
|
@ -322,6 +322,7 @@
|
|||
|
||||
# Flag indicating whether codegen tests will be run or not. If you get an error
|
||||
# saying that the FileCheck executable is missing, you may want to disable this.
|
||||
# Also see the target's llvm-filecheck option.
|
||||
#codegen-tests = true
|
||||
|
||||
# Flag indicating whether git info will be retrieved from .git automatically.
|
||||
|
|
@ -416,6 +417,10 @@
|
|||
# target.
|
||||
#llvm-config = "../path/to/llvm/root/bin/llvm-config"
|
||||
|
||||
# Normally the build system can find LLVM's FileCheck utility, but if
|
||||
# not, you can specify an explicit file name for it.
|
||||
#llvm-filecheck = "/path/to/FileCheck"
|
||||
|
||||
# Path to the custom jemalloc static library to link into the standard library
|
||||
# by default. This is only used if jemalloc is still enabled above
|
||||
#jemalloc = "/path/to/jemalloc/libjemalloc_pic.a"
|
||||
|
|
|
|||
|
|
@ -162,6 +162,8 @@ pub struct Config {
|
|||
pub struct Target {
|
||||
/// Some(path to llvm-config) if using an external LLVM.
|
||||
pub llvm_config: Option<PathBuf>,
|
||||
/// Some(path to FileCheck) if one was specified.
|
||||
pub llvm_filecheck: Option<PathBuf>,
|
||||
pub jemalloc: Option<PathBuf>,
|
||||
pub cc: Option<PathBuf>,
|
||||
pub cxx: Option<PathBuf>,
|
||||
|
|
@ -330,6 +332,7 @@ struct Rust {
|
|||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
struct TomlTarget {
|
||||
llvm_config: Option<String>,
|
||||
llvm_filecheck: Option<String>,
|
||||
jemalloc: Option<String>,
|
||||
cc: Option<String>,
|
||||
cxx: Option<String>,
|
||||
|
|
@ -583,6 +586,9 @@ impl Config {
|
|||
if let Some(ref s) = cfg.llvm_config {
|
||||
target.llvm_config = Some(config.src.join(s));
|
||||
}
|
||||
if let Some(ref s) = cfg.llvm_filecheck {
|
||||
target.llvm_filecheck = Some(config.src.join(s));
|
||||
}
|
||||
if let Some(ref s) = cfg.jemalloc {
|
||||
target.jemalloc = Some(config.src.join(s));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,6 +95,8 @@ v("docdir", "install.docdir", "install documentation in PATH")
|
|||
v("bindir", "install.bindir", "install binaries")
|
||||
|
||||
v("llvm-root", None, "set LLVM root")
|
||||
v("llvm-config", None, "set path to llvm-config")
|
||||
v("llvm-filecheck", None, "set path to LLVM's FileCheck utility")
|
||||
v("python", "build.python", "set path to python")
|
||||
v("jemalloc-root", None, "set directory where libjemalloc_pic.a is located")
|
||||
v("android-cross-path", "target.arm-linux-androideabi.android-ndk",
|
||||
|
|
@ -323,6 +325,10 @@ for key in known_args:
|
|||
set('build.cargo', value + '/bin/cargo')
|
||||
elif option.name == 'llvm-root':
|
||||
set('target.{}.llvm-config'.format(build()), value + '/bin/llvm-config')
|
||||
elif option.name == 'llvm-config':
|
||||
set('target.{}.llvm-config'.format(build()), value)
|
||||
elif option.name == 'llvm-filecheck':
|
||||
set('target.{}.llvm-filecheck'.format(build()), value)
|
||||
elif option.name == 'jemalloc-root':
|
||||
set('target.{}.jemalloc'.format(build()), value + '/libjemalloc_pic.a')
|
||||
elif option.name == 'tools':
|
||||
|
|
|
|||
|
|
@ -641,9 +641,28 @@ impl Build {
|
|||
/// Returns the path to `FileCheck` binary for the specified target
|
||||
fn llvm_filecheck(&self, target: Interned<String>) -> PathBuf {
|
||||
let target_config = self.config.target_config.get(&target);
|
||||
if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
|
||||
if let Some(s) = target_config.and_then(|c| c.llvm_filecheck.as_ref()) {
|
||||
s.to_path_buf()
|
||||
} else if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
|
||||
let llvm_bindir = output(Command::new(s).arg("--bindir"));
|
||||
Path::new(llvm_bindir.trim()).join(exe("FileCheck", &*target))
|
||||
let filecheck = Path::new(llvm_bindir.trim()).join(exe("FileCheck", &*target));
|
||||
if filecheck.exists() {
|
||||
filecheck
|
||||
} else {
|
||||
// On Fedora the system LLVM installs FileCheck in the
|
||||
// llvm subdirectory of the libdir.
|
||||
let llvm_libdir = output(Command::new(s).arg("--libdir"));
|
||||
let lib_filecheck = Path::new(llvm_libdir.trim())
|
||||
.join("llvm").join(exe("FileCheck", &*target));
|
||||
if lib_filecheck.exists() {
|
||||
lib_filecheck
|
||||
} else {
|
||||
// Return the most normal file name, even though
|
||||
// it doesn't exist, so that any error message
|
||||
// refers to that.
|
||||
filecheck
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let base = self.llvm_out(self.config.build).join("build");
|
||||
let base = if !self.config.ninja && self.config.build.contains("msvc") {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,23 @@
|
|||
nav {
|
||||
display: none;
|
||||
}
|
||||
#search-input {
|
||||
width: calc(100% - 58px);
|
||||
}
|
||||
#search-but {
|
||||
cursor: pointer;
|
||||
}
|
||||
#search-but, #search-input {
|
||||
padding: 4px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 3px;
|
||||
outline: none;
|
||||
font-size: 0.7em;
|
||||
background-color: #fff;
|
||||
}
|
||||
#search-but:hover, #search-input:focus {
|
||||
border-color: #55a9ff;
|
||||
}
|
||||
</style>
|
||||
|
||||
Welcome to an overview of the documentation provided by the Rust project.
|
||||
|
|
@ -45,8 +62,9 @@ accomplishing various tasks.
|
|||
|
||||
<div>
|
||||
<form action="std/index.html" method="get">
|
||||
<input type="search" name="search"/>
|
||||
<button>Search</button>
|
||||
<input id="search-input" type="search" name="search"
|
||||
placeholder="Search through the standard library"/>
|
||||
<button id="search-but">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -18,4 +18,4 @@ cargo run
|
|||
```
|
||||
|
||||
Once you've built and run your program, files with the `gcno` (after build) and `gcda` (after execution) extensions will be created.
|
||||
You can parse them with [llvm-cov gcov](http://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-gcov) or [grcov](https://github.com/marco-c/grcov).
|
||||
You can parse them with [llvm-cov gcov](https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-gcov) or [grcov](https://github.com/mozilla/grcov).
|
||||
|
|
|
|||
|
|
@ -116,9 +116,10 @@
|
|||
#![feature(unsize)]
|
||||
#![feature(allocator_internals)]
|
||||
#![feature(on_unimplemented)]
|
||||
#![feature(exact_chunks)]
|
||||
#![feature(chunks_exact)]
|
||||
#![feature(rustc_const_unstable)]
|
||||
#![feature(const_vec_new)]
|
||||
#![feature(slice_partition_dedup)]
|
||||
#![feature(maybe_uninit)]
|
||||
|
||||
// Allow testing this library
|
||||
|
|
|
|||
|
|
@ -123,8 +123,8 @@ pub use core::slice::{from_raw_parts, from_raw_parts_mut};
|
|||
pub use core::slice::{from_ref, from_mut};
|
||||
#[stable(feature = "slice_get_slice", since = "1.28.0")]
|
||||
pub use core::slice::SliceIndex;
|
||||
#[unstable(feature = "exact_chunks", issue = "47115")]
|
||||
pub use core::slice::{ExactChunks, ExactChunksMut};
|
||||
#[unstable(feature = "chunks_exact", issue = "47115")]
|
||||
pub use core::slice::{ChunksExact, ChunksExactMut};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Basic slice extension methods
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#![feature(str_escape)]
|
||||
#![feature(try_reserve)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(exact_chunks)]
|
||||
#![feature(chunks_exact)]
|
||||
#![feature(repeat_generic_slice)]
|
||||
|
||||
extern crate alloc_system;
|
||||
|
|
|
|||
|
|
@ -975,27 +975,27 @@ fn test_chunksator_0() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_exact_chunksator() {
|
||||
fn test_chunks_exactator() {
|
||||
let v = &[1, 2, 3, 4, 5];
|
||||
|
||||
assert_eq!(v.exact_chunks(2).len(), 2);
|
||||
assert_eq!(v.chunks_exact(2).len(), 2);
|
||||
|
||||
let chunks: &[&[_]] = &[&[1, 2], &[3, 4]];
|
||||
assert_eq!(v.exact_chunks(2).collect::<Vec<_>>(), chunks);
|
||||
assert_eq!(v.chunks_exact(2).collect::<Vec<_>>(), chunks);
|
||||
let chunks: &[&[_]] = &[&[1, 2, 3]];
|
||||
assert_eq!(v.exact_chunks(3).collect::<Vec<_>>(), chunks);
|
||||
assert_eq!(v.chunks_exact(3).collect::<Vec<_>>(), chunks);
|
||||
let chunks: &[&[_]] = &[];
|
||||
assert_eq!(v.exact_chunks(6).collect::<Vec<_>>(), chunks);
|
||||
assert_eq!(v.chunks_exact(6).collect::<Vec<_>>(), chunks);
|
||||
|
||||
let chunks: &[&[_]] = &[&[3, 4], &[1, 2]];
|
||||
assert_eq!(v.exact_chunks(2).rev().collect::<Vec<_>>(), chunks);
|
||||
assert_eq!(v.chunks_exact(2).rev().collect::<Vec<_>>(), chunks);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_exact_chunksator_0() {
|
||||
fn test_chunks_exactator_0() {
|
||||
let v = &[1, 2, 3, 4];
|
||||
let _it = v.exact_chunks(0);
|
||||
let _it = v.chunks_exact(0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1235,10 +1235,10 @@ fn test_mut_chunks_0() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_mut_exact_chunks() {
|
||||
fn test_mut_chunks_exact() {
|
||||
let mut v = [0, 1, 2, 3, 4, 5, 6];
|
||||
assert_eq!(v.exact_chunks_mut(2).len(), 3);
|
||||
for (i, chunk) in v.exact_chunks_mut(3).enumerate() {
|
||||
assert_eq!(v.chunks_exact_mut(2).len(), 3);
|
||||
for (i, chunk) in v.chunks_exact_mut(3).enumerate() {
|
||||
for x in chunk {
|
||||
*x = i as u8;
|
||||
}
|
||||
|
|
@ -1248,9 +1248,9 @@ fn test_mut_exact_chunks() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_mut_exact_chunks_rev() {
|
||||
fn test_mut_chunks_exact_rev() {
|
||||
let mut v = [0, 1, 2, 3, 4, 5, 6];
|
||||
for (i, chunk) in v.exact_chunks_mut(3).rev().enumerate() {
|
||||
for (i, chunk) in v.chunks_exact_mut(3).rev().enumerate() {
|
||||
for x in chunk {
|
||||
*x = i as u8;
|
||||
}
|
||||
|
|
@ -1261,9 +1261,9 @@ fn test_mut_exact_chunks_rev() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_mut_exact_chunks_0() {
|
||||
fn test_mut_chunks_exact_0() {
|
||||
let mut v = [1, 2, 3, 4];
|
||||
let _it = v.exact_chunks_mut(0);
|
||||
let _it = v.chunks_exact_mut(0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -947,10 +947,9 @@ impl<T> Vec<T> {
|
|||
/// Removes all but the first of consecutive elements in the vector satisfying a given equality
|
||||
/// relation.
|
||||
///
|
||||
/// The `same_bucket` function is passed references to two elements from the vector, and
|
||||
/// returns `true` if the elements compare equal, or `false` if they do not. The elements are
|
||||
/// passed in opposite order from their order in the vector, so if `same_bucket(a, b)` returns
|
||||
/// `true`, `a` is removed.
|
||||
/// The `same_bucket` function is passed references to two elements from the vector and
|
||||
/// must determine if the elements compare equal. The elements are passed in opposite order
|
||||
/// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is removed.
|
||||
///
|
||||
/// If the vector is sorted, this removes all duplicates.
|
||||
///
|
||||
|
|
@ -964,90 +963,12 @@ impl<T> Vec<T> {
|
|||
/// assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
|
||||
/// ```
|
||||
#[stable(feature = "dedup_by", since = "1.16.0")]
|
||||
pub fn dedup_by<F>(&mut self, mut same_bucket: F) where F: FnMut(&mut T, &mut T) -> bool {
|
||||
unsafe {
|
||||
// Although we have a mutable reference to `self`, we cannot make
|
||||
// *arbitrary* changes. The `same_bucket` calls could panic, so we
|
||||
// must ensure that the vector is in a valid state at all time.
|
||||
//
|
||||
// The way that we handle this is by using swaps; we iterate
|
||||
// over all the elements, swapping as we go so that at the end
|
||||
// the elements we wish to keep are in the front, and those we
|
||||
// wish to reject are at the back. We can then truncate the
|
||||
// vector. This operation is still O(n).
|
||||
//
|
||||
// Example: We start in this state, where `r` represents "next
|
||||
// read" and `w` represents "next_write`.
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 1 | 2 | 3 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Comparing self[r] against self[w-1], this is not a duplicate, so
|
||||
// we swap self[r] and self[w] (no effect as r==w) and then increment both
|
||||
// r and w, leaving us with:
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 1 | 2 | 3 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Comparing self[r] against self[w-1], this value is a duplicate,
|
||||
// so we increment `r` but leave everything else unchanged:
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 1 | 2 | 3 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Comparing self[r] against self[w-1], this is not a duplicate,
|
||||
// so swap self[r] and self[w] and advance r and w:
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 2 | 1 | 3 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Not a duplicate, repeat:
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 2 | 3 | 1 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Duplicate, advance r. End of vec. Truncate to w.
|
||||
|
||||
let ln = self.len();
|
||||
if ln <= 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
// Avoid bounds checks by using raw pointers.
|
||||
let p = self.as_mut_ptr();
|
||||
let mut r: usize = 1;
|
||||
let mut w: usize = 1;
|
||||
|
||||
while r < ln {
|
||||
let p_r = p.add(r);
|
||||
let p_wm1 = p.add(w - 1);
|
||||
if !same_bucket(&mut *p_r, &mut *p_wm1) {
|
||||
if r != w {
|
||||
let p_w = p_wm1.offset(1);
|
||||
mem::swap(&mut *p_r, &mut *p_w);
|
||||
}
|
||||
w += 1;
|
||||
}
|
||||
r += 1;
|
||||
}
|
||||
|
||||
self.truncate(w);
|
||||
}
|
||||
pub fn dedup_by<F>(&mut self, same_bucket: F) where F: FnMut(&mut T, &mut T) -> bool {
|
||||
let len = {
|
||||
let (dedup, _) = self.as_mut_slice().partition_dedup_by(same_bucket);
|
||||
dedup.len()
|
||||
};
|
||||
self.truncate(len);
|
||||
}
|
||||
|
||||
/// Appends an element to the back of a collection.
|
||||
|
|
@ -1533,7 +1454,8 @@ impl<'a> Drop for SetLenOnDrop<'a> {
|
|||
}
|
||||
|
||||
impl<T: PartialEq> Vec<T> {
|
||||
/// Removes consecutive repeated elements in the vector.
|
||||
/// Removes consecutive repeated elements in the vector according to the
|
||||
/// [`PartialEq`] trait implementation.
|
||||
///
|
||||
/// If the vector is sorted, this removes all duplicates.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -115,6 +115,19 @@ pub unsafe fn from_u32_unchecked(i: u32) -> char {
|
|||
|
||||
#[stable(feature = "char_convert", since = "1.13.0")]
|
||||
impl From<char> for u32 {
|
||||
/// Converts a [`char`] into a [`u32`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::mem;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let c = 'c';
|
||||
/// let u = u32::from(c);
|
||||
/// assert!(4 == mem::size_of_val(&u))
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
fn from(c: char) -> Self {
|
||||
c as u32
|
||||
|
|
@ -141,6 +154,19 @@ impl From<char> for u32 {
|
|||
/// C0 and C1 control codes.
|
||||
#[stable(feature = "char_convert", since = "1.13.0")]
|
||||
impl From<u8> for char {
|
||||
/// Converts a [`u8`] into a [`char`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::mem;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let u = 32 as u8;
|
||||
/// let c = char::from(u);
|
||||
/// assert!(4 == mem::size_of_val(&c))
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
fn from(i: u8) -> Self {
|
||||
i as char
|
||||
|
|
|
|||
|
|
@ -624,7 +624,7 @@ impl<T> [T] {
|
|||
/// not divide the length of the slice, then the last chunk will
|
||||
/// not have length `chunk_size`.
|
||||
///
|
||||
/// See [`exact_chunks`] for a variant of this iterator that returns chunks
|
||||
/// See [`chunks_exact`] for a variant of this iterator that returns chunks
|
||||
/// of always exactly `chunk_size` elements.
|
||||
///
|
||||
/// # Panics
|
||||
|
|
@ -642,7 +642,7 @@ impl<T> [T] {
|
|||
/// assert!(iter.next().is_none());
|
||||
/// ```
|
||||
///
|
||||
/// [`exact_chunks`]: #method.exact_chunks
|
||||
/// [`chunks_exact`]: #method.chunks_exact
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn chunks(&self, chunk_size: usize) -> Chunks<T> {
|
||||
|
|
@ -655,7 +655,7 @@ impl<T> [T] {
|
|||
/// not divide the length of the slice, then the last chunk will not
|
||||
/// have length `chunk_size`.
|
||||
///
|
||||
/// See [`exact_chunks_mut`] for a variant of this iterator that returns chunks
|
||||
/// See [`chunks_exact_mut`] for a variant of this iterator that returns chunks
|
||||
/// of always exactly `chunk_size` elements.
|
||||
///
|
||||
/// # Panics
|
||||
|
|
@ -677,7 +677,7 @@ impl<T> [T] {
|
|||
/// assert_eq!(v, &[1, 1, 2, 2, 3]);
|
||||
/// ```
|
||||
///
|
||||
/// [`exact_chunks_mut`]: #method.exact_chunks_mut
|
||||
/// [`chunks_exact_mut`]: #method.chunks_exact_mut
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> {
|
||||
|
|
@ -702,24 +702,24 @@ impl<T> [T] {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(exact_chunks)]
|
||||
/// #![feature(chunks_exact)]
|
||||
///
|
||||
/// let slice = ['l', 'o', 'r', 'e', 'm'];
|
||||
/// let mut iter = slice.exact_chunks(2);
|
||||
/// let mut iter = slice.chunks_exact(2);
|
||||
/// assert_eq!(iter.next().unwrap(), &['l', 'o']);
|
||||
/// assert_eq!(iter.next().unwrap(), &['r', 'e']);
|
||||
/// assert!(iter.next().is_none());
|
||||
/// ```
|
||||
///
|
||||
/// [`chunks`]: #method.chunks
|
||||
#[unstable(feature = "exact_chunks", issue = "47115")]
|
||||
#[unstable(feature = "chunks_exact", issue = "47115")]
|
||||
#[inline]
|
||||
pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks<T> {
|
||||
pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<T> {
|
||||
assert!(chunk_size != 0);
|
||||
let rem = self.len() % chunk_size;
|
||||
let len = self.len() - rem;
|
||||
let (fst, snd) = self.split_at(len);
|
||||
ExactChunks { v: fst, rem: snd, chunk_size }
|
||||
ChunksExact { v: fst, rem: snd, chunk_size }
|
||||
}
|
||||
|
||||
/// Returns an iterator over `chunk_size` elements of the slice at a time.
|
||||
|
|
@ -739,12 +739,12 @@ impl<T> [T] {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(exact_chunks)]
|
||||
/// #![feature(chunks_exact)]
|
||||
///
|
||||
/// let v = &mut [0, 0, 0, 0, 0];
|
||||
/// let mut count = 1;
|
||||
///
|
||||
/// for chunk in v.exact_chunks_mut(2) {
|
||||
/// for chunk in v.chunks_exact_mut(2) {
|
||||
/// for elem in chunk.iter_mut() {
|
||||
/// *elem += count;
|
||||
/// }
|
||||
|
|
@ -754,14 +754,14 @@ impl<T> [T] {
|
|||
/// ```
|
||||
///
|
||||
/// [`chunks_mut`]: #method.chunks_mut
|
||||
#[unstable(feature = "exact_chunks", issue = "47115")]
|
||||
#[unstable(feature = "chunks_exact", issue = "47115")]
|
||||
#[inline]
|
||||
pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut<T> {
|
||||
pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<T> {
|
||||
assert!(chunk_size != 0);
|
||||
let rem = self.len() % chunk_size;
|
||||
let len = self.len() - rem;
|
||||
let (fst, snd) = self.split_at_mut(len);
|
||||
ExactChunksMut { v: fst, rem: snd, chunk_size }
|
||||
ChunksExactMut { v: fst, rem: snd, chunk_size }
|
||||
}
|
||||
|
||||
/// Divides one slice into two at an index.
|
||||
|
|
@ -1402,6 +1402,178 @@ impl<T> [T] {
|
|||
sort::quicksort(self, |a, b| f(a).lt(&f(b)));
|
||||
}
|
||||
|
||||
/// Moves all consecutive repeated elements to the end of the slice according to the
|
||||
/// [`PartialEq`] trait implementation.
|
||||
///
|
||||
/// Returns two slices. The first contains no consecutive repeated elements.
|
||||
/// The second contains all the duplicates in no specified order.
|
||||
///
|
||||
/// If the slice is sorted, the first returned slice contains no duplicates.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_partition_dedup)]
|
||||
///
|
||||
/// let mut slice = [1, 2, 2, 3, 3, 2, 1, 1];
|
||||
///
|
||||
/// let (dedup, duplicates) = slice.partition_dedup();
|
||||
///
|
||||
/// assert_eq!(dedup, [1, 2, 3, 2, 1]);
|
||||
/// assert_eq!(duplicates, [2, 3, 1]);
|
||||
/// ```
|
||||
#[unstable(feature = "slice_partition_dedup", issue = "54279")]
|
||||
#[inline]
|
||||
pub fn partition_dedup(&mut self) -> (&mut [T], &mut [T])
|
||||
where T: PartialEq
|
||||
{
|
||||
self.partition_dedup_by(|a, b| a == b)
|
||||
}
|
||||
|
||||
/// Moves all but the first of consecutive elements to the end of the slice satisfying
|
||||
/// a given equality relation.
|
||||
///
|
||||
/// Returns two slices. The first contains no consecutive repeated elements.
|
||||
/// The second contains all the duplicates in no specified order.
|
||||
///
|
||||
/// The `same_bucket` function is passed references to two elements from the slice and
|
||||
/// must determine if the elements compare equal. The elements are passed in opposite order
|
||||
/// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is moved
|
||||
/// at the end of the slice.
|
||||
///
|
||||
/// If the slice is sorted, the first returned slice contains no duplicates.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_partition_dedup)]
|
||||
///
|
||||
/// let mut slice = ["foo", "Foo", "BAZ", "Bar", "bar", "baz", "BAZ"];
|
||||
///
|
||||
/// let (dedup, duplicates) = slice.partition_dedup_by(|a, b| a.eq_ignore_ascii_case(b));
|
||||
///
|
||||
/// assert_eq!(dedup, ["foo", "BAZ", "Bar", "baz"]);
|
||||
/// assert_eq!(duplicates, ["bar", "Foo", "BAZ"]);
|
||||
/// ```
|
||||
#[unstable(feature = "slice_partition_dedup", issue = "54279")]
|
||||
#[inline]
|
||||
pub fn partition_dedup_by<F>(&mut self, mut same_bucket: F) -> (&mut [T], &mut [T])
|
||||
where F: FnMut(&mut T, &mut T) -> bool
|
||||
{
|
||||
// Although we have a mutable reference to `self`, we cannot make
|
||||
// *arbitrary* changes. The `same_bucket` calls could panic, so we
|
||||
// must ensure that the slice is in a valid state at all times.
|
||||
//
|
||||
// The way that we handle this is by using swaps; we iterate
|
||||
// over all the elements, swapping as we go so that at the end
|
||||
// the elements we wish to keep are in the front, and those we
|
||||
// wish to reject are at the back. We can then split the slice.
|
||||
// This operation is still O(n).
|
||||
//
|
||||
// Example: We start in this state, where `r` represents "next
|
||||
// read" and `w` represents "next_write`.
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 1 | 2 | 3 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Comparing self[r] against self[w-1], this is not a duplicate, so
|
||||
// we swap self[r] and self[w] (no effect as r==w) and then increment both
|
||||
// r and w, leaving us with:
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 1 | 2 | 3 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Comparing self[r] against self[w-1], this value is a duplicate,
|
||||
// so we increment `r` but leave everything else unchanged:
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 1 | 2 | 3 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Comparing self[r] against self[w-1], this is not a duplicate,
|
||||
// so swap self[r] and self[w] and advance r and w:
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 2 | 1 | 3 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Not a duplicate, repeat:
|
||||
//
|
||||
// r
|
||||
// +---+---+---+---+---+---+
|
||||
// | 0 | 1 | 2 | 3 | 1 | 3 |
|
||||
// +---+---+---+---+---+---+
|
||||
// w
|
||||
//
|
||||
// Duplicate, advance r. End of slice. Split at w.
|
||||
|
||||
let len = self.len();
|
||||
if len <= 1 {
|
||||
return (self, &mut [])
|
||||
}
|
||||
|
||||
let ptr = self.as_mut_ptr();
|
||||
let mut next_read: usize = 1;
|
||||
let mut next_write: usize = 1;
|
||||
|
||||
unsafe {
|
||||
// Avoid bounds checks by using raw pointers.
|
||||
while next_read < len {
|
||||
let ptr_read = ptr.add(next_read);
|
||||
let prev_ptr_write = ptr.add(next_write - 1);
|
||||
if !same_bucket(&mut *ptr_read, &mut *prev_ptr_write) {
|
||||
if next_read != next_write {
|
||||
let ptr_write = prev_ptr_write.offset(1);
|
||||
mem::swap(&mut *ptr_read, &mut *ptr_write);
|
||||
}
|
||||
next_write += 1;
|
||||
}
|
||||
next_read += 1;
|
||||
}
|
||||
}
|
||||
|
||||
self.split_at_mut(next_write)
|
||||
}
|
||||
|
||||
/// Moves all but the first of consecutive elements to the end of the slice that resolve
|
||||
/// to the same key.
|
||||
///
|
||||
/// Returns two slices. The first contains no consecutive repeated elements.
|
||||
/// The second contains all the duplicates in no specified order.
|
||||
///
|
||||
/// If the slice is sorted, the first returned slice contains no duplicates.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_partition_dedup)]
|
||||
///
|
||||
/// let mut slice = [10, 20, 21, 30, 30, 20, 11, 13];
|
||||
///
|
||||
/// let (dedup, duplicates) = slice.partition_dedup_by_key(|i| *i / 10);
|
||||
///
|
||||
/// assert_eq!(dedup, [10, 20, 30, 20, 11]);
|
||||
/// assert_eq!(duplicates, [21, 30, 13]);
|
||||
/// ```
|
||||
#[unstable(feature = "slice_partition_dedup", issue = "54279")]
|
||||
#[inline]
|
||||
pub fn partition_dedup_by_key<K, F>(&mut self, mut key: F) -> (&mut [T], &mut [T])
|
||||
where F: FnMut(&mut T) -> K,
|
||||
K: PartialEq,
|
||||
{
|
||||
self.partition_dedup_by(|a, b| key(a) == key(b))
|
||||
}
|
||||
|
||||
/// Rotates the slice in-place such that the first `mid` elements of the
|
||||
/// slice move to the end while the last `self.len() - mid` elements move to
|
||||
/// the front. After calling `rotate_left`, the element previously at index
|
||||
|
|
@ -3657,21 +3829,21 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> {
|
|||
/// up to `chunk_size-1` elements will be omitted but can be retrieved from
|
||||
/// the [`remainder`] function from the iterator.
|
||||
///
|
||||
/// This struct is created by the [`exact_chunks`] method on [slices].
|
||||
/// This struct is created by the [`chunks_exact`] method on [slices].
|
||||
///
|
||||
/// [`exact_chunks`]: ../../std/primitive.slice.html#method.exact_chunks
|
||||
/// [`remainder`]: ../../std/slice/struct.ExactChunks.html#method.remainder
|
||||
/// [`chunks_exact`]: ../../std/primitive.slice.html#method.chunks_exact
|
||||
/// [`remainder`]: ../../std/slice/struct.ChunksExact.html#method.remainder
|
||||
/// [slices]: ../../std/primitive.slice.html
|
||||
#[derive(Debug)]
|
||||
#[unstable(feature = "exact_chunks", issue = "47115")]
|
||||
pub struct ExactChunks<'a, T:'a> {
|
||||
#[unstable(feature = "chunks_exact", issue = "47115")]
|
||||
pub struct ChunksExact<'a, T:'a> {
|
||||
v: &'a [T],
|
||||
rem: &'a [T],
|
||||
chunk_size: usize
|
||||
}
|
||||
|
||||
#[unstable(feature = "exact_chunks", issue = "47115")]
|
||||
impl<'a, T> ExactChunks<'a, T> {
|
||||
#[unstable(feature = "chunks_exact", issue = "47115")]
|
||||
impl<'a, T> ChunksExact<'a, T> {
|
||||
/// Return the remainder of the original slice that is not going to be
|
||||
/// returned by the iterator. The returned slice has at most `chunk_size-1`
|
||||
/// elements.
|
||||
|
|
@ -3681,10 +3853,10 @@ impl<'a, T> ExactChunks<'a, T> {
|
|||
}
|
||||
|
||||
// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
|
||||
#[unstable(feature = "exact_chunks", issue = "47115")]
|
||||
impl<'a, T> Clone for ExactChunks<'a, T> {
|
||||
fn clone(&self) -> ExactChunks<'a, T> {
|
||||
ExactChunks {
|
||||
#[unstable(feature = "chunks_exact", issue = "47115")]
|
||||
impl<'a, T> Clone for ChunksExact<'a, T> {
|
||||
fn clone(&self) -> ChunksExact<'a, T> {
|
||||
ChunksExact {
|
||||
v: self.v,
|
||||
rem: self.rem,
|
||||
chunk_size: self.chunk_size,
|
||||
|
|
@ -3692,8 +3864,8 @@ impl<'a, T> Clone for ExactChunks<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "exact_chunks", issue = "47115")]
|
||||
impl<'a, T> Iterator for ExactChunks<'a, T> {
|
||||
#[unstable(feature = "chunks_exact", issue = "47115")]
|
||||
impl<'a, T> Iterator for ChunksExact<'a, T> {
|
||||
type Item = &'a [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -3737,8 +3909,8 @@ impl<'a, T> Iterator for ExactChunks<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "exact_chunks", issue = "47115")]
|
||||
impl<'a, T> DoubleEndedIterator for ExactChunks<'a, T> {
|
||||
#[unstable(feature = "chunks_exact", issue = "47115")]
|
||||
impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<&'a [T]> {
|
||||
if self.v.len() < self.chunk_size {
|
||||
|
|
@ -3751,21 +3923,21 @@ impl<'a, T> DoubleEndedIterator for ExactChunks<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "exact_chunks", issue = "47115")]
|
||||
impl<'a, T> ExactSizeIterator for ExactChunks<'a, T> {
|
||||
#[unstable(feature = "chunks_exact", issue = "47115")]
|
||||
impl<'a, T> ExactSizeIterator for ChunksExact<'a, T> {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.v.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<'a, T> TrustedLen for ExactChunks<'a, T> {}
|
||||
unsafe impl<'a, T> TrustedLen for ChunksExact<'a, T> {}
|
||||
|
||||
#[unstable(feature = "exact_chunks", issue = "47115")]
|
||||
impl<'a, T> FusedIterator for ExactChunks<'a, T> {}
|
||||
#[unstable(feature = "chunks_exact", issue = "47115")]
|
||||
impl<'a, T> FusedIterator for ChunksExact<'a, T> {}
|
||||
|
||||
#[doc(hidden)]
|
||||
unsafe impl<'a, T> TrustedRandomAccess for ExactChunks<'a, T> {
|
||||
unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> {
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] {
|
||||
let start = i * self.chunk_size;
|
||||
from_raw_parts(self.v.as_ptr().add(start), self.chunk_size)
|
||||
|
|
@ -3780,21 +3952,21 @@ unsafe impl<'a, T> TrustedRandomAccess for ExactChunks<'a, T> {
|
|||
/// `chunk_size-1` elements will be omitted but can be retrieved from the
|
||||
/// [`into_remainder`] function from the iterator.
|
||||
///
|
||||
/// This struct is created by the [`exact_chunks_mut`] method on [slices].
|
||||
/// This struct is created by the [`chunks_exact_mut`] method on [slices].
|
||||
///
|
||||
/// [`exact_chunks_mut`]: ../../std/primitive.slice.html#method.exact_chunks_mut
|
||||
/// [`into_remainder`]: ../../std/slice/struct.ExactChunksMut.html#method.into_remainder
|
||||
/// [`chunks_exact_mut`]: ../../std/primitive.slice.html#method.chunks_exact_mut
|
||||
/// [`into_remainder`]: ../../std/slice/struct.ChunksExactMut.html#method.into_remainder
|
||||
/// [slices]: ../../std/primitive.slice.html
|
||||
#[derive(Debug)]
|
||||
#[unstable(feature = "exact_chunks", issue = "47115")]
|
||||
pub struct ExactChunksMut<'a, T:'a> {
|
||||
#[unstable(feature = "chunks_exact", issue = "47115")]
|
||||
pub struct ChunksExactMut<'a, T:'a> {
|
||||
v: &'a mut [T],
|
||||
rem: &'a mut [T],
|
||||
chunk_size: usize
|
||||
}
|
||||
|
||||
#[unstable(feature = "exact_chunks", issue = "47115")]
|
||||
impl<'a, T> ExactChunksMut<'a, T> {
|
||||
#[unstable(feature = "chunks_exact", issue = "47115")]
|
||||
impl<'a, T> ChunksExactMut<'a, T> {
|
||||
/// Return the remainder of the original slice that is not going to be
|
||||
/// returned by the iterator. The returned slice has at most `chunk_size-1`
|
||||
/// elements.
|
||||
|
|
@ -3803,8 +3975,8 @@ impl<'a, T> ExactChunksMut<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "exact_chunks", issue = "47115")]
|
||||
impl<'a, T> Iterator for ExactChunksMut<'a, T> {
|
||||
#[unstable(feature = "chunks_exact", issue = "47115")]
|
||||
impl<'a, T> Iterator for ChunksExactMut<'a, T> {
|
||||
type Item = &'a mut [T];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -3850,8 +4022,8 @@ impl<'a, T> Iterator for ExactChunksMut<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "exact_chunks", issue = "47115")]
|
||||
impl<'a, T> DoubleEndedIterator for ExactChunksMut<'a, T> {
|
||||
#[unstable(feature = "chunks_exact", issue = "47115")]
|
||||
impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<&'a mut [T]> {
|
||||
if self.v.len() < self.chunk_size {
|
||||
|
|
@ -3866,21 +4038,21 @@ impl<'a, T> DoubleEndedIterator for ExactChunksMut<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "exact_chunks", issue = "47115")]
|
||||
impl<'a, T> ExactSizeIterator for ExactChunksMut<'a, T> {
|
||||
#[unstable(feature = "chunks_exact", issue = "47115")]
|
||||
impl<'a, T> ExactSizeIterator for ChunksExactMut<'a, T> {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.v.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<'a, T> TrustedLen for ExactChunksMut<'a, T> {}
|
||||
unsafe impl<'a, T> TrustedLen for ChunksExactMut<'a, T> {}
|
||||
|
||||
#[unstable(feature = "exact_chunks", issue = "47115")]
|
||||
impl<'a, T> FusedIterator for ExactChunksMut<'a, T> {}
|
||||
#[unstable(feature = "chunks_exact", issue = "47115")]
|
||||
impl<'a, T> FusedIterator for ChunksExactMut<'a, T> {}
|
||||
|
||||
#[doc(hidden)]
|
||||
unsafe impl<'a, T> TrustedRandomAccess for ExactChunksMut<'a, T> {
|
||||
unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> {
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] {
|
||||
let start = i * self.chunk_size;
|
||||
from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size)
|
||||
|
|
|
|||
|
|
@ -33,12 +33,13 @@
|
|||
#![feature(trusted_len)]
|
||||
#![feature(try_from)]
|
||||
#![feature(try_trait)]
|
||||
#![feature(exact_chunks)]
|
||||
#![feature(chunks_exact)]
|
||||
#![feature(align_offset)]
|
||||
#![feature(reverse_bits)]
|
||||
#![feature(inner_deref)]
|
||||
#![feature(slice_internals)]
|
||||
#![feature(option_replace)]
|
||||
#![feature(slice_partition_dedup)]
|
||||
#![feature(copy_within)]
|
||||
|
||||
extern crate core;
|
||||
|
|
|
|||
|
|
@ -221,115 +221,115 @@ fn test_chunks_mut_zip() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_exact_chunks_count() {
|
||||
fn test_chunks_exact_count() {
|
||||
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
|
||||
let c = v.exact_chunks(3);
|
||||
let c = v.chunks_exact(3);
|
||||
assert_eq!(c.count(), 2);
|
||||
|
||||
let v2: &[i32] = &[0, 1, 2, 3, 4];
|
||||
let c2 = v2.exact_chunks(2);
|
||||
let c2 = v2.chunks_exact(2);
|
||||
assert_eq!(c2.count(), 2);
|
||||
|
||||
let v3: &[i32] = &[];
|
||||
let c3 = v3.exact_chunks(2);
|
||||
let c3 = v3.chunks_exact(2);
|
||||
assert_eq!(c3.count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exact_chunks_nth() {
|
||||
fn test_chunks_exact_nth() {
|
||||
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
|
||||
let mut c = v.exact_chunks(2);
|
||||
let mut c = v.chunks_exact(2);
|
||||
assert_eq!(c.nth(1).unwrap(), &[2, 3]);
|
||||
assert_eq!(c.next().unwrap(), &[4, 5]);
|
||||
|
||||
let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6];
|
||||
let mut c2 = v2.exact_chunks(3);
|
||||
let mut c2 = v2.chunks_exact(3);
|
||||
assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]);
|
||||
assert_eq!(c2.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exact_chunks_last() {
|
||||
fn test_chunks_exact_last() {
|
||||
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
|
||||
let c = v.exact_chunks(2);
|
||||
let c = v.chunks_exact(2);
|
||||
assert_eq!(c.last().unwrap(), &[4, 5]);
|
||||
|
||||
let v2: &[i32] = &[0, 1, 2, 3, 4];
|
||||
let c2 = v2.exact_chunks(2);
|
||||
let c2 = v2.chunks_exact(2);
|
||||
assert_eq!(c2.last().unwrap(), &[2, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exact_chunks_remainder() {
|
||||
fn test_chunks_exact_remainder() {
|
||||
let v: &[i32] = &[0, 1, 2, 3, 4];
|
||||
let c = v.exact_chunks(2);
|
||||
let c = v.chunks_exact(2);
|
||||
assert_eq!(c.remainder(), &[4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exact_chunks_zip() {
|
||||
fn test_chunks_exact_zip() {
|
||||
let v1: &[i32] = &[0, 1, 2, 3, 4];
|
||||
let v2: &[i32] = &[6, 7, 8, 9, 10];
|
||||
|
||||
let res = v1.exact_chunks(2)
|
||||
.zip(v2.exact_chunks(2))
|
||||
let res = v1.chunks_exact(2)
|
||||
.zip(v2.chunks_exact(2))
|
||||
.map(|(a, b)| a.iter().sum::<i32>() + b.iter().sum::<i32>())
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(res, vec![14, 22]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exact_chunks_mut_count() {
|
||||
fn test_chunks_exact_mut_count() {
|
||||
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
|
||||
let c = v.exact_chunks_mut(3);
|
||||
let c = v.chunks_exact_mut(3);
|
||||
assert_eq!(c.count(), 2);
|
||||
|
||||
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
|
||||
let c2 = v2.exact_chunks_mut(2);
|
||||
let c2 = v2.chunks_exact_mut(2);
|
||||
assert_eq!(c2.count(), 2);
|
||||
|
||||
let v3: &mut [i32] = &mut [];
|
||||
let c3 = v3.exact_chunks_mut(2);
|
||||
let c3 = v3.chunks_exact_mut(2);
|
||||
assert_eq!(c3.count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exact_chunks_mut_nth() {
|
||||
fn test_chunks_exact_mut_nth() {
|
||||
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
|
||||
let mut c = v.exact_chunks_mut(2);
|
||||
let mut c = v.chunks_exact_mut(2);
|
||||
assert_eq!(c.nth(1).unwrap(), &[2, 3]);
|
||||
assert_eq!(c.next().unwrap(), &[4, 5]);
|
||||
|
||||
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
|
||||
let mut c2 = v2.exact_chunks_mut(3);
|
||||
let mut c2 = v2.chunks_exact_mut(3);
|
||||
assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]);
|
||||
assert_eq!(c2.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exact_chunks_mut_last() {
|
||||
fn test_chunks_exact_mut_last() {
|
||||
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
|
||||
let c = v.exact_chunks_mut(2);
|
||||
let c = v.chunks_exact_mut(2);
|
||||
assert_eq!(c.last().unwrap(), &[4, 5]);
|
||||
|
||||
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
|
||||
let c2 = v2.exact_chunks_mut(2);
|
||||
let c2 = v2.chunks_exact_mut(2);
|
||||
assert_eq!(c2.last().unwrap(), &[2, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exact_chunks_mut_remainder() {
|
||||
fn test_chunks_exact_mut_remainder() {
|
||||
let v: &mut [i32] = &mut [0, 1, 2, 3, 4];
|
||||
let c = v.exact_chunks_mut(2);
|
||||
let c = v.chunks_exact_mut(2);
|
||||
assert_eq!(c.into_remainder(), &[4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exact_chunks_mut_zip() {
|
||||
fn test_chunks_exact_mut_zip() {
|
||||
let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
|
||||
let v2: &[i32] = &[6, 7, 8, 9, 10];
|
||||
|
||||
for (a, b) in v1.exact_chunks_mut(2).zip(v2.exact_chunks(2)) {
|
||||
for (a, b) in v1.chunks_exact_mut(2).zip(v2.chunks_exact(2)) {
|
||||
let sum = b.iter().sum::<i32>();
|
||||
for v in a {
|
||||
*v += sum;
|
||||
|
|
@ -1001,6 +1001,65 @@ fn test_align_to_empty_mid() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_slice_partition_dedup_by() {
|
||||
let mut slice: [i32; 9] = [1, -1, 2, 3, 1, -5, 5, -2, 2];
|
||||
|
||||
let (dedup, duplicates) = slice.partition_dedup_by(|a, b| a.abs() == b.abs());
|
||||
|
||||
assert_eq!(dedup, [1, 2, 3, 1, -5, -2]);
|
||||
assert_eq!(duplicates, [5, -1, 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_slice_partition_dedup_empty() {
|
||||
let mut slice: [i32; 0] = [];
|
||||
|
||||
let (dedup, duplicates) = slice.partition_dedup();
|
||||
|
||||
assert_eq!(dedup, []);
|
||||
assert_eq!(duplicates, []);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_slice_partition_dedup_one() {
|
||||
let mut slice = [12];
|
||||
|
||||
let (dedup, duplicates) = slice.partition_dedup();
|
||||
|
||||
assert_eq!(dedup, [12]);
|
||||
assert_eq!(duplicates, []);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_slice_partition_dedup_multiple_ident() {
|
||||
let mut slice = [12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11];
|
||||
|
||||
let (dedup, duplicates) = slice.partition_dedup();
|
||||
|
||||
assert_eq!(dedup, [12, 11]);
|
||||
assert_eq!(duplicates, [12, 12, 12, 12, 11, 11, 11, 11, 11]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_slice_partition_dedup_partialeq() {
|
||||
#[derive(Debug)]
|
||||
struct Foo(i32, i32);
|
||||
|
||||
impl PartialEq for Foo {
|
||||
fn eq(&self, other: &Foo) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
let mut slice = [Foo(0, 1), Foo(0, 5), Foo(1, 7), Foo(1, 9)];
|
||||
|
||||
let (dedup, duplicates) = slice.partition_dedup();
|
||||
|
||||
assert_eq!(dedup, [Foo(0, 1), Foo(1, 7)]);
|
||||
assert_eq!(duplicates, [Foo(0, 5), Foo(1, 9)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy_within() {
|
||||
// Start to end, with a RangeTo.
|
||||
|
|
|
|||
|
|
@ -646,7 +646,6 @@ impl Options {
|
|||
match self.debugging_opts.share_generics {
|
||||
Some(setting) => setting,
|
||||
None => {
|
||||
self.incremental.is_some() ||
|
||||
match self.optimize {
|
||||
OptLevel::No |
|
||||
OptLevel::Less |
|
||||
|
|
|
|||
|
|
@ -575,6 +575,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
// 5. Standard library prelude (de-facto closed, controlled).
|
||||
// 6. Language prelude (closed, controlled).
|
||||
// (Macro NS)
|
||||
// 0. Derive helpers (open, not controlled). All ambiguities with other names
|
||||
// are currently reported as errors. They should be higher in priority than preludes
|
||||
// and probably even names in modules according to the "general principles" above. They
|
||||
// also should be subject to restricted shadowing because are effectively produced by
|
||||
// derives (you need to resolve the derive first to add helpers into scope), but they
|
||||
// should be available before the derive is expanded for compatibility.
|
||||
// It's mess in general, so we are being conservative for now.
|
||||
// 1. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
|
||||
// (open, not controlled).
|
||||
// 2. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
|
||||
|
|
@ -583,13 +590,6 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
// 2b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
|
||||
// 3. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
|
||||
// 4. Language prelude: builtin attributes (closed, controlled).
|
||||
// N (unordered). Derive helpers (open, not controlled). All ambiguities with other names
|
||||
// are currently reported as errors. They should be higher in priority than preludes
|
||||
// and maybe even names in modules according to the "general principles" above. They
|
||||
// also should be subject to restricted shadowing because are effectively produced by
|
||||
// derives (you need to resolve the derive first to add helpers into scope), but they
|
||||
// should be available before the derive is expanded for compatibility.
|
||||
// It's mess in general, so we are being conservative for now.
|
||||
|
||||
assert!(ns == TypeNS || ns == MacroNS);
|
||||
assert!(force || !record_used); // `record_used` implies `force`
|
||||
|
|
@ -621,7 +621,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
}
|
||||
|
||||
// Go through all the scopes and try to resolve the name.
|
||||
let mut where_to_resolve = WhereToResolve::Module(parent_scope.module);
|
||||
let mut where_to_resolve = WhereToResolve::DeriveHelpers;
|
||||
let mut use_prelude = !parent_scope.module.no_implicit_prelude;
|
||||
loop {
|
||||
let result = match where_to_resolve {
|
||||
|
|
@ -751,8 +751,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
|
|||
}
|
||||
WhereToResolve::MacroUsePrelude => WhereToResolve::BuiltinMacros,
|
||||
WhereToResolve::BuiltinMacros => WhereToResolve::BuiltinAttrs,
|
||||
WhereToResolve::BuiltinAttrs => WhereToResolve::DeriveHelpers,
|
||||
WhereToResolve::DeriveHelpers => break, // nowhere else to search
|
||||
WhereToResolve::BuiltinAttrs => break, // nowhere else to search
|
||||
WhereToResolve::DeriveHelpers => WhereToResolve::Module(parent_scope.module),
|
||||
WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
|
||||
WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
|
||||
WhereToResolve::StdLibPrelude => WhereToResolve::BuiltinTypes,
|
||||
|
|
|
|||
|
|
@ -1991,8 +1991,11 @@
|
|||
}
|
||||
};
|
||||
if (getCurrentValue('rustdoc-trait-implementations') !== "false") {
|
||||
onEach(document.getElementById('implementations-list')
|
||||
.getElementsByClassName("collapse-toggle"), collapser);
|
||||
var impl_list = document.getElementById('implementations-list');
|
||||
|
||||
if (impl_list !== null) {
|
||||
onEach(impl_list.getElementsByClassName("collapse-toggle"), collapser);
|
||||
}
|
||||
}
|
||||
if (getCurrentValue('rustdoc-method-docs') !== "false") {
|
||||
var implItems = document.getElementsByClassName('impl-items');
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ code, pre {
|
|||
}
|
||||
.docblock code, .docblock-short code {
|
||||
border-radius: 3px;
|
||||
padding: 0 0.2em;
|
||||
padding: 0 0.1em;
|
||||
}
|
||||
.docblock pre code, .docblock-short pre code, .docblock code.spotlight {
|
||||
padding: 0;
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ mod prim_bool { }
|
|||
/// # `!` and traits
|
||||
///
|
||||
/// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl`
|
||||
/// which doesn't `panic!`. As is turns out, most traits can have an `impl` for `!`. Take [`Debug`]
|
||||
/// which doesn't `panic!`. As it turns out, most traits can have an `impl` for `!`. Take [`Debug`]
|
||||
/// for example:
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -228,9 +228,9 @@ mod prim_bool { }
|
|||
/// [`fmt::Result`]. Since this method takes a `&!` as an argument we know that it can never be
|
||||
/// called (because there is no value of type `!` for it to be called with). Writing `*self`
|
||||
/// essentially tells the compiler "We know that this code can never be run, so just treat the
|
||||
/// entire function body has having type [`fmt::Result`]". This pattern can be used a lot when
|
||||
/// entire function body as having type [`fmt::Result`]". This pattern can be used a lot when
|
||||
/// implementing traits for `!`. Generally, any trait which only has methods which take a `self`
|
||||
/// parameter should have such as impl.
|
||||
/// parameter should have such an impl.
|
||||
///
|
||||
/// On the other hand, one trait which would not be appropriate to implement is [`Default`]:
|
||||
///
|
||||
|
|
|
|||
|
|
@ -45,9 +45,17 @@
|
|||
extern crate getopts;
|
||||
#[cfg(any(unix, target_os = "cloudabi"))]
|
||||
extern crate libc;
|
||||
extern crate panic_unwind;
|
||||
extern crate term;
|
||||
|
||||
// FIXME(#54291): rustc and/or LLVM don't yet support building with panic-unwind
|
||||
// on aarch64-pc-windows-msvc, so we don't link libtest against
|
||||
// libunwind (for the time being), even though it means that
|
||||
// libtest won't be fully functional on this platform.
|
||||
//
|
||||
// See also: https://github.com/rust-lang/rust/issues/54190#issuecomment-422904437
|
||||
#[cfg(not(all(windows, target_arch = "aarch64")))]
|
||||
extern crate panic_unwind;
|
||||
|
||||
pub use self::TestFn::*;
|
||||
pub use self::ColorConfig::*;
|
||||
pub use self::TestResult::*;
|
||||
|
|
|
|||
|
|
@ -11,13 +11,11 @@
|
|||
// aux-build:derive-b.rs
|
||||
// ignore-stage1
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_b;
|
||||
|
||||
#[B] //~ ERROR `B` is a derive mode
|
||||
#[C]
|
||||
#[B]
|
||||
#[C] //~ ERROR attribute `C` is currently unknown to the compiler
|
||||
#[B(D)]
|
||||
#[B(E = "foo")]
|
||||
#[B(arbitrary tokens)]
|
||||
|
|
|
|||
|
|
@ -25,3 +25,13 @@ pub fn derive_foo(input: TokenStream) -> TokenStream {
|
|||
pub fn derive_bar(input: TokenStream) -> TokenStream {
|
||||
panic!("lolnope");
|
||||
}
|
||||
|
||||
#[proc_macro_derive(WithHelper, attributes(helper))]
|
||||
pub fn with_helper(input: TokenStream) -> TokenStream {
|
||||
TokenStream::new()
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn helper(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
input
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
// aux-build:plugin.rs
|
||||
// ignore-stage1
|
||||
|
||||
#[macro_use(WithHelper)]
|
||||
extern crate plugin;
|
||||
|
||||
use plugin::helper;
|
||||
|
||||
#[derive(WithHelper)]
|
||||
#[helper] //~ ERROR `helper` is ambiguous
|
||||
struct S;
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
error[E0659]: `helper` is ambiguous
|
||||
--> $DIR/helper-attr-blocked-by-import-ambig.rs:10:3
|
||||
|
|
||||
LL | #[helper] //~ ERROR `helper` is ambiguous
|
||||
| ^^^^^^ ambiguous name
|
||||
|
|
||||
note: `helper` could refer to the name defined here
|
||||
--> $DIR/helper-attr-blocked-by-import-ambig.rs:9:10
|
||||
|
|
||||
LL | #[derive(WithHelper)]
|
||||
| ^^^^^^^^^^
|
||||
note: `helper` could also refer to the name imported here
|
||||
--> $DIR/helper-attr-blocked-by-import-ambig.rs:7:5
|
||||
|
|
||||
LL | use plugin::helper;
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0659`.
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// compile-pass
|
||||
// aux-build:plugin.rs
|
||||
// ignore-stage1
|
||||
|
||||
#[macro_use(WithHelper)]
|
||||
extern crate plugin;
|
||||
|
||||
use self::one::*;
|
||||
use self::two::*;
|
||||
|
||||
mod helper {}
|
||||
|
||||
mod one {
|
||||
use helper;
|
||||
|
||||
#[derive(WithHelper)]
|
||||
#[helper]
|
||||
struct One;
|
||||
}
|
||||
|
||||
mod two {
|
||||
use helper;
|
||||
|
||||
#[derive(WithHelper)]
|
||||
#[helper]
|
||||
struct Two;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -4,17 +4,16 @@ error[E0659]: `my_attr` is ambiguous
|
|||
LL | #[my_attr] //~ ERROR `my_attr` is ambiguous
|
||||
| ^^^^^^^ ambiguous name
|
||||
|
|
||||
note: `my_attr` could refer to the name imported here
|
||||
--> $DIR/derive-helper-shadowing.rs:4:5
|
||||
|
|
||||
LL | use derive_helper_shadowing::*;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: `my_attr` could also refer to the name defined here
|
||||
note: `my_attr` could refer to the name defined here
|
||||
--> $DIR/derive-helper-shadowing.rs:7:10
|
||||
|
|
||||
LL | #[derive(MyTrait)]
|
||||
| ^^^^^^^
|
||||
= note: consider adding an explicit import of `my_attr` to disambiguate
|
||||
note: `my_attr` could also refer to the name imported here
|
||||
--> $DIR/derive-helper-shadowing.rs:4:5
|
||||
|
|
||||
LL | use derive_helper_shadowing::*;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue