always work, and sometimes it's hard to know what to search for, so consider this
extra credit. We won't mind if you accidentally file a duplicate report.
+Similarly, to help others who encountered the bug find your issue,
+consider filing an issue with with a descriptive title, which contains information that might be unique to it.
+This can be the language or compiler feature used, the conditions that trigger the bug,
+or part of the error message if there is any.
+An example could be: **"impossible case reached" on lifetime inference for impl Trait in return position**.
+
Opening an issue is as easy as following [this
link](https://github.com/rust-lang/rust/issues/new) and filling out the fields.
Here's a template that you can use to file a bug, though it's not necessary to
name = "alloc_jemalloc"
version = "0.0.0"
dependencies = [
- "alloc_system 0.0.0",
"build_helper 0.1.0",
"cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "cargo_metadata"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "cargo_metadata"
version = "0.5.4"
[[package]]
name = "elasticlunr-rs"
-version = "1.0.0"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strum_macros 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "mdbook"
-version = "0.1.5"
+version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "elasticlunr-rs 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "elasticlunr-rs 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"handlebars 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.1.0"
dependencies = [
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.1.0"
dependencies = [
"clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "mdbook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "strum"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "strum_macros"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "syn"
version = "0.11.11"
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
"checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32"
"checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87"
-"checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b"
"checksum cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ebd6272a2ca4fd39dbabbd6611eb03df45c2259b3b80b39a9ff8fbdcf42a4b3"
"checksum cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8b9d2900f78631a5876dc5d6c9033ede027253efcd33dd36b1309fc6cab97ee0"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
-"checksum elasticlunr-rs 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "19ab5f8db0ffb76b5d87454566ceb502c3650e29057c053f93e884d3b884e344"
+"checksum elasticlunr-rs 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4511b63d69dd5d31e8e29aed2c132c413f87acea8035d0584801feaab9dd1f0f"
"checksum ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b449f3b18c89d2dbe40548d2ee4fa58ea0a08b761992da6ecb9788e4688834"
"checksum endian-type 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
"checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
"checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43"
"checksum markup5ever 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfedc97d5a503e96816d10fedcd5b42f760b2e525ce2f7ec71f6a41780548475"
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
-"checksum mdbook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "326d0861da5681a13c19a00952a56c254dd04f00eb944e506fdb36e93ae6f1ca"
+"checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
"checksum string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479cde50c3539481f33906a387f2bd17c8e87cb848c35b6021d41fb81ff9b4d7"
"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
+"checksum strum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "099e21b5dd6dd07b5adcf8c4b723a7c0b7efd7a9359bf963d58c0caae8532545"
+"checksum strum_macros 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd9bd569e88028750e3ae5c25616b8278ac16a8e61aba4339195c72396d49e1"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5"
"checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59"
let host = self.host;
let compiler = builder.compiler(stage, host);
- builder.ensure(tool::Rls { compiler, target: self.host, extra_features: Vec::new() });
+ let build_result = builder.ensure(tool::Rls {
+ compiler,
+ target: self.host,
+ extra_features: Vec::new(),
+ });
+ if build_result.is_none() {
+ eprintln!("failed to test rls: could not build");
+ return;
+ }
+
let mut cargo = tool::prepare_tool_cargo(builder,
compiler,
host,
let host = self.host;
let compiler = builder.compiler(stage, host);
- builder.ensure(tool::Rustfmt { compiler, target: self.host, extra_features: Vec::new() });
+ let build_result = builder.ensure(tool::Rustfmt {
+ compiler,
+ target: self.host,
+ extra_features: Vec::new(),
+ });
+ if build_result.is_none() {
+ eprintln!("failed to test rustfmt: could not build");
+ return;
+ }
+
let mut cargo = tool::prepare_tool_cargo(builder,
compiler,
host,
verify_status rls src/tool/rls
verify_status rustfmt src/tool/rustfmt
verify_status clippy-driver src/tool/clippy
-#verify_status miri src/tool/miri
+verify_status miri src/tool/miri
if [ "$RUST_RELEASE_CHANNEL" = nightly -a -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then
. "$(dirname $0)/repo.sh"
`#[unstable]` attribute to any dependent crate that doesn't have another stability attribute. This
allows `rustdoc` to be able to generate documentation for the compiler crates and the standard
library, as an equivalent command-line argument is provided to `rustc` when building those crates.
+
+### `doc_alias` feature
+
+This feature allows you to add alias(es) to an item when using the `rustdoc` search through the
+`doc(alias)` attribute. Example:
+
+```rust,no_run
+#![feature(doc_alias)]
+
+#[doc(alias = "x")]
+#[doc(alias = "big")]
+pub struct BigX;
+```
+
+Then, when looking for it through the `rustdoc` search, if you enter "x" or
+"big", search will show the `BigX` struct first.
--- /dev/null
+# `doc_alias`
+
+The tracking issue for this feature is: [#50146]
+
+[#50146]: https://github.com/rust-lang/rust/issues/50146
+
+------------------------
+
+You can add alias(es) to an item when using the `rustdoc` search through the
+`doc(alias)` attribute. Example:
+
+```rust,no_run
+#![feature(doc_alias)]
+
+#[doc(alias = "x")]
+#[doc(alias = "big")]
+pub struct BigX;
+```
+
+Then, when looking for it through the `rustdoc` search, if you enter "x" or
+"big", search will show the `BigX` struct first.
+
+Note that this feature is currently hidden behind the `feature(doc_alias)` gate.
#[allocator]
#[rustc_allocator_nounwind]
fn __rust_alloc(size: usize, align: usize) -> *mut u8;
- #[cold]
- #[rustc_allocator_nounwind]
- fn __rust_oom() -> !;
#[rustc_allocator_nounwind]
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
#[rustc_allocator_nounwind]
let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), &mut 0);
ptr as *mut Opaque
}
-
- #[inline]
- fn oom(&self) -> ! {
- unsafe {
- #[cfg(not(stage0))]
- __rust_oom();
- #[cfg(stage0)]
- __rust_oom(&mut 0);
- }
- }
}
unsafe impl Alloc for Global {
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
}
-
- #[inline]
- fn oom(&mut self) -> ! {
- GlobalAlloc::oom(self)
- }
}
/// The allocator for unique pointers.
if !ptr.is_null() {
ptr as *mut u8
} else {
- Global.oom()
+ oom()
}
}
}
}
}
+#[cfg(stage0)]
+pub fn oom() -> ! {
+ unsafe { ::core::intrinsics::abort() }
+}
+
+#[cfg(not(stage0))]
+pub fn oom() -> ! {
+ extern {
+ #[lang = "oom"]
+ fn oom_impl() -> !;
+ }
+ unsafe { oom_impl() }
+}
+
#[cfg(test)]
mod tests {
extern crate test;
use self::test::Bencher;
use boxed::Box;
- use alloc::{Global, Alloc, Layout};
+ use alloc::{Global, Alloc, Layout, oom};
#[test]
fn allocate_zeroed() {
unsafe {
let layout = Layout::from_size_align(1024, 1).unwrap();
let ptr = Global.alloc_zeroed(layout.clone())
- .unwrap_or_else(|_| Global.oom());
+ .unwrap_or_else(|_| oom());
let mut i = ptr.cast::<u8>().as_ptr();
let end = i.offset(layout.size() as isize);
use core::{isize, usize};
use core::convert::From;
-use alloc::{Global, Alloc, Layout, box_free};
+use alloc::{Global, Alloc, Layout, box_free, oom};
use boxed::Box;
use string::String;
use vec::Vec;
let layout = Layout::for_value(&*fake_ptr);
let mem = Global.alloc(layout)
- .unwrap_or_else(|_| Global.oom());
+ .unwrap_or_else(|_| oom());
// Initialize the real ArcInner
let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner<T>;
}
fn oom(&mut self, _: AllocErr) -> ! {
- CoreAlloc::oom(self)
+ unsafe { ::core::intrinsics::abort() }
}
fn usable_size(&self, layout: &Layout) -> (usize, usize) {
#![deny(missing_debug_implementations)]
#![cfg_attr(test, allow(deprecated))] // rand
-#![cfg_attr(not(test), feature(core_float))]
+#![cfg_attr(all(not(test), stage0), feature(float_internals))]
#![cfg_attr(not(test), feature(exact_size_is_empty))]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(rand, test))]
#![feature(collections_range)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
+#![cfg_attr(stage0, feature(core_slice_ext))]
+#![cfg_attr(stage0, feature(core_str_ext))]
#![feature(custom_attribute)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
use core::ptr::{self, NonNull, Unique};
use core::slice;
-use alloc::{Alloc, Layout, Global};
+use alloc::{Alloc, Layout, Global, oom};
use alloc::CollectionAllocErr;
use alloc::CollectionAllocErr::*;
use boxed::Box;
};
match result {
Ok(ptr) => ptr,
- Err(_) => a.oom(),
+ Err(_) => oom(),
}
};
new_size);
match ptr_res {
Ok(ptr) => (new_cap, ptr.cast().into()),
- Err(_) => self.a.oom(),
+ Err(_) => oom(),
}
}
None => {
let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 };
match self.a.alloc_array::<T>(new_cap) {
Ok(ptr) => (new_cap, ptr.into()),
- Err(_) => self.a.oom(),
+ Err(_) => oom(),
}
}
};
pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) {
match self.try_reserve_exact(used_cap, needed_extra_cap) {
Err(CapacityOverflow) => capacity_overflow(),
- Err(AllocErr) => self.a.oom(),
+ Err(AllocErr) => oom(),
Ok(()) => { /* yay */ }
}
}
pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) {
match self.try_reserve(used_cap, needed_extra_cap) {
Err(CapacityOverflow) => capacity_overflow(),
- Err(AllocErr) => self.a.oom(),
+ Err(AllocErr) => oom(),
Ok(()) => { /* yay */ }
}
}
old_layout,
new_size) {
Ok(p) => self.ptr = p.cast().into(),
- Err(_) => self.a.oom(),
+ Err(_) => oom(),
}
}
self.cap = amount;
use core::ptr::{self, NonNull};
use core::convert::From;
-use alloc::{Global, Alloc, Layout, Opaque, box_free};
+use alloc::{Global, Alloc, Layout, Opaque, box_free, oom};
use string::String;
use vec::Vec;
let layout = Layout::for_value(&*fake_ptr);
let mem = Global.alloc(layout)
- .unwrap_or_else(|_| Global.oom());
+ .unwrap_or_else(|_| oom());
// Initialize the real RcBox
let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut RcBox<T>;
--- /dev/null
+// Copyright 2018 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.
+
+#![feature(repeat_generic_slice)]
+
+fn main() {
+ assert_eq!([1, 2].repeat(2), vec![1, 2, 1, 2]);
+ assert_eq!([1, 2, 3, 4].repeat(0), vec![]);
+ assert_eq!([1, 2, 3, 4].repeat(1), vec![1, 2, 3, 4]);
+ assert_eq!([1, 2, 3, 4].repeat(3),
+ vec![1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]);
+}
use core::mem::size_of;
use core::mem;
use core::ptr;
-use core::slice as core_slice;
+#[cfg(stage0)] use core::slice::SliceExt;
use core::{u8, u16, u32};
use borrow::{Borrow, BorrowMut, ToOwned};
}
}
-#[lang = "slice"]
+#[cfg_attr(stage0, lang = "slice")]
+#[cfg_attr(not(stage0), lang = "slice_alloc")]
#[cfg(not(test))]
impl<T> [T] {
- /// Returns the number of elements in the slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let a = [1, 2, 3];
- /// assert_eq!(a.len(), 3);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn len(&self) -> usize {
- core_slice::SliceExt::len(self)
- }
-
- /// Returns `true` if the slice has a length of 0.
- ///
- /// # Examples
- ///
- /// ```
- /// let a = [1, 2, 3];
- /// assert!(!a.is_empty());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_empty(&self) -> bool {
- core_slice::SliceExt::is_empty(self)
- }
-
- /// Returns the first element of the slice, or `None` if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = [10, 40, 30];
- /// assert_eq!(Some(&10), v.first());
- ///
- /// let w: &[i32] = &[];
- /// assert_eq!(None, w.first());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn first(&self) -> Option<&T> {
- core_slice::SliceExt::first(self)
- }
-
- /// Returns a mutable pointer to the first element of the slice, or `None` if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &mut [0, 1, 2];
- ///
- /// if let Some(first) = x.first_mut() {
- /// *first = 5;
- /// }
- /// assert_eq!(x, &[5, 1, 2]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn first_mut(&mut self) -> Option<&mut T> {
- core_slice::SliceExt::first_mut(self)
- }
-
- /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &[0, 1, 2];
- ///
- /// if let Some((first, elements)) = x.split_first() {
- /// assert_eq!(first, &0);
- /// assert_eq!(elements, &[1, 2]);
- /// }
- /// ```
- #[stable(feature = "slice_splits", since = "1.5.0")]
- #[inline]
- pub fn split_first(&self) -> Option<(&T, &[T])> {
- core_slice::SliceExt::split_first(self)
- }
-
- /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &mut [0, 1, 2];
- ///
- /// if let Some((first, elements)) = x.split_first_mut() {
- /// *first = 3;
- /// elements[0] = 4;
- /// elements[1] = 5;
- /// }
- /// assert_eq!(x, &[3, 4, 5]);
- /// ```
- #[stable(feature = "slice_splits", since = "1.5.0")]
- #[inline]
- pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> {
- core_slice::SliceExt::split_first_mut(self)
- }
-
- /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &[0, 1, 2];
- ///
- /// if let Some((last, elements)) = x.split_last() {
- /// assert_eq!(last, &2);
- /// assert_eq!(elements, &[0, 1]);
- /// }
- /// ```
- #[stable(feature = "slice_splits", since = "1.5.0")]
- #[inline]
- pub fn split_last(&self) -> Option<(&T, &[T])> {
- core_slice::SliceExt::split_last(self)
-
- }
-
- /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &mut [0, 1, 2];
- ///
- /// if let Some((last, elements)) = x.split_last_mut() {
- /// *last = 3;
- /// elements[0] = 4;
- /// elements[1] = 5;
- /// }
- /// assert_eq!(x, &[4, 5, 3]);
- /// ```
- #[stable(feature = "slice_splits", since = "1.5.0")]
- #[inline]
- pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> {
- core_slice::SliceExt::split_last_mut(self)
- }
-
- /// Returns the last element of the slice, or `None` if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = [10, 40, 30];
- /// assert_eq!(Some(&30), v.last());
- ///
- /// let w: &[i32] = &[];
- /// assert_eq!(None, w.last());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn last(&self) -> Option<&T> {
- core_slice::SliceExt::last(self)
- }
-
- /// Returns a mutable pointer to the last item in the slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &mut [0, 1, 2];
- ///
- /// if let Some(last) = x.last_mut() {
- /// *last = 10;
- /// }
- /// assert_eq!(x, &[0, 1, 10]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn last_mut(&mut self) -> Option<&mut T> {
- core_slice::SliceExt::last_mut(self)
- }
-
- /// Returns a reference to an element or subslice depending on the type of
- /// index.
- ///
- /// - If given a position, returns a reference to the element at that
- /// position or `None` if out of bounds.
- /// - If given a range, returns the subslice corresponding to that range,
- /// or `None` if out of bounds.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = [10, 40, 30];
- /// assert_eq!(Some(&40), v.get(1));
- /// assert_eq!(Some(&[10, 40][..]), v.get(0..2));
- /// assert_eq!(None, v.get(3));
- /// assert_eq!(None, v.get(0..4));
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn get<I>(&self, index: I) -> Option<&I::Output>
- where I: SliceIndex<Self>
- {
- core_slice::SliceExt::get(self, index)
- }
-
- /// Returns a mutable reference to an element or subslice depending on the
- /// type of index (see [`get`]) or `None` if the index is out of bounds.
- ///
- /// [`get`]: #method.get
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &mut [0, 1, 2];
- ///
- /// if let Some(elem) = x.get_mut(1) {
- /// *elem = 42;
- /// }
- /// assert_eq!(x, &[0, 42, 2]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
- where I: SliceIndex<Self>
- {
- core_slice::SliceExt::get_mut(self, index)
- }
-
- /// Returns a reference to an element or subslice, without doing bounds
- /// checking.
- ///
- /// This is generally not recommended, use with caution! For a safe
- /// alternative see [`get`].
- ///
- /// [`get`]: #method.get
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &[1, 2, 4];
- ///
- /// unsafe {
- /// assert_eq!(x.get_unchecked(1), &2);
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
- where I: SliceIndex<Self>
- {
- core_slice::SliceExt::get_unchecked(self, index)
- }
-
- /// Returns a mutable reference to an element or subslice, without doing
- /// bounds checking.
- ///
- /// This is generally not recommended, use with caution! For a safe
- /// alternative see [`get_mut`].
- ///
- /// [`get_mut`]: #method.get_mut
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &mut [1, 2, 4];
- ///
- /// unsafe {
- /// let elem = x.get_unchecked_mut(1);
- /// *elem = 13;
- /// }
- /// assert_eq!(x, &[1, 13, 4]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
- where I: SliceIndex<Self>
- {
- core_slice::SliceExt::get_unchecked_mut(self, index)
- }
-
- /// Returns a raw pointer to the slice's buffer.
- ///
- /// The caller must ensure that the slice outlives the pointer this
- /// function returns, or else it will end up pointing to garbage.
- ///
- /// Modifying the container referenced by this slice may cause its buffer
- /// to be reallocated, which would also make any pointers to it invalid.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &[1, 2, 4];
- /// let x_ptr = x.as_ptr();
- ///
- /// unsafe {
- /// for i in 0..x.len() {
- /// assert_eq!(x.get_unchecked(i), &*x_ptr.offset(i as isize));
- /// }
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn as_ptr(&self) -> *const T {
- core_slice::SliceExt::as_ptr(self)
- }
-
- /// Returns an unsafe mutable pointer to the slice's buffer.
- ///
- /// The caller must ensure that the slice outlives the pointer this
- /// function returns, or else it will end up pointing to garbage.
- ///
- /// Modifying the container referenced by this slice may cause its buffer
- /// to be reallocated, which would also make any pointers to it invalid.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &mut [1, 2, 4];
- /// let x_ptr = x.as_mut_ptr();
- ///
- /// unsafe {
- /// for i in 0..x.len() {
- /// *x_ptr.offset(i as isize) += 2;
- /// }
- /// }
- /// assert_eq!(x, &[3, 4, 6]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn as_mut_ptr(&mut self) -> *mut T {
- core_slice::SliceExt::as_mut_ptr(self)
- }
-
- /// Swaps two elements in the slice.
- ///
- /// # Arguments
- ///
- /// * a - The index of the first element
- /// * b - The index of the second element
- ///
- /// # Panics
- ///
- /// Panics if `a` or `b` are out of bounds.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = ["a", "b", "c", "d"];
- /// v.swap(1, 3);
- /// assert!(v == ["a", "d", "c", "b"]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn swap(&mut self, a: usize, b: usize) {
- core_slice::SliceExt::swap(self, a, b)
- }
-
- /// Reverses the order of elements in the slice, in place.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = [1, 2, 3];
- /// v.reverse();
- /// assert!(v == [3, 2, 1]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn reverse(&mut self) {
- core_slice::SliceExt::reverse(self)
- }
-
- /// Returns an iterator over the slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &[1, 2, 4];
- /// let mut iterator = x.iter();
- ///
- /// assert_eq!(iterator.next(), Some(&1));
- /// assert_eq!(iterator.next(), Some(&2));
- /// assert_eq!(iterator.next(), Some(&4));
- /// assert_eq!(iterator.next(), None);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn iter(&self) -> Iter<T> {
- core_slice::SliceExt::iter(self)
- }
-
- /// Returns an iterator that allows modifying each value.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &mut [1, 2, 4];
- /// for elem in x.iter_mut() {
- /// *elem += 2;
- /// }
- /// assert_eq!(x, &[3, 4, 6]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn iter_mut(&mut self) -> IterMut<T> {
- core_slice::SliceExt::iter_mut(self)
- }
-
- /// Returns an iterator over all contiguous windows of length
- /// `size`. The windows overlap. If the slice is shorter than
- /// `size`, the iterator returns no values.
- ///
- /// # Panics
- ///
- /// Panics if `size` is 0.
- ///
- /// # Examples
- ///
- /// ```
- /// let slice = ['r', 'u', 's', 't'];
- /// let mut iter = slice.windows(2);
- /// assert_eq!(iter.next().unwrap(), &['r', 'u']);
- /// assert_eq!(iter.next().unwrap(), &['u', 's']);
- /// assert_eq!(iter.next().unwrap(), &['s', 't']);
- /// assert!(iter.next().is_none());
- /// ```
- ///
- /// If the slice is shorter than `size`:
- ///
- /// ```
- /// let slice = ['f', 'o', 'o'];
- /// let mut iter = slice.windows(4);
- /// assert!(iter.next().is_none());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn windows(&self, size: usize) -> Windows<T> {
- core_slice::SliceExt::windows(self, size)
- }
-
- /// Returns an iterator over `chunk_size` elements of the slice at a
- /// time. The chunks are slices and do not overlap. If `chunk_size` does
- /// 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
- /// of always exactly `chunk_size` elements.
- ///
- /// # Panics
- ///
- /// Panics if `chunk_size` is 0.
- ///
- /// # Examples
- ///
- /// ```
- /// let slice = ['l', 'o', 'r', 'e', 'm'];
- /// let mut iter = slice.chunks(2);
- /// assert_eq!(iter.next().unwrap(), &['l', 'o']);
- /// assert_eq!(iter.next().unwrap(), &['r', 'e']);
- /// assert_eq!(iter.next().unwrap(), &['m']);
- /// assert!(iter.next().is_none());
- /// ```
- ///
- /// [`exact_chunks`]: #method.exact_chunks
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn chunks(&self, chunk_size: usize) -> Chunks<T> {
- core_slice::SliceExt::chunks(self, chunk_size)
- }
-
- /// Returns an iterator over `chunk_size` elements of the slice at a
- /// time. The chunks are slices and do not overlap. If `chunk_size` does
- /// not divide the length of the slice, then the last up to `chunk_size-1`
- /// elements will be omitted.
- ///
- /// Due to each chunk having exactly `chunk_size` elements, the compiler
- /// can often optimize the resulting code better than in the case of
- /// [`chunks`].
- ///
- /// # Panics
- ///
- /// Panics if `chunk_size` is 0.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(exact_chunks)]
- ///
- /// let slice = ['l', 'o', 'r', 'e', 'm'];
- /// let mut iter = slice.exact_chunks(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")]
- #[inline]
- pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks<T> {
- core_slice::SliceExt::exact_chunks(self, chunk_size)
- }
-
- /// Returns an iterator over `chunk_size` elements of the slice at a time.
- /// The chunks are mutable slices, and do not overlap. If `chunk_size` does
- /// 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
- /// of always exactly `chunk_size` elements.
- ///
- /// # Panics
- ///
- /// Panics if `chunk_size` is 0.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = &mut [0, 0, 0, 0, 0];
- /// let mut count = 1;
- ///
- /// for chunk in v.chunks_mut(2) {
- /// for elem in chunk.iter_mut() {
- /// *elem += count;
- /// }
- /// count += 1;
- /// }
- /// assert_eq!(v, &[1, 1, 2, 2, 3]);
- /// ```
- ///
- /// [`exact_chunks_mut`]: #method.exact_chunks_mut
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> {
- core_slice::SliceExt::chunks_mut(self, chunk_size)
- }
-
- /// Returns an iterator over `chunk_size` elements of the slice at a time.
- /// The chunks are mutable slices, and do not overlap. If `chunk_size` does
- /// not divide the length of the slice, then the last up to `chunk_size-1`
- /// elements will be omitted.
- ///
- ///
- /// Due to each chunk having exactly `chunk_size` elements, the compiler
- /// can often optimize the resulting code better than in the case of
- /// [`chunks_mut`].
- ///
- /// # Panics
- ///
- /// Panics if `chunk_size` is 0.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(exact_chunks)]
- ///
- /// let v = &mut [0, 0, 0, 0, 0];
- /// let mut count = 1;
- ///
- /// for chunk in v.exact_chunks_mut(2) {
- /// for elem in chunk.iter_mut() {
- /// *elem += count;
- /// }
- /// count += 1;
- /// }
- /// assert_eq!(v, &[1, 1, 2, 2, 0]);
- /// ```
- ///
- /// [`chunks_mut`]: #method.chunks_mut
- #[unstable(feature = "exact_chunks", issue = "47115")]
- #[inline]
- pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut<T> {
- core_slice::SliceExt::exact_chunks_mut(self, chunk_size)
- }
-
- /// Divides one slice 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).
- ///
- /// # Panics
- ///
- /// Panics if `mid > len`.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = [1, 2, 3, 4, 5, 6];
- ///
- /// {
- /// let (left, right) = v.split_at(0);
- /// assert!(left == []);
- /// assert!(right == [1, 2, 3, 4, 5, 6]);
- /// }
- ///
- /// {
- /// let (left, right) = v.split_at(2);
- /// assert!(left == [1, 2]);
- /// assert!(right == [3, 4, 5, 6]);
- /// }
- ///
- /// {
- /// let (left, right) = v.split_at(6);
- /// assert!(left == [1, 2, 3, 4, 5, 6]);
- /// assert!(right == []);
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn split_at(&self, mid: usize) -> (&[T], &[T]) {
- core_slice::SliceExt::split_at(self, mid)
- }
-
- /// Divides one mutable slice 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).
- ///
- /// # Panics
- ///
- /// Panics if `mid > len`.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = [1, 0, 3, 0, 5, 6];
- /// // scoped to restrict the lifetime of the borrows
- /// {
- /// let (left, right) = v.split_at_mut(2);
- /// assert!(left == [1, 0]);
- /// assert!(right == [3, 0, 5, 6]);
- /// left[1] = 2;
- /// right[1] = 4;
- /// }
- /// assert!(v == [1, 2, 3, 4, 5, 6]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
- core_slice::SliceExt::split_at_mut(self, mid)
- }
-
- /// Returns an iterator over subslices separated by elements that match
- /// `pred`. The matched element is not contained in the subslices.
- ///
- /// # Examples
- ///
- /// ```
- /// let slice = [10, 40, 33, 20];
- /// let mut iter = slice.split(|num| num % 3 == 0);
- ///
- /// assert_eq!(iter.next().unwrap(), &[10, 40]);
- /// assert_eq!(iter.next().unwrap(), &[20]);
- /// assert!(iter.next().is_none());
- /// ```
- ///
- /// If the first element is matched, an empty slice will be the first item
- /// returned by the iterator. Similarly, if the last element in the slice
- /// is matched, an empty slice will be the last item returned by the
- /// iterator:
- ///
- /// ```
- /// let slice = [10, 40, 33];
- /// let mut iter = slice.split(|num| num % 3 == 0);
- ///
- /// assert_eq!(iter.next().unwrap(), &[10, 40]);
- /// assert_eq!(iter.next().unwrap(), &[]);
- /// assert!(iter.next().is_none());
- /// ```
- ///
- /// If two matched elements are directly adjacent, an empty slice will be
- /// present between them:
- ///
- /// ```
- /// let slice = [10, 6, 33, 20];
- /// let mut iter = slice.split(|num| num % 3 == 0);
- ///
- /// assert_eq!(iter.next().unwrap(), &[10]);
- /// assert_eq!(iter.next().unwrap(), &[]);
- /// assert_eq!(iter.next().unwrap(), &[20]);
- /// assert!(iter.next().is_none());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn split<F>(&self, pred: F) -> Split<T, F>
- where F: FnMut(&T) -> bool
- {
- core_slice::SliceExt::split(self, pred)
- }
-
- /// Returns an iterator over mutable subslices separated by elements that
- /// match `pred`. The matched element is not contained in the subslices.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = [10, 40, 30, 20, 60, 50];
- ///
- /// for group in v.split_mut(|num| *num % 3 == 0) {
- /// group[0] = 1;
- /// }
- /// assert_eq!(v, [1, 40, 30, 1, 60, 1]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<T, F>
- where F: FnMut(&T) -> bool
- {
- core_slice::SliceExt::split_mut(self, pred)
- }
-
- /// Returns an iterator over subslices separated by elements that match
- /// `pred`, starting at the end of the slice and working backwards.
- /// The matched element is not contained in the subslices.
- ///
- /// # Examples
- ///
- /// ```
- ///
- /// let slice = [11, 22, 33, 0, 44, 55];
- /// let mut iter = slice.rsplit(|num| *num == 0);
- ///
- /// assert_eq!(iter.next().unwrap(), &[44, 55]);
- /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]);
- /// assert_eq!(iter.next(), None);
- /// ```
- ///
- /// As with `split()`, if the first or last element is matched, an empty
- /// slice will be the first (or last) item returned by the iterator.
- ///
- /// ```
- /// let v = &[0, 1, 1, 2, 3, 5, 8];
- /// let mut it = v.rsplit(|n| *n % 2 == 0);
- /// assert_eq!(it.next().unwrap(), &[]);
- /// assert_eq!(it.next().unwrap(), &[3, 5]);
- /// assert_eq!(it.next().unwrap(), &[1, 1]);
- /// assert_eq!(it.next().unwrap(), &[]);
- /// assert_eq!(it.next(), None);
- /// ```
- #[stable(feature = "slice_rsplit", since = "1.27.0")]
- #[inline]
- pub fn rsplit<F>(&self, pred: F) -> RSplit<T, F>
- where F: FnMut(&T) -> bool
- {
- core_slice::SliceExt::rsplit(self, pred)
- }
-
- /// Returns an iterator over mutable subslices separated by elements that
- /// match `pred`, starting at the end of the slice and working
- /// backwards. The matched element is not contained in the subslices.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = [100, 400, 300, 200, 600, 500];
- ///
- /// let mut count = 0;
- /// for group in v.rsplit_mut(|num| *num % 3 == 0) {
- /// count += 1;
- /// group[0] = count;
- /// }
- /// assert_eq!(v, [3, 400, 300, 2, 600, 1]);
- /// ```
- ///
- #[stable(feature = "slice_rsplit", since = "1.27.0")]
- #[inline]
- pub fn rsplit_mut<F>(&mut self, pred: F) -> RSplitMut<T, F>
- where F: FnMut(&T) -> bool
- {
- core_slice::SliceExt::rsplit_mut(self, pred)
- }
-
- /// Returns an iterator over subslices separated by elements that match
- /// `pred`, limited to returning at most `n` items. The matched element is
- /// not contained in the subslices.
- ///
- /// The last element returned, if any, will contain the remainder of the
- /// slice.
- ///
- /// # Examples
- ///
- /// Print the slice split once by numbers divisible by 3 (i.e. `[10, 40]`,
- /// `[20, 60, 50]`):
- ///
- /// ```
- /// let v = [10, 40, 30, 20, 60, 50];
- ///
- /// for group in v.splitn(2, |num| *num % 3 == 0) {
- /// println!("{:?}", group);
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<T, F>
- where F: FnMut(&T) -> bool
- {
- core_slice::SliceExt::splitn(self, n, pred)
- }
-
- /// Returns an iterator over subslices separated by elements that match
- /// `pred`, limited to returning at most `n` items. The matched element is
- /// not contained in the subslices.
- ///
- /// The last element returned, if any, will contain the remainder of the
- /// slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = [10, 40, 30, 20, 60, 50];
- ///
- /// for group in v.splitn_mut(2, |num| *num % 3 == 0) {
- /// group[0] = 1;
- /// }
- /// assert_eq!(v, [1, 40, 30, 1, 60, 50]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<T, F>
- where F: FnMut(&T) -> bool
- {
- core_slice::SliceExt::splitn_mut(self, n, pred)
- }
-
- /// Returns an iterator over subslices separated by elements that match
- /// `pred` limited to returning at most `n` items. This starts at the end of
- /// the slice and works backwards. The matched element is not contained in
- /// the subslices.
- ///
- /// The last element returned, if any, will contain the remainder of the
- /// slice.
- ///
- /// # Examples
- ///
- /// Print the slice split once, starting from the end, by numbers divisible
- /// by 3 (i.e. `[50]`, `[10, 40, 30, 20]`):
- ///
- /// ```
- /// let v = [10, 40, 30, 20, 60, 50];
- ///
- /// for group in v.rsplitn(2, |num| *num % 3 == 0) {
- /// println!("{:?}", group);
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<T, F>
- where F: FnMut(&T) -> bool
- {
- core_slice::SliceExt::rsplitn(self, n, pred)
- }
-
- /// Returns an iterator over subslices separated by elements that match
- /// `pred` limited to returning at most `n` items. This starts at the end of
- /// the slice and works backwards. The matched element is not contained in
- /// the subslices.
- ///
- /// The last element returned, if any, will contain the remainder of the
- /// slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut s = [10, 40, 30, 20, 60, 50];
- ///
- /// for group in s.rsplitn_mut(2, |num| *num % 3 == 0) {
- /// group[0] = 1;
- /// }
- /// assert_eq!(s, [1, 40, 30, 20, 60, 1]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<T, F>
- where F: FnMut(&T) -> bool
- {
- core_slice::SliceExt::rsplitn_mut(self, n, pred)
- }
-
- /// Returns `true` if the slice contains an element with the given value.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = [10, 40, 30];
- /// assert!(v.contains(&30));
- /// assert!(!v.contains(&50));
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn contains(&self, x: &T) -> bool
- where T: PartialEq
- {
- core_slice::SliceExt::contains(self, x)
- }
-
- /// Returns `true` if `needle` is a prefix of the slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = [10, 40, 30];
- /// assert!(v.starts_with(&[10]));
- /// assert!(v.starts_with(&[10, 40]));
- /// assert!(!v.starts_with(&[50]));
- /// assert!(!v.starts_with(&[10, 50]));
- /// ```
- ///
- /// Always returns `true` if `needle` is an empty slice:
- ///
- /// ```
- /// let v = &[10, 40, 30];
- /// assert!(v.starts_with(&[]));
- /// let v: &[u8] = &[];
- /// assert!(v.starts_with(&[]));
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn starts_with(&self, needle: &[T]) -> bool
- where T: PartialEq
- {
- core_slice::SliceExt::starts_with(self, needle)
- }
-
- /// Returns `true` if `needle` is a suffix of the slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = [10, 40, 30];
- /// assert!(v.ends_with(&[30]));
- /// assert!(v.ends_with(&[40, 30]));
- /// assert!(!v.ends_with(&[50]));
- /// assert!(!v.ends_with(&[50, 30]));
- /// ```
- ///
- /// Always returns `true` if `needle` is an empty slice:
- ///
- /// ```
- /// let v = &[10, 40, 30];
- /// assert!(v.ends_with(&[]));
- /// let v: &[u8] = &[];
- /// assert!(v.ends_with(&[]));
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn ends_with(&self, needle: &[T]) -> bool
- where T: PartialEq
- {
- core_slice::SliceExt::ends_with(self, needle)
- }
-
- /// Binary searches this sorted slice for a given element.
- ///
- /// If the value is found then `Ok` is returned, containing the
- /// index of the matching element; if the value is not found then
- /// `Err` is returned, containing the index where a matching
- /// element could be inserted while maintaining sorted order.
- ///
- /// # Examples
- ///
- /// Looks up a series of four elements. The first is found, with a
- /// uniquely determined position; the second and third are not
- /// found; the fourth could match any position in `[1, 4]`.
- ///
- /// ```
- /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
- ///
- /// assert_eq!(s.binary_search(&13), Ok(9));
- /// assert_eq!(s.binary_search(&4), Err(7));
- /// assert_eq!(s.binary_search(&100), Err(13));
- /// let r = s.binary_search(&1);
- /// assert!(match r { Ok(1...4) => true, _ => false, });
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn binary_search(&self, x: &T) -> Result<usize, usize>
- where T: Ord
- {
- core_slice::SliceExt::binary_search(self, x)
- }
-
- /// Binary searches this sorted slice with a comparator function.
- ///
- /// The comparator function should implement an order consistent
- /// with the sort order of the underlying slice, returning an
- /// order code that indicates whether its argument is `Less`,
- /// `Equal` or `Greater` the desired target.
- ///
- /// If a matching value is found then returns `Ok`, containing
- /// the index for the matched element; if no match is found then
- /// `Err` is returned, containing the index where a matching
- /// element could be inserted while maintaining sorted order.
- ///
- /// # Examples
- ///
- /// Looks up a series of four elements. The first is found, with a
- /// uniquely determined position; the second and third are not
- /// found; the fourth could match any position in `[1, 4]`.
- ///
- /// ```
- /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
- ///
- /// let seek = 13;
- /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9));
- /// let seek = 4;
- /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7));
- /// let seek = 100;
- /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13));
- /// let seek = 1;
- /// let r = s.binary_search_by(|probe| probe.cmp(&seek));
- /// assert!(match r { Ok(1...4) => true, _ => false, });
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
- where F: FnMut(&'a T) -> Ordering
- {
- core_slice::SliceExt::binary_search_by(self, f)
- }
-
- /// Binary searches this sorted slice with a key extraction function.
- ///
- /// Assumes that the slice is sorted by the key, for instance with
- /// [`sort_by_key`] using the same key extraction function.
- ///
- /// If a matching value is found then returns `Ok`, containing the
- /// index for the matched element; if no match is found then `Err`
- /// is returned, containing the index where a matching element could
- /// be inserted while maintaining sorted order.
- ///
- /// [`sort_by_key`]: #method.sort_by_key
- ///
- /// # Examples
- ///
- /// Looks up a series of four elements in a slice of pairs sorted by
- /// their second elements. The first is found, with a uniquely
- /// determined position; the second and third are not found; the
- /// fourth could match any position in `[1, 4]`.
- ///
- /// ```
- /// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1),
- /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
- /// (1, 21), (2, 34), (4, 55)];
- ///
- /// assert_eq!(s.binary_search_by_key(&13, |&(a,b)| b), Ok(9));
- /// assert_eq!(s.binary_search_by_key(&4, |&(a,b)| b), Err(7));
- /// assert_eq!(s.binary_search_by_key(&100, |&(a,b)| b), Err(13));
- /// let r = s.binary_search_by_key(&1, |&(a,b)| b);
- /// assert!(match r { Ok(1...4) => true, _ => false, });
- /// ```
- #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")]
- #[inline]
- pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result<usize, usize>
- where F: FnMut(&'a T) -> B,
- B: Ord
- {
- core_slice::SliceExt::binary_search_by_key(self, b, f)
- }
+ #[cfg(stage0)]
+ slice_core_methods!();
/// Sorts the slice.
///
sort_by_key!(usize, self, f)
}
- /// 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),
- /// and `O(n log n)` worst-case.
- ///
- /// # 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.
- ///
- /// It is typically faster than stable sorting, except in a few special cases, e.g. when the
- /// slice consists of several concatenated sorted sequences.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = [-5, 4, 1, -3, 2];
- ///
- /// v.sort_unstable();
- /// assert!(v == [-5, -3, 1, 2, 4]);
- /// ```
- ///
- /// [pdqsort]: https://github.com/orlp/pdqsort
- #[stable(feature = "sort_unstable", since = "1.20.0")]
- #[inline]
- pub fn sort_unstable(&mut self)
- where T: Ord
- {
- core_slice::SliceExt::sort_unstable(self);
- }
-
- /// Sorts the slice with a comparator function, 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),
- /// and `O(n log n)` worst-case.
- ///
- /// # 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.
- ///
- /// It is typically faster than stable sorting, except in a few special cases, e.g. when the
- /// slice consists of several concatenated sorted sequences.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = [5, 4, 1, 3, 2];
- /// v.sort_unstable_by(|a, b| a.cmp(b));
- /// assert!(v == [1, 2, 3, 4, 5]);
- ///
- /// // reverse sorting
- /// v.sort_unstable_by(|a, b| b.cmp(a));
- /// assert!(v == [5, 4, 3, 2, 1]);
- /// ```
- ///
- /// [pdqsort]: https://github.com/orlp/pdqsort
- #[stable(feature = "sort_unstable", since = "1.20.0")]
- #[inline]
- pub fn sort_unstable_by<F>(&mut self, compare: F)
- where F: FnMut(&T, &T) -> Ordering
- {
- core_slice::SliceExt::sort_unstable_by(self, compare);
- }
-
- /// Sorts the slice with a key extraction function, 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),
- /// and `O(m n log(m n))` worst-case, where the key function is `O(m)`.
- ///
- /// # 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.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = [-5i32, 4, 1, -3, 2];
- ///
- /// v.sort_unstable_by_key(|k| k.abs());
- /// assert!(v == [1, 2, -3, 4, -5]);
- /// ```
- ///
- /// [pdqsort]: https://github.com/orlp/pdqsort
- #[stable(feature = "sort_unstable", since = "1.20.0")]
- #[inline]
- pub fn sort_unstable_by_key<K, F>(&mut self, f: F)
- where F: FnMut(&T) -> K, K: Ord
- {
- core_slice::SliceExt::sort_unstable_by_key(self, f);
- }
-
- /// 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
- /// `mid` will become the first element in the slice.
- ///
- /// # Panics
- ///
- /// This function will panic if `mid` is greater than the length of the
- /// slice. Note that `mid == self.len()` does _not_ panic and is a no-op
- /// rotation.
- ///
- /// # Complexity
- ///
- /// Takes linear (in `self.len()`) time.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
- /// a.rotate_left(2);
- /// assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']);
- /// ```
- ///
- /// Rotating a subslice:
- ///
- /// ```
- /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
- /// a[1..5].rotate_left(1);
- /// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']);
- /// ```
- #[stable(feature = "slice_rotate", since = "1.26.0")]
- pub fn rotate_left(&mut self, mid: usize) {
- core_slice::SliceExt::rotate_left(self, mid);
- }
-
- /// Rotates the slice in-place such that the first `self.len() - k`
- /// elements of the slice move to the end while the last `k` elements move
- /// to the front. After calling `rotate_right`, the element previously at
- /// index `self.len() - k` will become the first element in the slice.
- ///
- /// # Panics
- ///
- /// This function will panic if `k` is greater than the length of the
- /// slice. Note that `k == self.len()` does _not_ panic and is a no-op
- /// rotation.
- ///
- /// # Complexity
- ///
- /// Takes linear (in `self.len()`) time.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
- /// a.rotate_right(2);
- /// assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']);
- /// ```
- ///
- /// Rotate a subslice:
- ///
- /// ```
- /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
- /// a[1..5].rotate_right(1);
- /// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']);
- /// ```
- #[stable(feature = "slice_rotate", since = "1.26.0")]
- pub fn rotate_right(&mut self, k: usize) {
- core_slice::SliceExt::rotate_right(self, k);
- }
-
- /// Copies the elements from `src` into `self`.
- ///
- /// The length of `src` must be the same as `self`.
- ///
- /// If `src` implements `Copy`, it can be more performant to use
- /// [`copy_from_slice`].
- ///
- /// # Panics
- ///
- /// This function will panic if the two slices have different lengths.
- ///
- /// # Examples
- ///
- /// Cloning two elements from a slice into another:
- ///
- /// ```
- /// let src = [1, 2, 3, 4];
- /// let mut dst = [0, 0];
- ///
- /// dst.clone_from_slice(&src[2..]);
- ///
- /// assert_eq!(src, [1, 2, 3, 4]);
- /// assert_eq!(dst, [3, 4]);
- /// ```
- ///
- /// Rust enforces that there can only be one mutable reference with no
- /// immutable references to a particular piece of data in a particular
- /// scope. Because of this, attempting to use `clone_from_slice` on a
- /// single slice will result in a compile failure:
- ///
- /// ```compile_fail
- /// let mut slice = [1, 2, 3, 4, 5];
- ///
- /// slice[..2].clone_from_slice(&slice[3..]); // compile fail!
- /// ```
- ///
- /// To work around this, we can use [`split_at_mut`] to create two distinct
- /// sub-slices from a slice:
- ///
- /// ```
- /// let mut slice = [1, 2, 3, 4, 5];
- ///
- /// {
- /// let (left, right) = slice.split_at_mut(2);
- /// left.clone_from_slice(&right[1..]);
- /// }
- ///
- /// assert_eq!(slice, [4, 5, 3, 4, 5]);
- /// ```
- ///
- /// [`copy_from_slice`]: #method.copy_from_slice
- /// [`split_at_mut`]: #method.split_at_mut
- #[stable(feature = "clone_from_slice", since = "1.7.0")]
- pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone {
- core_slice::SliceExt::clone_from_slice(self, src)
- }
-
- /// Copies all elements from `src` into `self`, using a memcpy.
- ///
- /// The length of `src` must be the same as `self`.
- ///
- /// If `src` does not implement `Copy`, use [`clone_from_slice`].
- ///
- /// # Panics
- ///
- /// This function will panic if the two slices have different lengths.
- ///
- /// # Examples
- ///
- /// Copying two elements from a slice into another:
- ///
- /// ```
- /// let src = [1, 2, 3, 4];
- /// let mut dst = [0, 0];
- ///
- /// dst.copy_from_slice(&src[2..]);
- ///
- /// assert_eq!(src, [1, 2, 3, 4]);
- /// assert_eq!(dst, [3, 4]);
- /// ```
- ///
- /// Rust enforces that there can only be one mutable reference with no
- /// immutable references to a particular piece of data in a particular
- /// scope. Because of this, attempting to use `copy_from_slice` on a
- /// single slice will result in a compile failure:
- ///
- /// ```compile_fail
- /// let mut slice = [1, 2, 3, 4, 5];
- ///
- /// slice[..2].copy_from_slice(&slice[3..]); // compile fail!
- /// ```
- ///
- /// To work around this, we can use [`split_at_mut`] to create two distinct
- /// sub-slices from a slice:
- ///
- /// ```
- /// let mut slice = [1, 2, 3, 4, 5];
- ///
- /// {
- /// let (left, right) = slice.split_at_mut(2);
- /// left.copy_from_slice(&right[1..]);
- /// }
- ///
- /// assert_eq!(slice, [4, 5, 3, 4, 5]);
- /// ```
- ///
- /// [`clone_from_slice`]: #method.clone_from_slice
- /// [`split_at_mut`]: #method.split_at_mut
- #[stable(feature = "copy_from_slice", since = "1.9.0")]
- pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy {
- core_slice::SliceExt::copy_from_slice(self, src)
- }
-
- /// Swaps all elements in `self` with those in `other`.
- ///
- /// The length of `other` must be the same as `self`.
- ///
- /// # Panics
- ///
- /// This function will panic if the two slices have different lengths.
- ///
- /// # Example
- ///
- /// Swapping two elements across slices:
- ///
- /// ```
- /// let mut slice1 = [0, 0];
- /// let mut slice2 = [1, 2, 3, 4];
- ///
- /// slice1.swap_with_slice(&mut slice2[2..]);
- ///
- /// assert_eq!(slice1, [3, 4]);
- /// assert_eq!(slice2, [1, 2, 0, 0]);
- /// ```
- ///
- /// Rust enforces that there can only be one mutable reference to a
- /// particular piece of data in a particular scope. Because of this,
- /// attempting to use `swap_with_slice` on a single slice will result in
- /// a compile failure:
- ///
- /// ```compile_fail
- /// let mut slice = [1, 2, 3, 4, 5];
- /// slice[..2].swap_with_slice(&mut slice[3..]); // compile fail!
- /// ```
- ///
- /// To work around this, we can use [`split_at_mut`] to create two distinct
- /// mutable sub-slices from a slice:
- ///
- /// ```
- /// let mut slice = [1, 2, 3, 4, 5];
- ///
- /// {
- /// let (left, right) = slice.split_at_mut(2);
- /// left.swap_with_slice(&mut right[1..]);
- /// }
- ///
- /// assert_eq!(slice, [4, 5, 3, 1, 2]);
- /// ```
- ///
- /// [`split_at_mut`]: #method.split_at_mut
- #[stable(feature = "swap_with_slice", since = "1.27.0")]
- pub fn swap_with_slice(&mut self, other: &mut [T]) {
- core_slice::SliceExt::swap_with_slice(self, other)
- }
-
/// Copies `self` into a new `Vec`.
///
/// # Examples
// NB see hack module in this file
hack::into_vec(self)
}
+
+ /// Creates a vector by repeating a slice `n` times.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(repeat_generic_slice)]
+ ///
+ /// fn main() {
+ /// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]);
+ /// }
+ /// ```
+ #[unstable(feature = "repeat_generic_slice",
+ reason = "it's on str, why not on slice?",
+ issue = "48784")]
+ pub fn repeat(&self, n: usize) -> Vec<T> where T: Copy {
+ if n == 0 {
+ return Vec::new();
+ }
+
+ // If `n` is larger than zero, it can be split as
+ // `n = 2^expn + rem (2^expn > rem, expn >= 0, rem >= 0)`.
+ // `2^expn` is the number represented by the leftmost '1' bit of `n`,
+ // and `rem` is the remaining part of `n`.
+
+ // Using `Vec` to access `set_len()`.
+ let mut buf = Vec::with_capacity(self.len() * n);
+
+ // `2^expn` repetition is done by doubling `buf` `expn`-times.
+ buf.extend(self);
+ {
+ let mut m = n >> 1;
+ // If `m > 0`, there are remaining bits up to the leftmost '1'.
+ while m > 0 {
+ // `buf.extend(buf)`:
+ unsafe {
+ ptr::copy_nonoverlapping(
+ buf.as_ptr(),
+ (buf.as_mut_ptr() as *mut T).add(buf.len()),
+ buf.len(),
+ );
+ // `buf` has capacity of `self.len() * n`.
+ let buf_len = buf.len();
+ buf.set_len(buf_len * 2);
+ }
+
+ m >>= 1;
+ }
+ }
+
+ // `rem` (`= n - 2^expn`) repetition is done by copying
+ // first `rem` repetitions from `buf` itself.
+ let rem_len = self.len() * n - buf.len(); // `self.len() * rem`
+ if rem_len > 0 {
+ // `buf.extend(buf[0 .. rem_len])`:
+ unsafe {
+ // This is non-overlapping since `2^expn > rem`.
+ ptr::copy_nonoverlapping(
+ buf.as_ptr(),
+ (buf.as_mut_ptr() as *mut T).add(buf.len()),
+ rem_len,
+ );
+ // `buf.len() + rem_len` equals to `buf.capacity()` (`= self.len() * n`).
+ let buf_cap = buf.capacity();
+ buf.set_len(buf_cap);
+ }
+ }
+ buf
+ }
}
-#[lang = "slice_u8"]
+#[cfg_attr(stage0, lang = "slice_u8")]
+#[cfg_attr(not(stage0), lang = "slice_u8_alloc")]
#[cfg(not(test))]
impl [u8] {
- /// Checks if all bytes in this slice are within the ASCII range.
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- #[inline]
- pub fn is_ascii(&self) -> bool {
- self.iter().all(|b| b.is_ascii())
- }
-
/// Returns a vector containing a copy of this slice where each byte
/// is mapped to its ASCII upper case equivalent.
///
me
}
- /// Checks that two slices are an ASCII case-insensitive match.
- ///
- /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
- /// but without allocating and copying temporaries.
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- #[inline]
- pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
- self.len() == other.len() &&
- self.iter().zip(other).all(|(a, b)| {
- a.eq_ignore_ascii_case(b)
- })
- }
-
- /// Converts this slice to its ASCII upper case equivalent in-place.
- ///
- /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
- /// but non-ASCII letters are unchanged.
- ///
- /// To return a new uppercased value without modifying the existing one, use
- /// [`to_ascii_uppercase`].
- ///
- /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- #[inline]
- pub fn make_ascii_uppercase(&mut self) {
- for byte in self {
- byte.make_ascii_uppercase();
- }
- }
-
- /// Converts this slice to its ASCII lower case equivalent in-place.
- ///
- /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
- /// but non-ASCII letters are unchanged.
- ///
- /// To return a new lowercased value without modifying the existing one, use
- /// [`to_ascii_lowercase`].
- ///
- /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- #[inline]
- pub fn make_ascii_lowercase(&mut self) {
- for byte in self {
- byte.make_ascii_lowercase();
- }
- }
+ #[cfg(stage0)]
+ slice_u8_core_methods!();
}
////////////////////////////////////////////////////////////////////////////////
use core::fmt;
use core::str as core_str;
+#[cfg(stage0)] use core::str::StrExt;
use core::str::pattern::Pattern;
use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
use core::mem;
pub use core::str::SplitWhitespace;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::str::pattern;
-
+#[stable(feature = "encode_utf16", since = "1.8.0")]
+pub use core::str::EncodeUtf16;
#[unstable(feature = "slice_concat_ext",
reason = "trait should not have to exist",
fn concat(&self) -> String {
if self.is_empty() {
- return String::new();
- }
-
- // `len` calculation may overflow but push_str will check boundaries
- let len = self.iter().map(|s| s.borrow().len()).sum();
- let mut result = String::with_capacity(len);
-
- for s in self {
- result.push_str(s.borrow())
- }
-
- result
- }
-
- fn join(&self, sep: &str) -> String {
- if self.is_empty() {
- return String::new();
- }
-
- // concat is faster
- if sep.is_empty() {
- return self.concat();
- }
-
- // this is wrong without the guarantee that `self` is non-empty
- // `len` calculation may overflow but push_str but will check boundaries
- let len = sep.len() * (self.len() - 1) +
- self.iter().map(|s| s.borrow().len()).sum::<usize>();
- let mut result = String::with_capacity(len);
- let mut first = true;
-
- for s in self {
- if first {
- first = false;
- } else {
- result.push_str(sep);
- }
- result.push_str(s.borrow());
- }
- result
- }
-
- fn connect(&self, sep: &str) -> String {
- self.join(sep)
- }
-}
-
-/// An iterator of [`u16`] over the string encoded as UTF-16.
-///
-/// [`u16`]: ../../std/primitive.u16.html
-///
-/// This struct is created by the [`encode_utf16`] method on [`str`].
-/// See its documentation for more.
-///
-/// [`encode_utf16`]: ../../std/primitive.str.html#method.encode_utf16
-/// [`str`]: ../../std/primitive.str.html
-#[derive(Clone)]
-#[stable(feature = "encode_utf16", since = "1.8.0")]
-pub struct EncodeUtf16<'a> {
- chars: Chars<'a>,
- extra: u16,
-}
-
-#[stable(feature = "collection_debug", since = "1.17.0")]
-impl<'a> fmt::Debug for EncodeUtf16<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.pad("EncodeUtf16 { .. }")
- }
-}
-
-#[stable(feature = "encode_utf16", since = "1.8.0")]
-impl<'a> Iterator for EncodeUtf16<'a> {
- type Item = u16;
-
- #[inline]
- fn next(&mut self) -> Option<u16> {
- if self.extra != 0 {
- let tmp = self.extra;
- self.extra = 0;
- return Some(tmp);
- }
-
- let mut buf = [0; 2];
- self.chars.next().map(|ch| {
- let n = ch.encode_utf16(&mut buf).len();
- if n == 2 {
- self.extra = buf[1];
- }
- buf[0]
- })
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let (low, high) = self.chars.size_hint();
- // every char gets either one u16 or two u16,
- // so this iterator is between 1 or 2 times as
- // long as the underlying iterator.
- (low, high.and_then(|n| n.checked_mul(2)))
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<'a> FusedIterator for EncodeUtf16<'a> {}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Borrow<str> for String {
- #[inline]
- fn borrow(&self) -> &str {
- &self[..]
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl ToOwned for str {
- type Owned = String;
- fn to_owned(&self) -> String {
- unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) }
- }
-
- fn clone_into(&self, target: &mut String) {
- let mut b = mem::replace(target, String::new()).into_bytes();
- self.as_bytes().clone_into(&mut b);
- *target = unsafe { String::from_utf8_unchecked(b) }
- }
-}
-
-/// Methods for string slices.
-#[lang = "str"]
-#[cfg(not(test))]
-impl str {
- /// Returns the length of `self`.
- ///
- /// This length is in bytes, not [`char`]s or graphemes. In other words,
- /// it may not be what a human considers the length of the string.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let len = "foo".len();
- /// assert_eq!(3, len);
- ///
- /// let len = "ƒoo".len(); // fancy f!
- /// assert_eq!(4, len);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn len(&self) -> usize {
- core_str::StrExt::len(self)
- }
-
- /// Returns `true` if `self` has a length of zero bytes.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let s = "";
- /// assert!(s.is_empty());
- ///
- /// let s = "not empty";
- /// assert!(!s.is_empty());
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn is_empty(&self) -> bool {
- core_str::StrExt::is_empty(self)
- }
-
- /// Checks that `index`-th byte lies at the start and/or end of a
- /// UTF-8 code point sequence.
- ///
- /// The start and end of the string (when `index == self.len()`) are
- /// considered to be
- /// boundaries.
- ///
- /// Returns `false` if `index` is greater than `self.len()`.
- ///
- /// # Examples
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- /// assert!(s.is_char_boundary(0));
- /// // start of `老`
- /// assert!(s.is_char_boundary(6));
- /// assert!(s.is_char_boundary(s.len()));
- ///
- /// // second byte of `ö`
- /// assert!(!s.is_char_boundary(2));
- ///
- /// // third byte of `老`
- /// assert!(!s.is_char_boundary(8));
- /// ```
- #[stable(feature = "is_char_boundary", since = "1.9.0")]
- #[inline]
- pub fn is_char_boundary(&self, index: usize) -> bool {
- core_str::StrExt::is_char_boundary(self, index)
- }
-
- /// Converts a string slice to a byte slice. To convert the byte slice back
- /// into a string slice, use the [`str::from_utf8`] function.
- ///
- /// [`str::from_utf8`]: ./str/fn.from_utf8.html
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let bytes = "bors".as_bytes();
- /// assert_eq!(b"bors", bytes);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline(always)]
- pub fn as_bytes(&self) -> &[u8] {
- core_str::StrExt::as_bytes(self)
- }
-
- /// Converts a mutable string slice to a mutable byte slice. To convert the
- /// mutable byte slice back into a mutable string slice, use the
- /// [`str::from_utf8_mut`] function.
- ///
- /// [`str::from_utf8_mut`]: ./str/fn.from_utf8_mut.html
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let mut s = String::from("Hello");
- /// let bytes = unsafe { s.as_bytes_mut() };
- ///
- /// assert_eq!(b"Hello", bytes);
- /// ```
- ///
- /// Mutability:
- ///
- /// ```
- /// let mut s = String::from("🗻∈🌏");
- ///
- /// unsafe {
- /// let bytes = s.as_bytes_mut();
- ///
- /// bytes[0] = 0xF0;
- /// bytes[1] = 0x9F;
- /// bytes[2] = 0x8D;
- /// bytes[3] = 0x94;
- /// }
- ///
- /// assert_eq!("🍔∈🌏", s);
- /// ```
- #[stable(feature = "str_mut_extras", since = "1.20.0")]
- #[inline(always)]
- pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
- core_str::StrExt::as_bytes_mut(self)
- }
-
- /// Converts a string slice to a raw pointer.
- ///
- /// As string slices are a slice of bytes, the raw pointer points to a
- /// [`u8`]. This pointer will be pointing to the first byte of the string
- /// slice.
- ///
- /// [`u8`]: primitive.u8.html
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let s = "Hello";
- /// let ptr = s.as_ptr();
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn as_ptr(&self) -> *const u8 {
- core_str::StrExt::as_ptr(self)
- }
-
- /// Returns a subslice of `str`.
- ///
- /// This is the non-panicking alternative to indexing the `str`. Returns
- /// [`None`] whenever equivalent indexing operation would panic.
- ///
- /// [`None`]: option/enum.Option.html#variant.None
- ///
- /// # Examples
- ///
- /// ```
- /// let v = String::from("🗻∈🌏");
- ///
- /// assert_eq!(Some("🗻"), v.get(0..4));
- ///
- /// // indices not on UTF-8 sequence boundaries
- /// assert!(v.get(1..).is_none());
- /// assert!(v.get(..8).is_none());
- ///
- /// // out of bounds
- /// assert!(v.get(..42).is_none());
- /// ```
- #[stable(feature = "str_checked_slicing", since = "1.20.0")]
- #[inline]
- pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
- core_str::StrExt::get(self, i)
- }
-
- /// Returns a mutable subslice of `str`.
- ///
- /// This is the non-panicking alternative to indexing the `str`. Returns
- /// [`None`] whenever equivalent indexing operation would panic.
- ///
- /// [`None`]: option/enum.Option.html#variant.None
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = String::from("hello");
- /// // correct length
- /// assert!(v.get_mut(0..5).is_some());
- /// // out of bounds
- /// assert!(v.get_mut(..42).is_none());
- /// assert_eq!(Some("he"), v.get_mut(0..2).map(|v| &*v));
- ///
- /// assert_eq!("hello", v);
- /// {
- /// let s = v.get_mut(0..2);
- /// let s = s.map(|s| {
- /// s.make_ascii_uppercase();
- /// &*s
- /// });
- /// assert_eq!(Some("HE"), s);
- /// }
- /// assert_eq!("HEllo", v);
- /// ```
- #[stable(feature = "str_checked_slicing", since = "1.20.0")]
- #[inline]
- pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
- core_str::StrExt::get_mut(self, i)
- }
-
- /// Returns a unchecked subslice of `str`.
- ///
- /// This is the unchecked alternative to indexing the `str`.
- ///
- /// # Safety
- ///
- /// Callers of this function are responsible that these preconditions are
- /// satisfied:
- ///
- /// * The starting index must come before the ending index;
- /// * Indexes must be within bounds of the original slice;
- /// * Indexes must lie on UTF-8 sequence boundaries.
- ///
- /// Failing that, the returned string slice may reference invalid memory or
- /// violate the invariants communicated by the `str` type.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = "🗻∈🌏";
- /// unsafe {
- /// assert_eq!("🗻", v.get_unchecked(0..4));
- /// assert_eq!("∈", v.get_unchecked(4..7));
- /// assert_eq!("🌏", v.get_unchecked(7..11));
- /// }
- /// ```
- #[stable(feature = "str_checked_slicing", since = "1.20.0")]
- #[inline]
- pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
- core_str::StrExt::get_unchecked(self, i)
- }
-
- /// Returns a mutable, unchecked subslice of `str`.
- ///
- /// This is the unchecked alternative to indexing the `str`.
- ///
- /// # Safety
- ///
- /// Callers of this function are responsible that these preconditions are
- /// satisfied:
- ///
- /// * The starting index must come before the ending index;
- /// * Indexes must be within bounds of the original slice;
- /// * Indexes must lie on UTF-8 sequence boundaries.
- ///
- /// Failing that, the returned string slice may reference invalid memory or
- /// violate the invariants communicated by the `str` type.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = String::from("🗻∈🌏");
- /// unsafe {
- /// assert_eq!("🗻", v.get_unchecked_mut(0..4));
- /// assert_eq!("∈", v.get_unchecked_mut(4..7));
- /// assert_eq!("🌏", v.get_unchecked_mut(7..11));
- /// }
- /// ```
- #[stable(feature = "str_checked_slicing", since = "1.20.0")]
- #[inline]
- pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
- core_str::StrExt::get_unchecked_mut(self, i)
- }
-
- /// Creates a string slice from another string slice, bypassing safety
- /// checks.
- ///
- /// This is generally not recommended, use with caution! For a safe
- /// alternative see [`str`] and [`Index`].
- ///
- /// [`str`]: primitive.str.html
- /// [`Index`]: ops/trait.Index.html
- ///
- /// This new slice goes from `begin` to `end`, including `begin` but
- /// excluding `end`.
- ///
- /// To get a mutable string slice instead, see the
- /// [`slice_mut_unchecked`] method.
- ///
- /// [`slice_mut_unchecked`]: #method.slice_mut_unchecked
- ///
- /// # Safety
- ///
- /// Callers of this function are responsible that three preconditions are
- /// satisfied:
- ///
- /// * `begin` must come before `end`.
- /// * `begin` and `end` must be byte positions within the string slice.
- /// * `begin` and `end` must lie on UTF-8 sequence boundaries.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- ///
- /// unsafe {
- /// assert_eq!("Löwe 老虎 Léopard", s.slice_unchecked(0, 21));
- /// }
- ///
- /// let s = "Hello, world!";
- ///
- /// unsafe {
- /// assert_eq!("world", s.slice_unchecked(7, 12));
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
- core_str::StrExt::slice_unchecked(self, begin, end)
- }
-
- /// Creates a string slice from another string slice, bypassing safety
- /// checks.
- /// This is generally not recommended, use with caution! For a safe
- /// alternative see [`str`] and [`IndexMut`].
- ///
- /// [`str`]: primitive.str.html
- /// [`IndexMut`]: ops/trait.IndexMut.html
- ///
- /// This new slice goes from `begin` to `end`, including `begin` but
- /// excluding `end`.
- ///
- /// To get an immutable string slice instead, see the
- /// [`slice_unchecked`] method.
- ///
- /// [`slice_unchecked`]: #method.slice_unchecked
- ///
- /// # Safety
- ///
- /// Callers of this function are responsible that three preconditions are
- /// satisfied:
- ///
- /// * `begin` must come before `end`.
- /// * `begin` and `end` must be byte positions within the string slice.
- /// * `begin` and `end` must lie on UTF-8 sequence boundaries.
- #[stable(feature = "str_slice_mut", since = "1.5.0")]
- #[inline]
- pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
- core_str::StrExt::slice_mut_unchecked(self, begin, end)
- }
-
- /// Divide one string slice into two at an index.
- ///
- /// The argument, `mid`, should be a byte offset from the start of the
- /// string. It must also be on the boundary of a UTF-8 code point.
- ///
- /// The two slices returned go from the start of the string slice to `mid`,
- /// and from `mid` to the end of the string slice.
- ///
- /// To get mutable string slices instead, see the [`split_at_mut`]
- /// method.
- ///
- /// [`split_at_mut`]: #method.split_at_mut
- ///
- /// # Panics
- ///
- /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is
- /// beyond the last code point of the string slice.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let s = "Per Martin-Löf";
- ///
- /// let (first, last) = s.split_at(3);
- ///
- /// assert_eq!("Per", first);
- /// assert_eq!(" Martin-Löf", last);
- /// ```
- #[inline]
- #[stable(feature = "str_split_at", since = "1.4.0")]
- pub fn split_at(&self, mid: usize) -> (&str, &str) {
- core_str::StrExt::split_at(self, mid)
- }
-
- /// Divide one mutable string slice into two at an index.
- ///
- /// The argument, `mid`, should be a byte offset from the start of the
- /// string. It must also be on the boundary of a UTF-8 code point.
- ///
- /// The two slices returned go from the start of the string slice to `mid`,
- /// and from `mid` to the end of the string slice.
- ///
- /// To get immutable string slices instead, see the [`split_at`] method.
- ///
- /// [`split_at`]: #method.split_at
- ///
- /// # Panics
- ///
- /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is
- /// beyond the last code point of the string slice.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let mut s = "Per Martin-Löf".to_string();
- /// {
- /// let (first, last) = s.split_at_mut(3);
- /// first.make_ascii_uppercase();
- /// assert_eq!("PER", first);
- /// assert_eq!(" Martin-Löf", last);
- /// }
- /// assert_eq!("PER Martin-Löf", s);
- /// ```
- #[inline]
- #[stable(feature = "str_split_at", since = "1.4.0")]
- pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
- core_str::StrExt::split_at_mut(self, mid)
- }
-
- /// Returns an iterator over the [`char`]s of a string slice.
- ///
- /// As a string slice consists of valid UTF-8, we can iterate through a
- /// string slice by [`char`]. This method returns such an iterator.
- ///
- /// It's important to remember that [`char`] represents a Unicode Scalar
- /// Value, and may not match your idea of what a 'character' is. Iteration
- /// over grapheme clusters may be what you actually want.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let word = "goodbye";
- ///
- /// let count = word.chars().count();
- /// assert_eq!(7, count);
- ///
- /// let mut chars = word.chars();
- ///
- /// assert_eq!(Some('g'), chars.next());
- /// assert_eq!(Some('o'), chars.next());
- /// assert_eq!(Some('o'), chars.next());
- /// assert_eq!(Some('d'), chars.next());
- /// assert_eq!(Some('b'), chars.next());
- /// assert_eq!(Some('y'), chars.next());
- /// assert_eq!(Some('e'), chars.next());
- ///
- /// assert_eq!(None, chars.next());
- /// ```
- ///
- /// Remember, [`char`]s may not match your human intuition about characters:
- ///
- /// ```
- /// let y = "y̆";
- ///
- /// let mut chars = y.chars();
- ///
- /// assert_eq!(Some('y'), chars.next()); // not 'y̆'
- /// assert_eq!(Some('\u{0306}'), chars.next());
- ///
- /// assert_eq!(None, chars.next());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn chars(&self) -> Chars {
- core_str::StrExt::chars(self)
- }
- /// Returns an iterator over the [`char`]s of a string slice, and their
- /// positions.
- ///
- /// As a string slice consists of valid UTF-8, we can iterate through a
- /// string slice by [`char`]. This method returns an iterator of both
- /// these [`char`]s, as well as their byte positions.
- ///
- /// The iterator yields tuples. The position is first, the [`char`] is
- /// second.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let word = "goodbye";
- ///
- /// let count = word.char_indices().count();
- /// assert_eq!(7, count);
- ///
- /// let mut char_indices = word.char_indices();
- ///
- /// assert_eq!(Some((0, 'g')), char_indices.next());
- /// assert_eq!(Some((1, 'o')), char_indices.next());
- /// assert_eq!(Some((2, 'o')), char_indices.next());
- /// assert_eq!(Some((3, 'd')), char_indices.next());
- /// assert_eq!(Some((4, 'b')), char_indices.next());
- /// assert_eq!(Some((5, 'y')), char_indices.next());
- /// assert_eq!(Some((6, 'e')), char_indices.next());
- ///
- /// assert_eq!(None, char_indices.next());
- /// ```
- ///
- /// Remember, [`char`]s may not match your human intuition about characters:
- ///
- /// ```
- /// let yes = "y̆es";
- ///
- /// let mut char_indices = yes.char_indices();
- ///
- /// assert_eq!(Some((0, 'y')), char_indices.next()); // not (0, 'y̆')
- /// assert_eq!(Some((1, '\u{0306}')), char_indices.next());
- ///
- /// // note the 3 here - the last character took up two bytes
- /// assert_eq!(Some((3, 'e')), char_indices.next());
- /// assert_eq!(Some((4, 's')), char_indices.next());
- ///
- /// assert_eq!(None, char_indices.next());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn char_indices(&self) -> CharIndices {
- core_str::StrExt::char_indices(self)
- }
-
- /// An iterator over the bytes of a string slice.
- ///
- /// As a string slice consists of a sequence of bytes, we can iterate
- /// through a string slice by byte. This method returns such an iterator.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let mut bytes = "bors".bytes();
- ///
- /// assert_eq!(Some(b'b'), bytes.next());
- /// assert_eq!(Some(b'o'), bytes.next());
- /// assert_eq!(Some(b'r'), bytes.next());
- /// assert_eq!(Some(b's'), bytes.next());
- ///
- /// assert_eq!(None, bytes.next());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn bytes(&self) -> Bytes {
- core_str::StrExt::bytes(self)
- }
-
- /// Split a string slice by whitespace.
- ///
- /// The iterator returned will return string slices that are sub-slices of
- /// the original string slice, separated by any amount of whitespace.
- ///
- /// 'Whitespace' is defined according to the terms of the Unicode Derived
- /// Core Property `White_Space`.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let mut iter = "A few words".split_whitespace();
- ///
- /// assert_eq!(Some("A"), iter.next());
- /// assert_eq!(Some("few"), iter.next());
- /// assert_eq!(Some("words"), iter.next());
- ///
- /// assert_eq!(None, iter.next());
- /// ```
- ///
- /// All kinds of whitespace are considered:
- ///
- /// ```
- /// let mut iter = " Mary had\ta\u{2009}little \n\t lamb".split_whitespace();
- /// assert_eq!(Some("Mary"), iter.next());
- /// assert_eq!(Some("had"), iter.next());
- /// assert_eq!(Some("a"), iter.next());
- /// assert_eq!(Some("little"), iter.next());
- /// assert_eq!(Some("lamb"), iter.next());
- ///
- /// assert_eq!(None, iter.next());
- /// ```
- #[stable(feature = "split_whitespace", since = "1.1.0")]
- #[inline]
- pub fn split_whitespace(&self) -> SplitWhitespace {
- StrExt::split_whitespace(self)
- }
-
- /// An iterator over the lines of a string, as string slices.
- ///
- /// Lines are ended with either a newline (`\n`) or a carriage return with
- /// a line feed (`\r\n`).
- ///
- /// The final line ending is optional.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let text = "foo\r\nbar\n\nbaz\n";
- /// let mut lines = text.lines();
- ///
- /// assert_eq!(Some("foo"), lines.next());
- /// assert_eq!(Some("bar"), lines.next());
- /// assert_eq!(Some(""), lines.next());
- /// assert_eq!(Some("baz"), lines.next());
- ///
- /// assert_eq!(None, lines.next());
- /// ```
- ///
- /// The final line ending isn't required:
- ///
- /// ```
- /// let text = "foo\nbar\n\r\nbaz";
- /// let mut lines = text.lines();
- ///
- /// assert_eq!(Some("foo"), lines.next());
- /// assert_eq!(Some("bar"), lines.next());
- /// assert_eq!(Some(""), lines.next());
- /// assert_eq!(Some("baz"), lines.next());
- ///
- /// assert_eq!(None, lines.next());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn lines(&self) -> Lines {
- core_str::StrExt::lines(self)
- }
-
- /// An iterator over the lines of a string.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(since = "1.4.0", reason = "use lines() instead now")]
- #[inline]
- #[allow(deprecated)]
- pub fn lines_any(&self) -> LinesAny {
- core_str::StrExt::lines_any(self)
- }
-
- /// Returns an iterator of `u16` over the string encoded as UTF-16.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let text = "Zażółć gęślą jaźń";
- ///
- /// let utf8_len = text.len();
- /// let utf16_len = text.encode_utf16().count();
- ///
- /// assert!(utf16_len <= utf8_len);
- /// ```
- #[stable(feature = "encode_utf16", since = "1.8.0")]
- pub fn encode_utf16(&self) -> EncodeUtf16 {
- EncodeUtf16 { chars: self[..].chars(), extra: 0 }
- }
-
- /// Returns `true` if the given pattern matches a sub-slice of
- /// this string slice.
- ///
- /// Returns `false` if it does not.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let bananas = "bananas";
- ///
- /// assert!(bananas.contains("nana"));
- /// assert!(!bananas.contains("apples"));
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
- core_str::StrExt::contains(self, pat)
- }
-
- /// Returns `true` if the given pattern matches a prefix of this
- /// string slice.
- ///
- /// Returns `false` if it does not.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let bananas = "bananas";
- ///
- /// assert!(bananas.starts_with("bana"));
- /// assert!(!bananas.starts_with("nana"));
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
- core_str::StrExt::starts_with(self, pat)
- }
-
- /// Returns `true` if the given pattern matches a suffix of this
- /// string slice.
- ///
- /// Returns `false` if it does not.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let bananas = "bananas";
- ///
- /// assert!(bananas.ends_with("anas"));
- /// assert!(!bananas.ends_with("nana"));
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::ends_with(self, pat)
- }
-
- /// Returns the byte index of the first character of this string slice that
- /// matches the pattern.
- ///
- /// Returns [`None`] if the pattern doesn't match.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines if
- /// a character matches.
- ///
- /// [`char`]: primitive.char.html
- /// [`None`]: option/enum.Option.html#variant.None
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- ///
- /// assert_eq!(s.find('L'), Some(0));
- /// assert_eq!(s.find('é'), Some(14));
- /// assert_eq!(s.find("Léopard"), Some(13));
- /// ```
- ///
- /// More complex patterns using point-free style and closures:
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- ///
- /// assert_eq!(s.find(char::is_whitespace), Some(5));
- /// assert_eq!(s.find(char::is_lowercase), Some(1));
- /// assert_eq!(s.find(|c: char| c.is_whitespace() || c.is_lowercase()), Some(1));
- /// assert_eq!(s.find(|c: char| (c < 'o') && (c > 'a')), Some(4));
- /// ```
- ///
- /// Not finding the pattern:
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- /// let x: &[_] = &['1', '2'];
- ///
- /// assert_eq!(s.find(x), None);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
- core_str::StrExt::find(self, pat)
- }
-
- /// Returns the byte index of the last character of this string slice that
- /// matches the pattern.
- ///
- /// Returns [`None`] if the pattern doesn't match.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines if
- /// a character matches.
- ///
- /// [`char`]: primitive.char.html
- /// [`None`]: option/enum.Option.html#variant.None
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- ///
- /// assert_eq!(s.rfind('L'), Some(13));
- /// assert_eq!(s.rfind('é'), Some(14));
- /// ```
- ///
- /// More complex patterns with closures:
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- ///
- /// assert_eq!(s.rfind(char::is_whitespace), Some(12));
- /// assert_eq!(s.rfind(char::is_lowercase), Some(20));
- /// ```
- ///
- /// Not finding the pattern:
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- /// let x: &[_] = &['1', '2'];
- ///
- /// assert_eq!(s.rfind(x), None);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rfind(self, pat)
- }
-
- /// An iterator over substrings of this string slice, separated by
- /// characters matched by a pattern.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines the
- /// split.
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
- /// allows a reverse search and forward/reverse search yields the same
- /// elements. This is true for, eg, [`char`] but not for `&str`.
- ///
- /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
- ///
- /// If the pattern allows a reverse search but its results might differ
- /// from a forward search, the [`rsplit`] method can be used.
- ///
- /// [`char`]: primitive.char.html
- /// [`rsplit`]: #method.rsplit
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```
- /// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect();
- /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
- ///
- /// let v: Vec<&str> = "".split('X').collect();
- /// assert_eq!(v, [""]);
- ///
- /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect();
- /// assert_eq!(v, ["lion", "", "tiger", "leopard"]);
- ///
- /// let v: Vec<&str> = "lion::tiger::leopard".split("::").collect();
- /// assert_eq!(v, ["lion", "tiger", "leopard"]);
- ///
- /// let v: Vec<&str> = "abc1def2ghi".split(char::is_numeric).collect();
- /// assert_eq!(v, ["abc", "def", "ghi"]);
- ///
- /// let v: Vec<&str> = "lionXtigerXleopard".split(char::is_uppercase).collect();
- /// assert_eq!(v, ["lion", "tiger", "leopard"]);
- /// ```
- ///
- /// A more complex pattern, using a closure:
- ///
- /// ```
- /// let v: Vec<&str> = "abc1defXghi".split(|c| c == '1' || c == 'X').collect();
- /// assert_eq!(v, ["abc", "def", "ghi"]);
- /// ```
- ///
- /// If a string contains multiple contiguous separators, you will end up
- /// with empty strings in the output:
- ///
- /// ```
- /// let x = "||||a||b|c".to_string();
- /// let d: Vec<_> = x.split('|').collect();
- ///
- /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]);
- /// ```
- ///
- /// Contiguous separators are separated by the empty string.
- ///
- /// ```
- /// let x = "(///)".to_string();
- /// let d: Vec<_> = x.split('/').collect();
- ///
- /// assert_eq!(d, &["(", "", "", ")"]);
- /// ```
- ///
- /// Separators at the start or end of a string are neighbored
- /// by empty strings.
- ///
- /// ```
- /// let d: Vec<_> = "010".split("0").collect();
- /// assert_eq!(d, &["", "1", ""]);
- /// ```
- ///
- /// When the empty string is used as a separator, it separates
- /// every character in the string, along with the beginning
- /// and end of the string.
- ///
- /// ```
- /// let f: Vec<_> = "rust".split("").collect();
- /// assert_eq!(f, &["", "r", "u", "s", "t", ""]);
- /// ```
- ///
- /// Contiguous separators can lead to possibly surprising behavior
- /// when whitespace is used as the separator. This code is correct:
- ///
- /// ```
- /// let x = " a b c".to_string();
- /// let d: Vec<_> = x.split(' ').collect();
- ///
- /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]);
- /// ```
- ///
- /// It does _not_ give you:
- ///
- /// ```,ignore
- /// assert_eq!(d, &["a", "b", "c"]);
- /// ```
- ///
- /// Use [`split_whitespace`] for this behavior.
- ///
- /// [`split_whitespace`]: #method.split_whitespace
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
- core_str::StrExt::split(self, pat)
- }
-
- /// An iterator over substrings of the given string slice, separated by
- /// characters matched by a pattern and yielded in reverse order.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines the
- /// split.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator requires that the pattern supports a reverse
- /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
- /// search yields the same elements.
- ///
- /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
- ///
- /// For iterating from the front, the [`split`] method can be used.
- ///
- /// [`split`]: #method.split
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```
- /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect();
- /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]);
- ///
- /// let v: Vec<&str> = "".rsplit('X').collect();
- /// assert_eq!(v, [""]);
- ///
- /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect();
- /// assert_eq!(v, ["leopard", "tiger", "", "lion"]);
- ///
- /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect();
- /// assert_eq!(v, ["leopard", "tiger", "lion"]);
- /// ```
- ///
- /// A more complex pattern, using a closure:
- ///
- /// ```
- /// let v: Vec<&str> = "abc1defXghi".rsplit(|c| c == '1' || c == 'X').collect();
- /// assert_eq!(v, ["ghi", "def", "abc"]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rsplit(self, pat)
- }
-
- /// An iterator over substrings of the given string slice, separated by
- /// characters matched by a pattern.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines the
- /// split.
- ///
- /// Equivalent to [`split`], except that the trailing substring
- /// is skipped if empty.
- ///
- /// [`split`]: #method.split
- ///
- /// This method can be used for string data that is _terminated_,
- /// rather than _separated_ by a pattern.
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
- /// allows a reverse search and forward/reverse search yields the same
- /// elements. This is true for, eg, [`char`] but not for `&str`.
- ///
- /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
- /// [`char`]: primitive.char.html
- ///
- /// If the pattern allows a reverse search but its results might differ
- /// from a forward search, the [`rsplit_terminator`] method can be used.
- ///
- /// [`rsplit_terminator`]: #method.rsplit_terminator
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let v: Vec<&str> = "A.B.".split_terminator('.').collect();
- /// assert_eq!(v, ["A", "B"]);
- ///
- /// let v: Vec<&str> = "A..B..".split_terminator(".").collect();
- /// assert_eq!(v, ["A", "", "B", ""]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> {
- core_str::StrExt::split_terminator(self, pat)
- }
-
- /// An iterator over substrings of `self`, separated by characters
- /// matched by a pattern and yielded in reverse order.
- ///
- /// The pattern can be a simple `&str`, [`char`], or a closure that
- /// determines the split.
- /// Additional libraries might provide more complex patterns like
- /// regular expressions.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// Equivalent to [`split`], except that the trailing substring is
- /// skipped if empty.
- ///
- /// [`split`]: #method.split
- ///
- /// This method can be used for string data that is _terminated_,
- /// rather than _separated_ by a pattern.
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator requires that the pattern supports a
- /// reverse search, and it will be double ended if a forward/reverse
- /// search yields the same elements.
- ///
- /// For iterating from the front, the [`split_terminator`] method can be
- /// used.
- ///
- /// [`split_terminator`]: #method.split_terminator
- ///
- /// # Examples
- ///
- /// ```
- /// let v: Vec<&str> = "A.B.".rsplit_terminator('.').collect();
- /// assert_eq!(v, ["B", "A"]);
- ///
- /// let v: Vec<&str> = "A..B..".rsplit_terminator(".").collect();
- /// assert_eq!(v, ["", "B", "", "A"]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rsplit_terminator(self, pat)
- }
-
- /// An iterator over substrings of the given string slice, separated by a
- /// pattern, restricted to returning at most `n` items.
- ///
- /// If `n` substrings are returned, the last substring (the `n`th substring)
- /// will contain the remainder of the string.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines the
- /// split.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator will not be double ended, because it is
- /// not efficient to support.
- ///
- /// If the pattern allows a reverse search, the [`rsplitn`] method can be
- /// used.
- ///
- /// [`rsplitn`]: #method.rsplitn
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```
- /// let v: Vec<&str> = "Mary had a little lambda".splitn(3, ' ').collect();
- /// assert_eq!(v, ["Mary", "had", "a little lambda"]);
- ///
- /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(3, "X").collect();
- /// assert_eq!(v, ["lion", "", "tigerXleopard"]);
- ///
- /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect();
- /// assert_eq!(v, ["abcXdef"]);
- ///
- /// let v: Vec<&str> = "".splitn(1, 'X').collect();
- /// assert_eq!(v, [""]);
- /// ```
- ///
- /// A more complex pattern, using a closure:
- ///
- /// ```
- /// let v: Vec<&str> = "abc1defXghi".splitn(2, |c| c == '1' || c == 'X').collect();
- /// assert_eq!(v, ["abc", "defXghi"]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> {
- core_str::StrExt::splitn(self, n, pat)
- }
-
- /// An iterator over substrings of this string slice, separated by a
- /// pattern, starting from the end of the string, restricted to returning
- /// at most `n` items.
- ///
- /// If `n` substrings are returned, the last substring (the `n`th substring)
- /// will contain the remainder of the string.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that
- /// determines the split.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator will not be double ended, because it is not
- /// efficient to support.
- ///
- /// For splitting from the front, the [`splitn`] method can be used.
- ///
- /// [`splitn`]: #method.splitn
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```
- /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect();
- /// assert_eq!(v, ["lamb", "little", "Mary had a"]);
- ///
- /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(3, 'X').collect();
- /// assert_eq!(v, ["leopard", "tiger", "lionX"]);
- ///
- /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect();
- /// assert_eq!(v, ["leopard", "lion::tiger"]);
- /// ```
- ///
- /// A more complex pattern, using a closure:
- ///
- /// ```
- /// let v: Vec<&str> = "abc1defXghi".rsplitn(2, |c| c == '1' || c == 'X').collect();
- /// assert_eq!(v, ["ghi", "abc1def"]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rsplitn(self, n, pat)
- }
-
- /// An iterator over the disjoint matches of a pattern within the given string
- /// slice.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that
- /// determines if a character matches.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
- /// allows a reverse search and forward/reverse search yields the same
- /// elements. This is true for, eg, [`char`] but not for `&str`.
- ///
- /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
- /// [`char`]: primitive.char.html
- ///
- /// If the pattern allows a reverse search but its results might differ
- /// from a forward search, the [`rmatches`] method can be used.
- ///
- /// [`rmatches`]: #method.rmatches
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect();
- /// assert_eq!(v, ["abc", "abc", "abc"]);
- ///
- /// let v: Vec<&str> = "1abc2abc3".matches(char::is_numeric).collect();
- /// assert_eq!(v, ["1", "2", "3"]);
- /// ```
- #[stable(feature = "str_matches", since = "1.2.0")]
- #[inline]
- pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
- core_str::StrExt::matches(self, pat)
- }
-
- /// An iterator over the disjoint matches of a pattern within this string slice,
- /// yielded in reverse order.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines if
- /// a character matches.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator requires that the pattern supports a reverse
- /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
- /// search yields the same elements.
- ///
- /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
- ///
- /// For iterating from the front, the [`matches`] method can be used.
- ///
- /// [`matches`]: #method.matches
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let v: Vec<&str> = "abcXXXabcYYYabc".rmatches("abc").collect();
- /// assert_eq!(v, ["abc", "abc", "abc"]);
- ///
- /// let v: Vec<&str> = "1abc2abc3".rmatches(char::is_numeric).collect();
- /// assert_eq!(v, ["3", "2", "1"]);
- /// ```
- #[stable(feature = "str_matches", since = "1.2.0")]
- #[inline]
- pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rmatches(self, pat)
- }
+ return String::new();
+ }
- /// An iterator over the disjoint matches of a pattern within this string
- /// slice as well as the index that the match starts at.
- ///
- /// For matches of `pat` within `self` that overlap, only the indices
- /// corresponding to the first match are returned.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines
- /// if a character matches.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
- /// allows a reverse search and forward/reverse search yields the same
- /// elements. This is true for, eg, [`char`] but not for `&str`.
- ///
- /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
- ///
- /// If the pattern allows a reverse search but its results might differ
- /// from a forward search, the [`rmatch_indices`] method can be used.
- ///
- /// [`rmatch_indices`]: #method.rmatch_indices
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect();
- /// assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]);
- ///
- /// let v: Vec<_> = "1abcabc2".match_indices("abc").collect();
- /// assert_eq!(v, [(1, "abc"), (4, "abc")]);
- ///
- /// let v: Vec<_> = "ababa".match_indices("aba").collect();
- /// assert_eq!(v, [(0, "aba")]); // only the first `aba`
- /// ```
- #[stable(feature = "str_match_indices", since = "1.5.0")]
- #[inline]
- pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
- core_str::StrExt::match_indices(self, pat)
- }
+ // `len` calculation may overflow but push_str will check boundaries
+ let len = self.iter().map(|s| s.borrow().len()).sum();
+ let mut result = String::with_capacity(len);
- /// An iterator over the disjoint matches of a pattern within `self`,
- /// yielded in reverse order along with the index of the match.
- ///
- /// For matches of `pat` within `self` that overlap, only the indices
- /// corresponding to the last match are returned.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines if a
- /// character matches.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator requires that the pattern supports a reverse
- /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
- /// search yields the same elements.
- ///
- /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
- ///
- /// For iterating from the front, the [`match_indices`] method can be used.
- ///
- /// [`match_indices`]: #method.match_indices
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_indices("abc").collect();
- /// assert_eq!(v, [(12, "abc"), (6, "abc"), (0, "abc")]);
- ///
- /// let v: Vec<_> = "1abcabc2".rmatch_indices("abc").collect();
- /// assert_eq!(v, [(4, "abc"), (1, "abc")]);
- ///
- /// let v: Vec<_> = "ababa".rmatch_indices("aba").collect();
- /// assert_eq!(v, [(2, "aba")]); // only the last `aba`
- /// ```
- #[stable(feature = "str_match_indices", since = "1.5.0")]
- #[inline]
- pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rmatch_indices(self, pat)
- }
+ for s in self {
+ result.push_str(s.borrow())
+ }
- /// Returns a string slice with leading and trailing whitespace removed.
- ///
- /// 'Whitespace' is defined according to the terms of the Unicode Derived
- /// Core Property `White_Space`.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let s = " Hello\tworld\t";
- ///
- /// assert_eq!("Hello\tworld", s.trim());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim(&self) -> &str {
- StrExt::trim(self)
+ result
}
- /// Returns a string slice with leading whitespace removed.
- ///
- /// 'Whitespace' is defined according to the terms of the Unicode Derived
- /// Core Property `White_Space`.
- ///
- /// # Text directionality
- ///
- /// A string is a sequence of bytes. 'Left' in this context means the first
- /// position of that byte string; for a language like Arabic or Hebrew
- /// which are 'right to left' rather than 'left to right', this will be
- /// the _right_ side, not the left.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let s = " Hello\tworld\t";
- ///
- /// assert_eq!("Hello\tworld\t", s.trim_left());
- /// ```
- ///
- /// Directionality:
- ///
- /// ```
- /// let s = " English";
- /// assert!(Some('E') == s.trim_left().chars().next());
- ///
- /// let s = " עברית";
- /// assert!(Some('ע') == s.trim_left().chars().next());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_left(&self) -> &str {
- StrExt::trim_left(self)
- }
+ fn join(&self, sep: &str) -> String {
+ if self.is_empty() {
+ return String::new();
+ }
- /// Returns a string slice with trailing whitespace removed.
- ///
- /// 'Whitespace' is defined according to the terms of the Unicode Derived
- /// Core Property `White_Space`.
- ///
- /// # Text directionality
- ///
- /// A string is a sequence of bytes. 'Right' in this context means the last
- /// position of that byte string; for a language like Arabic or Hebrew
- /// which are 'right to left' rather than 'left to right', this will be
- /// the _left_ side, not the right.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let s = " Hello\tworld\t";
- ///
- /// assert_eq!(" Hello\tworld", s.trim_right());
- /// ```
- ///
- /// Directionality:
- ///
- /// ```
- /// let s = "English ";
- /// assert!(Some('h') == s.trim_right().chars().rev().next());
- ///
- /// let s = "עברית ";
- /// assert!(Some('ת') == s.trim_right().chars().rev().next());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_right(&self) -> &str {
- StrExt::trim_right(self)
+ // concat is faster
+ if sep.is_empty() {
+ return self.concat();
+ }
+
+ // this is wrong without the guarantee that `self` is non-empty
+ // `len` calculation may overflow but push_str but will check boundaries
+ let len = sep.len() * (self.len() - 1) +
+ self.iter().map(|s| s.borrow().len()).sum::<usize>();
+ let mut result = String::with_capacity(len);
+ let mut first = true;
+
+ for s in self {
+ if first {
+ first = false;
+ } else {
+ result.push_str(sep);
+ }
+ result.push_str(s.borrow());
+ }
+ result
}
- /// Returns a string slice with all prefixes and suffixes that match a
- /// pattern repeatedly removed.
- ///
- /// The pattern can be a [`char`] or a closure that determines if a
- /// character matches.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```
- /// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar");
- /// assert_eq!("123foo1bar123".trim_matches(char::is_numeric), "foo1bar");
- ///
- /// let x: &[_] = &['1', '2'];
- /// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar");
- /// ```
- ///
- /// A more complex pattern, using a closure:
- ///
- /// ```
- /// assert_eq!("1foo1barXX".trim_matches(|c| c == '1' || c == 'X'), "foo1bar");
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
- where P::Searcher: DoubleEndedSearcher<'a>
- {
- core_str::StrExt::trim_matches(self, pat)
+ fn connect(&self, sep: &str) -> String {
+ self.join(sep)
}
+}
- /// Returns a string slice with all prefixes that match a pattern
- /// repeatedly removed.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines if
- /// a character matches.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Text directionality
- ///
- /// A string is a sequence of bytes. 'Left' in this context means the first
- /// position of that byte string; for a language like Arabic or Hebrew
- /// which are 'right to left' rather than 'left to right', this will be
- /// the _right_ side, not the left.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11");
- /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123");
- ///
- /// let x: &[_] = &['1', '2'];
- /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
- core_str::StrExt::trim_left_matches(self, pat)
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Borrow<str> for String {
+ #[inline]
+ fn borrow(&self) -> &str {
+ &self[..]
}
+}
- /// Returns a string slice with all suffixes that match a pattern
- /// repeatedly removed.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that
- /// determines if a character matches.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Text directionality
- ///
- /// A string is a sequence of bytes. 'Right' in this context means the last
- /// position of that byte string; for a language like Arabic or Hebrew
- /// which are 'right to left' rather than 'left to right', this will be
- /// the _left_ side, not the right.
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```
- /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar");
- /// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar");
- ///
- /// let x: &[_] = &['1', '2'];
- /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar");
- /// ```
- ///
- /// A more complex pattern, using a closure:
- ///
- /// ```
- /// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo");
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::trim_right_matches(self, pat)
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToOwned for str {
+ type Owned = String;
+ fn to_owned(&self) -> String {
+ unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) }
}
- /// Parses this string slice into another type.
- ///
- /// Because `parse` is so general, it can cause problems with type
- /// inference. As such, `parse` is one of the few times you'll see
- /// the syntax affectionately known as the 'turbofish': `::<>`. This
- /// helps the inference algorithm understand specifically which type
- /// you're trying to parse into.
- ///
- /// `parse` can parse any type that implements the [`FromStr`] trait.
- ///
- /// [`FromStr`]: str/trait.FromStr.html
- ///
- /// # Errors
- ///
- /// Will return [`Err`] if it's not possible to parse this string slice into
- /// the desired type.
- ///
- /// [`Err`]: str/trait.FromStr.html#associatedtype.Err
- ///
- /// # Examples
- ///
- /// Basic usage
- ///
- /// ```
- /// let four: u32 = "4".parse().unwrap();
- ///
- /// assert_eq!(4, four);
- /// ```
- ///
- /// Using the 'turbofish' instead of annotating `four`:
- ///
- /// ```
- /// let four = "4".parse::<u32>();
- ///
- /// assert_eq!(Ok(4), four);
- /// ```
- ///
- /// Failing to parse:
- ///
- /// ```
- /// let nope = "j".parse::<u32>();
- ///
- /// assert!(nope.is_err());
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
- core_str::StrExt::parse(self)
+ fn clone_into(&self, target: &mut String) {
+ let mut b = mem::replace(target, String::new()).into_bytes();
+ self.as_bytes().clone_into(&mut b);
+ *target = unsafe { String::from_utf8_unchecked(b) }
}
+}
+
+/// Methods for string slices.
+#[cfg_attr(stage0, lang = "str")]
+#[cfg_attr(not(stage0), lang = "str_alloc")]
+#[cfg(not(test))]
+impl str {
+ #[cfg(stage0)]
+ str_core_methods!();
/// Converts a `Box<str>` into a `Box<[u8]>` without copying or allocating.
///
/// ```
#[stable(feature = "repeat_str", since = "1.16.0")]
pub fn repeat(&self, n: usize) -> String {
- if n == 0 {
- return String::new();
- }
-
- // If `n` is larger than zero, it can be split as
- // `n = 2^expn + rem (2^expn > rem, expn >= 0, rem >= 0)`.
- // `2^expn` is the number represented by the leftmost '1' bit of `n`,
- // and `rem` is the remaining part of `n`.
-
- // Using `Vec` to access `set_len()`.
- let mut buf = Vec::with_capacity(self.len() * n);
-
- // `2^expn` repetition is done by doubling `buf` `expn`-times.
- buf.extend(self.as_bytes());
- {
- let mut m = n >> 1;
- // If `m > 0`, there are remaining bits up to the leftmost '1'.
- while m > 0 {
- // `buf.extend(buf)`:
- unsafe {
- ptr::copy_nonoverlapping(
- buf.as_ptr(),
- (buf.as_mut_ptr() as *mut u8).add(buf.len()),
- buf.len(),
- );
- // `buf` has capacity of `self.len() * n`.
- let buf_len = buf.len();
- buf.set_len(buf_len * 2);
- }
-
- m >>= 1;
- }
- }
-
- // `rem` (`= n - 2^expn`) repetition is done by copying
- // first `rem` repetitions from `buf` itself.
- let rem_len = self.len() * n - buf.len(); // `self.len() * rem`
- if rem_len > 0 {
- // `buf.extend(buf[0 .. rem_len])`:
- unsafe {
- // This is non-overlapping since `2^expn > rem`.
- ptr::copy_nonoverlapping(
- buf.as_ptr(),
- (buf.as_mut_ptr() as *mut u8).add(buf.len()),
- rem_len,
- );
- // `buf.len() + rem_len` equals to `buf.capacity()` (`= self.len() * n`).
- let buf_cap = buf.capacity();
- buf.set_len(buf_cap);
- }
- }
-
- unsafe { String::from_utf8_unchecked(buf) }
- }
-
- /// Checks if all characters in this string are within the ASCII range.
- ///
- /// # Examples
- ///
- /// ```
- /// let ascii = "hello!\n";
- /// let non_ascii = "Grüße, Jürgen ❤";
- ///
- /// assert!(ascii.is_ascii());
- /// assert!(!non_ascii.is_ascii());
- /// ```
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- #[inline]
- pub fn is_ascii(&self) -> bool {
- // We can treat each byte as character here: all multibyte characters
- // start with a byte that is not in the ascii range, so we will stop
- // there already.
- self.bytes().all(|b| b.is_ascii())
+ unsafe { String::from_utf8_unchecked(self.as_bytes().repeat(n)) }
}
/// Returns a copy of this string where each character is mapped to its
// make_ascii_lowercase() preserves the UTF-8 invariant.
unsafe { String::from_utf8_unchecked(bytes) }
}
-
- /// Checks that two strings are an ASCII case-insensitive match.
- ///
- /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
- /// but without allocating and copying temporaries.
- ///
- /// # Examples
- ///
- /// ```
- /// assert!("Ferris".eq_ignore_ascii_case("FERRIS"));
- /// assert!("Ferrös".eq_ignore_ascii_case("FERRöS"));
- /// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS"));
- /// ```
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- #[inline]
- pub fn eq_ignore_ascii_case(&self, other: &str) -> bool {
- self.as_bytes().eq_ignore_ascii_case(other.as_bytes())
- }
-
- /// Converts this string to its ASCII upper case equivalent in-place.
- ///
- /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
- /// but non-ASCII letters are unchanged.
- ///
- /// To return a new uppercased value without modifying the existing one, use
- /// [`to_ascii_uppercase`].
- ///
- /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- pub fn make_ascii_uppercase(&mut self) {
- let me = unsafe { self.as_bytes_mut() };
- me.make_ascii_uppercase()
- }
-
- /// Converts this string to its ASCII lower case equivalent in-place.
- ///
- /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
- /// but non-ASCII letters are unchanged.
- ///
- /// To return a new lowercased value without modifying the existing one, use
- /// [`to_ascii_lowercase`].
- ///
- /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- pub fn make_ascii_lowercase(&mut self) {
- let me = unsafe { self.as_bytes_mut() };
- me.make_ascii_lowercase()
- }
}
/// Converts a boxed slice of bytes to a boxed string slice without checking
}
}
+#[test]
+fn test_str_slice_rangetoinclusive_ok() {
+ let s = "abcαβγ";
+ assert_eq!(&s[..=2], "abc");
+ assert_eq!(&s[..=4], "abcα");
+}
+
+#[test]
+#[should_panic]
+fn test_str_slice_rangetoinclusive_notok() {
+ let s = "abcαβγ";
+ &s[..=3];
+}
+
+#[test]
+fn test_str_slicemut_rangetoinclusive_ok() {
+ let mut s = "abcαβγ".to_owned();
+ let s: &mut str = &mut s;
+ assert_eq!(&mut s[..=2], "abc");
+ assert_eq!(&mut s[..=4], "abcα");
+}
+
+#[test]
+#[should_panic]
+fn test_str_slicemut_rangetoinclusive_notok() {
+ let mut s = "abcαβγ".to_owned();
+ let s: &mut str = &mut s;
+ &mut s[..=3];
+}
+
#[test]
fn test_is_char_boundary() {
let s = "ศไทย中华Việt Nam β-release 🐱123";
use core::marker::PhantomData;
use core::mem;
#[cfg(not(test))]
+#[cfg(stage0)]
use core::num::Float;
use core::ops::Bound::{Excluded, Included, Unbounded};
use core::ops::{Index, IndexMut, RangeBounds};
doc = false
[dependencies]
-alloc_system = { path = "../liballoc_system" }
core = { path = "../libcore" }
libc = { path = "../rustc/libc_shim" }
compiler_builtins = { path = "../rustc/compiler_builtins_shim" }
reason = "this library is unlikely to be stabilized in its current \
form or name",
issue = "27783")]
-#![feature(alloc_system)]
+#![feature(core_intrinsics)]
#![feature(libc)]
#![feature(linkage)]
#![feature(staged_api)]
#![cfg_attr(not(dummy_jemalloc), feature(allocator_api))]
#![rustc_alloc_kind = "exe"]
-extern crate alloc_system;
extern crate libc;
#[cfg(not(dummy_jemalloc))]
pub use contents::*;
#[cfg(not(dummy_jemalloc))]
mod contents {
- use core::alloc::GlobalAlloc;
- use alloc_system::System;
use libc::{c_int, c_void, size_t};
// Note that the symbols here are prefixed by default on macOS and Windows (we
ptr
}
+ #[cfg(stage0)]
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rde_oom() -> ! {
- System.oom()
+ ::core::intrinsics::abort();
}
#[no_mangle]
new_size: usize) -> Result<NonNull<Opaque>, AllocErr> {
NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
}
-
- #[inline]
- fn oom(&mut self) -> ! {
- ::oom()
- }
}
#[cfg(stage0)]
new_size: usize) -> Result<NonNull<Opaque>, AllocErr> {
NonNull::new(GlobalAlloc::realloc(*self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
}
-
- #[inline]
- fn oom(&mut self) -> ! {
- ::oom()
- }
}
#[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))]
}
}
}
-
-#[inline]
-fn oom() -> ! {
- write_to_stderr("fatal runtime error: memory allocation failed");
- unsafe {
- ::core::intrinsics::abort();
- }
-}
-
-#[cfg(any(unix, target_os = "redox"))]
-#[inline]
-fn write_to_stderr(s: &str) {
- extern crate libc;
-
- unsafe {
- libc::write(libc::STDERR_FILENO,
- s.as_ptr() as *const libc::c_void,
- s.len());
- }
-}
-
-#[cfg(windows)]
-#[inline]
-fn write_to_stderr(s: &str) {
- use core::ptr;
-
- type LPVOID = *mut u8;
- type HANDLE = LPVOID;
- type DWORD = u32;
- type BOOL = i32;
- type LPDWORD = *mut DWORD;
- type LPOVERLAPPED = *mut u8;
-
- const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
-
- extern "system" {
- fn WriteFile(hFile: HANDLE,
- lpBuffer: LPVOID,
- nNumberOfBytesToWrite: DWORD,
- lpNumberOfBytesWritten: LPDWORD,
- lpOverlapped: LPOVERLAPPED)
- -> BOOL;
- fn GetStdHandle(which: DWORD) -> HANDLE;
- }
-
- unsafe {
- // WriteFile silently fails if it is passed an invalid
- // handle, so there is no need to check the result of
- // GetStdHandle.
- WriteFile(GetStdHandle(STD_ERROR_HANDLE),
- s.as_ptr() as LPVOID,
- s.len() as DWORD,
- ptr::null_mut(),
- ptr::null_mut());
- }
-}
-
-#[cfg(not(any(windows, unix, target_os = "redox")))]
-#[inline]
-fn write_to_stderr(_: &str) {}
/// requests have positive size. A caller to the `Alloc::alloc`
/// method must either ensure that conditions like this are met, or
/// use specific allocators with looser requirements.)
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Layout {
// size of the requested block of memory, measured in bytes.
size: usize,
}
new_ptr
}
-
- /// Aborts the thread or process, optionally performing
- /// cleanup or logging diagnostic information before panicking or
- /// aborting.
- ///
- /// `oom` is meant to be used by clients unable to cope with an
- /// unsatisfied allocation request, and wish to abandon
- /// computation rather than attempt to recover locally.
- fn oom(&self) -> ! {
- unsafe { ::intrinsics::abort() }
- }
}
/// An implementation of `Alloc` can allocate, reallocate, and
/// to allocate that block of memory.
unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout);
- /// Allocator-specific method for signaling an out-of-memory
- /// condition.
- ///
- /// `oom` aborts the thread or process, optionally performing
- /// cleanup or logging diagnostic information before panicking or
- /// aborting.
- ///
- /// `oom` is meant to be used by clients unable to cope with an
- /// unsatisfied allocation request, and wish to abandon
- /// computation rather than attempt to recover locally.
- ///
- /// Implementations of the `oom` method are discouraged from
- /// infinitely regressing in nested calls to `oom`. In
- /// practice this means implementors should eschew allocating,
- /// especially from `self` (directly or indirectly).
- ///
- /// Implementations of the allocation and reallocation methods
- /// (e.g. `alloc`, `alloc_one`, `realloc`) are discouraged from
- /// panicking (or aborting) in the event of memory exhaustion;
- /// instead they should return an appropriate error from the
- /// invoked method, and let the client decide whether to invoke
- /// this `oom` method in response.
- fn oom(&mut self) -> ! {
- unsafe { ::intrinsics::abort() }
- }
-
// == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS ==
// usable_size
}
/// The error type returned when a conversion from a slice to an array fails.
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
#[derive(Debug, Copy, Clone)]
pub struct TryFromSliceError(());
}
}
- #[stable(feature = "try_from", since = "1.26.0")]
+ #[unstable(feature = "try_from", issue = "33417")]
impl<'a, T> TryFrom<&'a [T]> for &'a [T; $N] {
type Error = TryFromSliceError;
}
}
- #[stable(feature = "try_from", since = "1.26.0")]
+ #[unstable(feature = "try_from", issue = "33417")]
impl<'a, T> TryFrom<&'a mut [T]> for &'a mut [T; $N] {
type Error = TryFromSliceError;
pub fn get(&self) -> T {
unsafe{ *self.value.get() }
}
+
+ /// Updates the contained value using a function and returns the new value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(cell_update)]
+ ///
+ /// use std::cell::Cell;
+ ///
+ /// let c = Cell::new(5);
+ /// let new = c.update(|x| x + 1);
+ ///
+ /// assert_eq!(new, 6);
+ /// assert_eq!(c.get(), 6);
+ /// ```
+ #[inline]
+ #[unstable(feature = "cell_update", issue = "50186")]
+ pub fn update<F>(&self, f: F) -> T
+ where
+ F: FnOnce(T) -> T,
+ {
+ let old = self.get();
+ let new = f(old);
+ self.set(new);
+ new
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
}
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl TryFrom<u32> for char {
type Error = CharTryFromError;
}
/// The error type returned when a conversion from u32 to char fails.
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CharTryFromError(());
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl fmt::Display for CharTryFromError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
"converted integer out of range for `char`".fmt(f)
/// An iterator over an iterator of bytes of the characters the bytes represent
/// as UTF-8
#[unstable(feature = "decode_utf8", issue = "33906")]
+#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
+ https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
#[derive(Clone, Debug)]
+#[allow(deprecated)]
pub struct DecodeUtf8<I: Iterator<Item = u8>>(::iter::Peekable<I>);
/// Decodes an `Iterator` of bytes as UTF-8.
#[unstable(feature = "decode_utf8", issue = "33906")]
+#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
+ https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
+#[allow(deprecated)]
#[inline]
pub fn decode_utf8<I: IntoIterator<Item = u8>>(i: I) -> DecodeUtf8<I::IntoIter> {
DecodeUtf8(i.into_iter().peekable())
/// `<DecodeUtf8 as Iterator>::next` returns this for an invalid input sequence.
#[unstable(feature = "decode_utf8", issue = "33906")]
+#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
+ https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
#[derive(PartialEq, Eq, Debug)]
+#[allow(deprecated)]
pub struct InvalidSequence(());
#[unstable(feature = "decode_utf8", issue = "33906")]
+#[allow(deprecated)]
impl<I: Iterator<Item = u8>> Iterator for DecodeUtf8<I> {
type Item = Result<char, InvalidSequence>;
#[inline]
}
#[unstable(feature = "decode_utf8", issue = "33906")]
+#[allow(deprecated)]
impl<I: FusedIterator<Item = u8>> FusedIterator for DecodeUtf8<I> {}
/// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s.
pub use self::convert::from_u32_unchecked;
#[stable(feature = "char_from_str", since = "1.20.0")]
pub use self::convert::ParseCharError;
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
pub use self::convert::CharTryFromError;
#[stable(feature = "decode_utf16", since = "1.9.0")]
pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error};
#[unstable(feature = "unicode_version", issue = "49726")]
pub use unicode::version::UnicodeVersion;
#[unstable(feature = "decode_utf8", issue = "33906")]
+#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
+ https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
+#[allow(deprecated)]
pub use self::decode::{decode_utf8, DecodeUtf8, InvalidSequence};
use fmt::{self, Write};
bool char
}
- #[stable(feature = "never_type", since = "1.26.0")]
+ #[unstable(feature = "never_type", issue = "35121")]
impl Clone for ! {
#[inline]
fn clone(&self) -> Self {
ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
- #[stable(feature = "never_type", since = "1.26.0")]
+ #[unstable(feature = "never_type", issue = "35121")]
impl PartialEq for ! {
fn eq(&self, _: &!) -> bool {
*self
}
}
- #[stable(feature = "never_type", since = "1.26.0")]
+ #[unstable(feature = "never_type", issue = "35121")]
impl Eq for ! {}
- #[stable(feature = "never_type", since = "1.26.0")]
+ #[unstable(feature = "never_type", issue = "35121")]
impl PartialOrd for ! {
fn partial_cmp(&self, _: &!) -> Option<Ordering> {
*self
}
}
- #[stable(feature = "never_type", since = "1.26.0")]
+ #[unstable(feature = "never_type", issue = "35121")]
impl Ord for ! {
fn cmp(&self, _: &!) -> Ordering {
*self
///
/// [`TryFrom`]: trait.TryFrom.html
/// [`Into`]: trait.Into.html
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
pub trait TryInto<T>: Sized {
/// The type returned in the event of a conversion error.
- #[stable(feature = "try_from", since = "1.26.0")]
type Error;
/// Performs the conversion.
- #[stable(feature = "try_from", since = "1.26.0")]
fn try_into(self) -> Result<T, Self::Error>;
}
/// Attempt to construct `Self` via a conversion.
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
pub trait TryFrom<T>: Sized {
/// The type returned in the event of a conversion error.
- #[stable(feature = "try_from", since = "1.26.0")]
type Error;
/// Performs the conversion.
- #[stable(feature = "try_from", since = "1.26.0")]
fn try_from(value: T) -> Result<Self, Self::Error>;
}
// TryFrom implies TryInto
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl<T, U> TryInto<U> for T where U: TryFrom<T>
{
type Error = U::Error;
// Infallible conversions are semantically equivalent to fallible conversions
// with an uninhabited error type.
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl<T, U> TryFrom<U> for T where T: From<U> {
type Error = !;
fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp }
-#[stable(feature = "never_type", since = "1.26.0")]
+#[unstable(feature = "never_type", issue = "35121")]
impl Debug for ! {
fn fmt(&self, _: &mut Formatter) -> Result {
*self
}
}
-#[stable(feature = "never_type", since = "1.26.0")]
+#[unstable(feature = "never_type", issue = "35121")]
impl Display for ! {
fn fmt(&self, _: &mut Formatter) -> Result {
*self
--- /dev/null
+// Copyright 2018 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.
+
+#![stable(feature = "core_hint", since = "1.27.0")]
+
+//! Hints to compiler that affects how code should be emitted or optimized.
+
+use intrinsics;
+
+/// Informs the compiler that this point in the code is not reachable, enabling
+/// further optimizations.
+///
+/// # Safety
+///
+/// Reaching this function is completely *undefined behavior* (UB). In
+/// particular, the compiler assumes that all UB must never happen, and
+/// therefore will eliminate all branches that reach to a call to
+/// `unreachable_unchecked()`.
+///
+/// Like all instances of UB, if this assumption turns out to be wrong, i.e. the
+/// `unreachable_unchecked()` call is actually reachable among all possible
+/// control flow, the compiler will apply the wrong optimization strategy, and
+/// may sometimes even corrupt seemingly unrelated code, causing
+/// difficult-to-debug problems.
+///
+/// Use this function only when you can prove that the code will never call it.
+///
+/// The [`unreachable!()`] macro is the safe counterpart of this function, which
+/// will panic instead when executed.
+///
+/// [`unreachable!()`]: ../macro.unreachable.html
+///
+/// # Example
+///
+/// ```
+/// fn div_1(a: u32, b: u32) -> u32 {
+/// use std::hint::unreachable_unchecked;
+///
+/// // `b.saturating_add(1)` is always positive (not zero),
+/// // hence `checked_div` will never return None.
+/// // Therefore, the else branch is unreachable.
+/// a.checked_div(b.saturating_add(1))
+/// .unwrap_or_else(|| unsafe { unreachable_unchecked() })
+/// }
+///
+/// assert_eq!(div_1(7, 0), 7);
+/// assert_eq!(div_1(9, 1), 4);
+/// assert_eq!(div_1(11, std::u32::MAX), 0);
+/// ```
+#[inline]
+#[stable(feature = "unreachable", since = "1.27.0")]
+pub unsafe fn unreachable_unchecked() -> ! {
+ intrinsics::unreachable()
+}
}
}
+#[cfg(stage0)]
+macro_rules! public_in_stage0 {
+ ( { $(#[$attr:meta])* } $($Item: tt)*) => {
+ $(#[$attr])* pub $($Item)*
+ }
+}
+
+#[cfg(not(stage0))]
+macro_rules! public_in_stage0 {
+ ( { $(#[$attr:meta])* } $($Item: tt)*) => {
+ $(#[$attr])* pub(crate) $($Item)*
+ }
+}
/// NB: This is very different from the `unreachable!()` macro: Unlike the
/// macro, which panics when it is executed, it is *undefined behavior* to
/// reach code marked with this function.
+ ///
+ /// The stabilized version of this intrinsic is
+ /// [`std::hint::unreachable_unchecked`](../../std/hint/fn.unreachable_unchecked.html).
pub fn unreachable() -> !;
/// Informs the optimizer that a condition is always true.
#![feature(cfg_target_has_atomic)]
#![feature(concat_idents)]
#![feature(const_fn)]
+#![feature(core_float)]
#![feature(custom_attribute)]
#![feature(doc_cfg)]
#![feature(doc_spotlight)]
#![feature(iterator_repeat_with)]
#![feature(lang_items)]
#![feature(link_llvm_intrinsics)]
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![feature(macro_at_most_once_rep)]
#![feature(no_core)]
#![feature(rustc_attrs)]
#![feature(rustc_const_unstable)]
#![feature(simd_ffi)]
+#![feature(core_slice_ext)]
+#![feature(core_str_ext)]
#![feature(specialization)]
#![feature(staged_api)]
#![feature(stmt_expr_attributes)]
#![feature(unboxed_closures)]
#![feature(untagged_unions)]
#![feature(unwind_attributes)]
+#![feature(doc_alias)]
#![cfg_attr(not(stage0), feature(mmx_target_feature))]
#![cfg_attr(not(stage0), feature(tbm_target_feature))]
pub mod mem;
pub mod nonzero;
pub mod ptr;
+pub mod hint;
/* Core language traits */
#[allow(unused_macros)]
macro_rules! vector_impl { ($([$f:ident, $($args:tt)*]),*) => { $($f!($($args)*);)* } }
#[path = "../stdsimd/coresimd/mod.rs"]
-#[allow(missing_docs, missing_debug_implementations, dead_code)]
+#[allow(missing_docs, missing_debug_implementations, dead_code, unused_imports)]
#[unstable(feature = "stdsimd", issue = "48556")]
#[cfg(not(stage0))] // allow changes to how stdsimd works in stage0
mod coresimd;
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(alias = "?")]
macro_rules! try {
($expr:expr) => (match $expr {
$crate::result::Result::Ok(val) => val,
/// * Iterators that dynamically terminate.
///
/// If the determination that the code is unreachable proves incorrect, the
-/// program immediately terminates with a [`panic!`]. The function [`unreachable`],
-/// which belongs to the [`std::intrinsics`] module, informs the compilier to
+/// program immediately terminates with a [`panic!`]. The function [`unreachable_unchecked`],
+/// which belongs to the [`std::hint`] module, informs the compilier to
/// optimize the code out of the release version entirely.
///
/// [`panic!`]: ../std/macro.panic.html
-/// [`unreachable`]: ../std/intrinsics/fn.unreachable.html
-/// [`std::intrinsics`]: ../std/intrinsics/index.html
+/// [`unreachable_unchecked`]: ../std/hint/fn.unreachable_unchecked.html
+/// [`std::hint`]: ../std/hint/index.html
///
/// # Panics
///
bool char
}
- #[stable(feature = "never_type", since = "1.26.0")]
+ #[unstable(feature = "never_type", issue = "35121")]
impl Copy for ! {}
#[stable(feature = "rust1", since = "1.0.0")]
}
}
-/// Tells LLVM that this point in the code is not reachable, enabling further
-/// optimizations.
-///
-/// NB: This is very different from the `unreachable!()` macro: Unlike the
-/// macro, which panics when it is executed, it is *undefined behavior* to
-/// reach code marked with this function.
-#[inline]
-#[unstable(feature = "unreachable", issue = "43751")]
-pub unsafe fn unreachable() -> ! {
- intrinsics::unreachable()
-}
-
/// A pinned reference.
///
/// A pinned reference is a lot like a mutable reference, except that it is not
#![stable(feature = "rust1", since = "1.0.0")]
-use intrinsics;
use mem;
use num::Float;
+#[cfg(not(stage0))] use num::FpCategory;
use num::FpCategory as Fp;
/// The radix or base of the internal representation of `f32`.
}
}
- /// Computes the absolute value of `self`. Returns `Float::nan()` if the
- /// number is `Float::nan()`.
- #[inline]
- fn abs(self) -> f32 {
- unsafe { intrinsics::fabsf32(self) }
- }
-
- /// Returns a number that represents the sign of `self`.
- ///
- /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()`
- /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()`
- /// - `Float::nan()` if the number is `Float::nan()`
- #[inline]
- fn signum(self) -> f32 {
- if self.is_nan() {
- NAN
- } else {
- unsafe { intrinsics::copysignf32(1.0, self) }
- }
- }
-
/// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
/// positive sign bit and positive infinity.
#[inline]
1.0 / self
}
- #[inline]
- fn powi(self, n: i32) -> f32 {
- unsafe { intrinsics::powif32(self, n) }
- }
-
/// Converts to degrees, assuming the number is in radians.
#[inline]
fn to_degrees(self) -> f32 {
unsafe { mem::transmute(v) }
}
}
+
+// FIXME: remove (inline) this macro and the Float trait
+// when updating to a bootstrap compiler that has the new lang items.
+#[cfg_attr(stage0, macro_export)]
+#[unstable(feature = "core_float", issue = "32110")]
+macro_rules! f32_core_methods { () => {
+ /// Returns `true` if this value is `NaN` and false otherwise.
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let nan = f32::NAN;
+ /// let f = 7.0_f32;
+ ///
+ /// assert!(nan.is_nan());
+ /// assert!(!f.is_nan());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_nan(self) -> bool { Float::is_nan(self) }
+
+ /// Returns `true` if this value is positive infinity or negative infinity and
+ /// false otherwise.
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let f = 7.0f32;
+ /// let inf = f32::INFINITY;
+ /// let neg_inf = f32::NEG_INFINITY;
+ /// let nan = f32::NAN;
+ ///
+ /// assert!(!f.is_infinite());
+ /// assert!(!nan.is_infinite());
+ ///
+ /// assert!(inf.is_infinite());
+ /// assert!(neg_inf.is_infinite());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_infinite(self) -> bool { Float::is_infinite(self) }
+
+ /// Returns `true` if this number is neither infinite nor `NaN`.
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let f = 7.0f32;
+ /// let inf = f32::INFINITY;
+ /// let neg_inf = f32::NEG_INFINITY;
+ /// let nan = f32::NAN;
+ ///
+ /// assert!(f.is_finite());
+ ///
+ /// assert!(!nan.is_finite());
+ /// assert!(!inf.is_finite());
+ /// assert!(!neg_inf.is_finite());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_finite(self) -> bool { Float::is_finite(self) }
+
+ /// Returns `true` if the number is neither zero, infinite,
+ /// [subnormal][subnormal], or `NaN`.
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32
+ /// let max = f32::MAX;
+ /// let lower_than_min = 1.0e-40_f32;
+ /// let zero = 0.0_f32;
+ ///
+ /// assert!(min.is_normal());
+ /// assert!(max.is_normal());
+ ///
+ /// assert!(!zero.is_normal());
+ /// assert!(!f32::NAN.is_normal());
+ /// assert!(!f32::INFINITY.is_normal());
+ /// // Values between `0` and `min` are Subnormal.
+ /// assert!(!lower_than_min.is_normal());
+ /// ```
+ /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_normal(self) -> bool { Float::is_normal(self) }
+
+ /// Returns the floating point category of the number. If only one property
+ /// is going to be tested, it is generally faster to use the specific
+ /// predicate instead.
+ ///
+ /// ```
+ /// use std::num::FpCategory;
+ /// use std::f32;
+ ///
+ /// let num = 12.4_f32;
+ /// let inf = f32::INFINITY;
+ ///
+ /// assert_eq!(num.classify(), FpCategory::Normal);
+ /// assert_eq!(inf.classify(), FpCategory::Infinite);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn classify(self) -> FpCategory { Float::classify(self) }
+
+ /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
+ /// positive sign bit and positive infinity.
+ ///
+ /// ```
+ /// let f = 7.0_f32;
+ /// let g = -7.0_f32;
+ ///
+ /// assert!(f.is_sign_positive());
+ /// assert!(!g.is_sign_positive());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_sign_positive(self) -> bool { Float::is_sign_positive(self) }
+
+ /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
+ /// negative sign bit and negative infinity.
+ ///
+ /// ```
+ /// let f = 7.0f32;
+ /// let g = -7.0f32;
+ ///
+ /// assert!(!f.is_sign_negative());
+ /// assert!(g.is_sign_negative());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_sign_negative(self) -> bool { Float::is_sign_negative(self) }
+
+ /// Takes the reciprocal (inverse) of a number, `1/x`.
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = 2.0_f32;
+ /// let abs_difference = (x.recip() - (1.0/x)).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn recip(self) -> f32 { Float::recip(self) }
+
+ /// Converts radians to degrees.
+ ///
+ /// ```
+ /// use std::f32::{self, consts};
+ ///
+ /// let angle = consts::PI;
+ ///
+ /// let abs_difference = (angle.to_degrees() - 180.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")]
+ #[inline]
+ pub fn to_degrees(self) -> f32 { Float::to_degrees(self) }
+
+ /// Converts degrees to radians.
+ ///
+ /// ```
+ /// use std::f32::{self, consts};
+ ///
+ /// let angle = 180.0f32;
+ ///
+ /// let abs_difference = (angle.to_radians() - consts::PI).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")]
+ #[inline]
+ pub fn to_radians(self) -> f32 { Float::to_radians(self) }
+
+ /// Returns the maximum of the two numbers.
+ ///
+ /// ```
+ /// let x = 1.0f32;
+ /// let y = 2.0f32;
+ ///
+ /// assert_eq!(x.max(y), y);
+ /// ```
+ ///
+ /// If one of the arguments is NaN, then the other argument is returned.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn max(self, other: f32) -> f32 {
+ Float::max(self, other)
+ }
+
+ /// Returns the minimum of the two numbers.
+ ///
+ /// ```
+ /// let x = 1.0f32;
+ /// let y = 2.0f32;
+ ///
+ /// assert_eq!(x.min(y), x);
+ /// ```
+ ///
+ /// If one of the arguments is NaN, then the other argument is returned.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn min(self, other: f32) -> f32 {
+ Float::min(self, other)
+ }
+
+ /// Raw transmutation to `u32`.
+ ///
+ /// This is currently identical to `transmute::<f32, u32>(self)` on all platforms.
+ ///
+ /// See `from_bits` for some discussion of the portability of this operation
+ /// (there are almost no issues).
+ ///
+ /// Note that this function is distinct from `as` casting, which attempts to
+ /// preserve the *numeric* value, and not the bitwise value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// assert_ne!((1f32).to_bits(), 1f32 as u32); // to_bits() is not casting!
+ /// assert_eq!((12.5f32).to_bits(), 0x41480000);
+ ///
+ /// ```
+ #[stable(feature = "float_bits_conv", since = "1.20.0")]
+ #[inline]
+ pub fn to_bits(self) -> u32 {
+ Float::to_bits(self)
+ }
+
+ /// Raw transmutation from `u32`.
+ ///
+ /// This is currently identical to `transmute::<u32, f32>(v)` on all platforms.
+ /// It turns out this is incredibly portable, for two reasons:
+ ///
+ /// * Floats and Ints have the same endianness on all supported platforms.
+ /// * IEEE-754 very precisely specifies the bit layout of floats.
+ ///
+ /// However there is one caveat: prior to the 2008 version of IEEE-754, how
+ /// to interpret the NaN signaling bit wasn't actually specified. Most platforms
+ /// (notably x86 and ARM) picked the interpretation that was ultimately
+ /// standardized in 2008, but some didn't (notably MIPS). As a result, all
+ /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
+ ///
+ /// Rather than trying to preserve signaling-ness cross-platform, this
+ /// implementation favours preserving the exact bits. This means that
+ /// any payloads encoded in NaNs will be preserved even if the result of
+ /// this method is sent over the network from an x86 machine to a MIPS one.
+ ///
+ /// If the results of this method are only manipulated by the same
+ /// architecture that produced them, then there is no portability concern.
+ ///
+ /// If the input isn't NaN, then there is no portability concern.
+ ///
+ /// If you don't care about signalingness (very likely), then there is no
+ /// portability concern.
+ ///
+ /// Note that this function is distinct from `as` casting, which attempts to
+ /// preserve the *numeric* value, and not the bitwise value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ /// let v = f32::from_bits(0x41480000);
+ /// let difference = (v - 12.5).abs();
+ /// assert!(difference <= 1e-5);
+ /// ```
+ #[stable(feature = "float_bits_conv", since = "1.20.0")]
+ #[inline]
+ pub fn from_bits(v: u32) -> Self {
+ Float::from_bits(v)
+ }
+}}
+
+#[lang = "f32"]
+#[cfg(not(test))]
+#[cfg(not(stage0))]
+impl f32 {
+ f32_core_methods!();
+}
#![stable(feature = "rust1", since = "1.0.0")]
-use intrinsics;
use mem;
-use num::FpCategory as Fp;
use num::Float;
+#[cfg(not(stage0))] use num::FpCategory;
+use num::FpCategory as Fp;
/// The radix or base of the internal representation of `f64`.
#[stable(feature = "rust1", since = "1.0.0")]
}
}
- /// Computes the absolute value of `self`. Returns `Float::nan()` if the
- /// number is `Float::nan()`.
- #[inline]
- fn abs(self) -> f64 {
- unsafe { intrinsics::fabsf64(self) }
- }
-
- /// Returns a number that represents the sign of `self`.
- ///
- /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()`
- /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()`
- /// - `Float::nan()` if the number is `Float::nan()`
- #[inline]
- fn signum(self) -> f64 {
- if self.is_nan() {
- NAN
- } else {
- unsafe { intrinsics::copysignf64(1.0, self) }
- }
- }
-
/// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
/// positive sign bit and positive infinity.
#[inline]
1.0 / self
}
- #[inline]
- fn powi(self, n: i32) -> f64 {
- unsafe { intrinsics::powif64(self, n) }
- }
-
/// Converts to degrees, assuming the number is in radians.
#[inline]
fn to_degrees(self) -> f64 {
unsafe { mem::transmute(v) }
}
}
+
+// FIXME: remove (inline) this macro and the Float trait
+// when updating to a bootstrap compiler that has the new lang items.
+#[cfg_attr(stage0, macro_export)]
+#[unstable(feature = "core_float", issue = "32110")]
+macro_rules! f64_core_methods { () => {
+ /// Returns `true` if this value is `NaN` and false otherwise.
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let nan = f64::NAN;
+ /// let f = 7.0_f64;
+ ///
+ /// assert!(nan.is_nan());
+ /// assert!(!f.is_nan());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_nan(self) -> bool { Float::is_nan(self) }
+
+ /// Returns `true` if this value is positive infinity or negative infinity and
+ /// false otherwise.
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let f = 7.0f64;
+ /// let inf = f64::INFINITY;
+ /// let neg_inf = f64::NEG_INFINITY;
+ /// let nan = f64::NAN;
+ ///
+ /// assert!(!f.is_infinite());
+ /// assert!(!nan.is_infinite());
+ ///
+ /// assert!(inf.is_infinite());
+ /// assert!(neg_inf.is_infinite());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_infinite(self) -> bool { Float::is_infinite(self) }
+
+ /// Returns `true` if this number is neither infinite nor `NaN`.
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let f = 7.0f64;
+ /// let inf: f64 = f64::INFINITY;
+ /// let neg_inf: f64 = f64::NEG_INFINITY;
+ /// let nan: f64 = f64::NAN;
+ ///
+ /// assert!(f.is_finite());
+ ///
+ /// assert!(!nan.is_finite());
+ /// assert!(!inf.is_finite());
+ /// assert!(!neg_inf.is_finite());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_finite(self) -> bool { Float::is_finite(self) }
+
+ /// Returns `true` if the number is neither zero, infinite,
+ /// [subnormal][subnormal], or `NaN`.
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64
+ /// let max = f64::MAX;
+ /// let lower_than_min = 1.0e-308_f64;
+ /// let zero = 0.0f64;
+ ///
+ /// assert!(min.is_normal());
+ /// assert!(max.is_normal());
+ ///
+ /// assert!(!zero.is_normal());
+ /// assert!(!f64::NAN.is_normal());
+ /// assert!(!f64::INFINITY.is_normal());
+ /// // Values between `0` and `min` are Subnormal.
+ /// assert!(!lower_than_min.is_normal());
+ /// ```
+ /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_normal(self) -> bool { Float::is_normal(self) }
+
+ /// Returns the floating point category of the number. If only one property
+ /// is going to be tested, it is generally faster to use the specific
+ /// predicate instead.
+ ///
+ /// ```
+ /// use std::num::FpCategory;
+ /// use std::f64;
+ ///
+ /// let num = 12.4_f64;
+ /// let inf = f64::INFINITY;
+ ///
+ /// assert_eq!(num.classify(), FpCategory::Normal);
+ /// assert_eq!(inf.classify(), FpCategory::Infinite);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn classify(self) -> FpCategory { Float::classify(self) }
+
+ /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
+ /// positive sign bit and positive infinity.
+ ///
+ /// ```
+ /// let f = 7.0_f64;
+ /// let g = -7.0_f64;
+ ///
+ /// assert!(f.is_sign_positive());
+ /// assert!(!g.is_sign_positive());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_sign_positive(self) -> bool { Float::is_sign_positive(self) }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")]
+ #[inline]
+ #[doc(hidden)]
+ pub fn is_positive(self) -> bool { Float::is_sign_positive(self) }
+
+ /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
+ /// negative sign bit and negative infinity.
+ ///
+ /// ```
+ /// let f = 7.0_f64;
+ /// let g = -7.0_f64;
+ ///
+ /// assert!(!f.is_sign_negative());
+ /// assert!(g.is_sign_negative());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_sign_negative(self) -> bool { Float::is_sign_negative(self) }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")]
+ #[inline]
+ #[doc(hidden)]
+ pub fn is_negative(self) -> bool { Float::is_sign_negative(self) }
+
+ /// Takes the reciprocal (inverse) of a number, `1/x`.
+ ///
+ /// ```
+ /// let x = 2.0_f64;
+ /// let abs_difference = (x.recip() - (1.0/x)).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn recip(self) -> f64 { Float::recip(self) }
+
+ /// Converts radians to degrees.
+ ///
+ /// ```
+ /// use std::f64::consts;
+ ///
+ /// let angle = consts::PI;
+ ///
+ /// let abs_difference = (angle.to_degrees() - 180.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn to_degrees(self) -> f64 { Float::to_degrees(self) }
+
+ /// Converts degrees to radians.
+ ///
+ /// ```
+ /// use std::f64::consts;
+ ///
+ /// let angle = 180.0_f64;
+ ///
+ /// let abs_difference = (angle.to_radians() - consts::PI).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn to_radians(self) -> f64 { Float::to_radians(self) }
+
+ /// Returns the maximum of the two numbers.
+ ///
+ /// ```
+ /// let x = 1.0_f64;
+ /// let y = 2.0_f64;
+ ///
+ /// assert_eq!(x.max(y), y);
+ /// ```
+ ///
+ /// If one of the arguments is NaN, then the other argument is returned.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn max(self, other: f64) -> f64 {
+ Float::max(self, other)
+ }
+
+ /// Returns the minimum of the two numbers.
+ ///
+ /// ```
+ /// let x = 1.0_f64;
+ /// let y = 2.0_f64;
+ ///
+ /// assert_eq!(x.min(y), x);
+ /// ```
+ ///
+ /// If one of the arguments is NaN, then the other argument is returned.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn min(self, other: f64) -> f64 {
+ Float::min(self, other)
+ }
+
+ /// Raw transmutation to `u64`.
+ ///
+ /// This is currently identical to `transmute::<f64, u64>(self)` on all platforms.
+ ///
+ /// See `from_bits` for some discussion of the portability of this operation
+ /// (there are almost no issues).
+ ///
+ /// Note that this function is distinct from `as` casting, which attempts to
+ /// preserve the *numeric* value, and not the bitwise value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting!
+ /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
+ ///
+ /// ```
+ #[stable(feature = "float_bits_conv", since = "1.20.0")]
+ #[inline]
+ pub fn to_bits(self) -> u64 {
+ Float::to_bits(self)
+ }
+
+ /// Raw transmutation from `u64`.
+ ///
+ /// This is currently identical to `transmute::<u64, f64>(v)` on all platforms.
+ /// It turns out this is incredibly portable, for two reasons:
+ ///
+ /// * Floats and Ints have the same endianness on all supported platforms.
+ /// * IEEE-754 very precisely specifies the bit layout of floats.
+ ///
+ /// However there is one caveat: prior to the 2008 version of IEEE-754, how
+ /// to interpret the NaN signaling bit wasn't actually specified. Most platforms
+ /// (notably x86 and ARM) picked the interpretation that was ultimately
+ /// standardized in 2008, but some didn't (notably MIPS). As a result, all
+ /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
+ ///
+ /// Rather than trying to preserve signaling-ness cross-platform, this
+ /// implementation favours preserving the exact bits. This means that
+ /// any payloads encoded in NaNs will be preserved even if the result of
+ /// this method is sent over the network from an x86 machine to a MIPS one.
+ ///
+ /// If the results of this method are only manipulated by the same
+ /// architecture that produced them, then there is no portability concern.
+ ///
+ /// If the input isn't NaN, then there is no portability concern.
+ ///
+ /// If you don't care about signalingness (very likely), then there is no
+ /// portability concern.
+ ///
+ /// Note that this function is distinct from `as` casting, which attempts to
+ /// preserve the *numeric* value, and not the bitwise value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ /// let v = f64::from_bits(0x4029000000000000);
+ /// let difference = (v - 12.5).abs();
+ /// assert!(difference <= 1e-5);
+ /// ```
+ #[stable(feature = "float_bits_conv", since = "1.20.0")]
+ #[inline]
+ pub fn from_bits(v: u64) -> Self {
+ Float::from_bits(v)
+ }
+}}
+
+#[lang = "f64"]
+#[cfg(not(test))]
+#[cfg(not(stage0))]
+impl f64 {
+ f64_core_methods!();
+}
pub fn mod_euc(self, rhs: Self) -> Self {
let r = self % rhs;
if r < 0 {
- r + rhs.abs()
+ if rhs < 0 {
+ r - rhs
+ } else {
+ r + rhs
+ }
} else {
r
}
Normal,
}
-/// A built-in floating point number.
+// Technically private and only exposed for coretests:
#[doc(hidden)]
-#[unstable(feature = "core_float",
- reason = "stable interface is via `impl f{32,64}` in later crates",
- issue = "32110")]
+#[unstable(feature = "float_internals",
+ reason = "internal routines only exposed for testing",
+ issue = "0")]
pub trait Float: Sized {
/// Type used by `to_bits` and `from_bits`.
- #[stable(feature = "core_float_bits", since = "1.25.0")]
type Bits;
/// Returns `true` if this value is NaN and false otherwise.
- #[stable(feature = "core", since = "1.6.0")]
fn is_nan(self) -> bool;
+
/// Returns `true` if this value is positive infinity or negative infinity and
/// false otherwise.
- #[stable(feature = "core", since = "1.6.0")]
fn is_infinite(self) -> bool;
+
/// Returns `true` if this number is neither infinite nor NaN.
- #[stable(feature = "core", since = "1.6.0")]
fn is_finite(self) -> bool;
+
/// Returns `true` if this number is neither zero, infinite, denormal, or NaN.
- #[stable(feature = "core", since = "1.6.0")]
fn is_normal(self) -> bool;
+
/// Returns the category that this number falls into.
- #[stable(feature = "core", since = "1.6.0")]
fn classify(self) -> FpCategory;
- /// Computes the absolute value of `self`. Returns `Float::nan()` if the
- /// number is `Float::nan()`.
- #[stable(feature = "core", since = "1.6.0")]
- fn abs(self) -> Self;
- /// Returns a number that represents the sign of `self`.
- ///
- /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()`
- /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()`
- /// - `Float::nan()` if the number is `Float::nan()`
- #[stable(feature = "core", since = "1.6.0")]
- fn signum(self) -> Self;
-
/// Returns `true` if `self` is positive, including `+0.0` and
/// `Float::infinity()`.
- #[stable(feature = "core", since = "1.6.0")]
fn is_sign_positive(self) -> bool;
+
/// Returns `true` if `self` is negative, including `-0.0` and
/// `Float::neg_infinity()`.
- #[stable(feature = "core", since = "1.6.0")]
fn is_sign_negative(self) -> bool;
/// Take the reciprocal (inverse) of a number, `1/x`.
- #[stable(feature = "core", since = "1.6.0")]
fn recip(self) -> Self;
- /// Raise a number to an integer power.
- ///
- /// Using this function is generally faster than using `powf`
- #[stable(feature = "core", since = "1.6.0")]
- fn powi(self, n: i32) -> Self;
-
/// Convert radians to degrees.
- #[stable(feature = "deg_rad_conversions", since="1.7.0")]
fn to_degrees(self) -> Self;
+
/// Convert degrees to radians.
- #[stable(feature = "deg_rad_conversions", since="1.7.0")]
fn to_radians(self) -> Self;
/// Returns the maximum of the two numbers.
- #[stable(feature = "core_float_min_max", since="1.20.0")]
fn max(self, other: Self) -> Self;
+
/// Returns the minimum of the two numbers.
- #[stable(feature = "core_float_min_max", since="1.20.0")]
fn min(self, other: Self) -> Self;
/// Raw transmutation to integer.
- #[stable(feature = "core_float_bits", since="1.25.0")]
fn to_bits(self) -> Self::Bits;
+
/// Raw transmutation from integer.
- #[stable(feature = "core_float_bits", since="1.25.0")]
fn from_bits(v: Self::Bits) -> Self;
}
from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 }
/// The error type returned when a checked integral type conversion fails.
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
#[derive(Debug, Copy, Clone)]
pub struct TryFromIntError(());
}
}
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl fmt::Display for TryFromIntError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.__description().fmt(fmt)
}
}
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl From<!> for TryFromIntError {
fn from(never: !) -> TryFromIntError {
never
// only negative bounds
macro_rules! try_from_lower_bounded {
($source:ty, $($target:ty),*) => {$(
- #[stable(feature = "try_from", since = "1.26.0")]
+ #[unstable(feature = "try_from", issue = "33417")]
impl TryFrom<$source> for $target {
type Error = TryFromIntError;
// unsigned to signed (only positive bound)
macro_rules! try_from_upper_bounded {
($source:ty, $($target:ty),*) => {$(
- #[stable(feature = "try_from", since = "1.26.0")]
+ #[unstable(feature = "try_from", issue = "33417")]
impl TryFrom<$source> for $target {
type Error = TryFromIntError;
// all other cases
macro_rules! try_from_both_bounded {
($source:ty, $($target:ty),*) => {$(
- #[stable(feature = "try_from", since = "1.26.0")]
+ #[unstable(feature = "try_from", issue = "33417")]
impl TryFrom<$source> for $target {
type Error = TryFromIntError;
message="cannot add `{RHS}` to `{Self}`",
label="no implementation for `{Self} + {RHS}`",
)]
+#[doc(alias = "+")]
pub trait Add<RHS=Self> {
/// The resulting type after applying the `+` operator.
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(message="cannot subtract `{RHS}` from `{Self}`",
label="no implementation for `{Self} - {RHS}`")]
+#[doc(alias = "-")]
pub trait Sub<RHS=Self> {
/// The resulting type after applying the `-` operator.
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(message="cannot multiply `{RHS}` to `{Self}`",
label="no implementation for `{Self} * {RHS}`")]
+#[doc(alias = "*")]
pub trait Mul<RHS=Self> {
/// The resulting type after applying the `*` operator.
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(message="cannot divide `{Self}` by `{RHS}`",
label="no implementation for `{Self} / {RHS}`")]
+#[doc(alias = "/")]
pub trait Div<RHS=Self> {
/// The resulting type after applying the `/` operator.
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(message="cannot mod `{Self}` by `{RHS}`",
label="no implementation for `{Self} % {RHS}`")]
+#[doc(alias = "%")]
pub trait Rem<RHS=Self> {
/// The resulting type after applying the `%` operator.
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "neg"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(alias = "-")]
pub trait Neg {
/// The resulting type after applying the `-` operator.
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[rustc_on_unimplemented(message="cannot add-assign `{Rhs}` to `{Self}`",
label="no implementation for `{Self} += {Rhs}`")]
+#[doc(alias = "+")]
+#[doc(alias = "+=")]
pub trait AddAssign<Rhs=Self> {
/// Performs the `+=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[rustc_on_unimplemented(message="cannot subtract-assign `{Rhs}` from `{Self}`",
label="no implementation for `{Self} -= {Rhs}`")]
+#[doc(alias = "-")]
+#[doc(alias = "-=")]
pub trait SubAssign<Rhs=Self> {
/// Performs the `-=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[rustc_on_unimplemented(message="cannot multiply-assign `{Rhs}` to `{Self}`",
label="no implementation for `{Self} *= {Rhs}`")]
+#[doc(alias = "*")]
+#[doc(alias = "*=")]
pub trait MulAssign<Rhs=Self> {
/// Performs the `*=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[rustc_on_unimplemented(message="cannot divide-assign `{Self}` by `{Rhs}`",
label="no implementation for `{Self} /= {Rhs}`")]
+#[doc(alias = "/")]
+#[doc(alias = "/=")]
pub trait DivAssign<Rhs=Self> {
/// Performs the `/=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[rustc_on_unimplemented(message="cannot mod-assign `{Self}` by `{Rhs}``",
label="no implementation for `{Self} %= {Rhs}`")]
+#[doc(alias = "%")]
+#[doc(alias = "%=")]
pub trait RemAssign<Rhs=Self> {
/// Performs the `%=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[lang = "index"]
#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(alias = "]")]
+#[doc(alias = "[")]
+#[doc(alias = "[]")]
pub trait Index<Idx: ?Sized> {
/// The returned type after indexing.
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "index_mut"]
#[rustc_on_unimplemented = "the type `{Self}` cannot be mutably indexed by `{Idx}`"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(alias = "[")]
+#[doc(alias = "]")]
+#[doc(alias = "[]")]
pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
/// Performs the mutable indexing (`container[index]`) operation.
#[stable(feature = "rust1", since = "1.0.0")]
that implement `{Try}`",
label="the `?` operator cannot be applied to type `{Self}`")
)]
+#[doc(alias = "?")]
pub trait Try {
/// The type of this value when viewed as successful.
#[unstable(feature = "try_trait", issue = "42327")]
// Re-exported extension traits for primitive types
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
+#[cfg(stage0)]
pub use slice::SliceExt;
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
+#[cfg(stage0)]
pub use str::StrExt;
// Extension traits
//
+public_in_stage0! {
+{
/// Extension methods for slices.
#[unstable(feature = "core_slice_ext",
reason = "stable interface provided by `impl [T]` in later crates",
issue = "32110")]
#[allow(missing_docs)] // documented elsewhere
-pub trait SliceExt {
+}
+trait SliceExt {
type Item;
#[stable(feature = "core", since = "1.6.0")]
fn sort_unstable_by_key<B, F>(&mut self, f: F)
where F: FnMut(&Self::Item) -> B,
B: Ord;
-}
+}}
// Use macros to be generic over const/mut
macro_rules! slice_offset {
}
}
+// FIXME: remove (inline) this macro and the SliceExt trait
+// when updating to a bootstrap compiler that has the new lang items.
+#[cfg_attr(stage0, macro_export)]
+#[unstable(feature = "core_slice_ext", issue = "32110")]
+macro_rules! slice_core_methods { () => {
+ /// Returns the number of elements in the slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let a = [1, 2, 3];
+ /// assert_eq!(a.len(), 3);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn len(&self) -> usize {
+ SliceExt::len(self)
+ }
+
+ /// Returns `true` if the slice has a length of 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let a = [1, 2, 3];
+ /// assert!(!a.is_empty());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ SliceExt::is_empty(self)
+ }
+
+ /// Returns the first element of the slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = [10, 40, 30];
+ /// assert_eq!(Some(&10), v.first());
+ ///
+ /// let w: &[i32] = &[];
+ /// assert_eq!(None, w.first());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn first(&self) -> Option<&T> {
+ SliceExt::first(self)
+ }
+
+ /// Returns a mutable pointer to the first element of the slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some(first) = x.first_mut() {
+ /// *first = 5;
+ /// }
+ /// assert_eq!(x, &[5, 1, 2]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn first_mut(&mut self) -> Option<&mut T> {
+ SliceExt::first_mut(self)
+ }
+
+ /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &[0, 1, 2];
+ ///
+ /// if let Some((first, elements)) = x.split_first() {
+ /// assert_eq!(first, &0);
+ /// assert_eq!(elements, &[1, 2]);
+ /// }
+ /// ```
+ #[stable(feature = "slice_splits", since = "1.5.0")]
+ #[inline]
+ pub fn split_first(&self) -> Option<(&T, &[T])> {
+ SliceExt::split_first(self)
+ }
+
+ /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some((first, elements)) = x.split_first_mut() {
+ /// *first = 3;
+ /// elements[0] = 4;
+ /// elements[1] = 5;
+ /// }
+ /// assert_eq!(x, &[3, 4, 5]);
+ /// ```
+ #[stable(feature = "slice_splits", since = "1.5.0")]
+ #[inline]
+ pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> {
+ SliceExt::split_first_mut(self)
+ }
+
+ /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &[0, 1, 2];
+ ///
+ /// if let Some((last, elements)) = x.split_last() {
+ /// assert_eq!(last, &2);
+ /// assert_eq!(elements, &[0, 1]);
+ /// }
+ /// ```
+ #[stable(feature = "slice_splits", since = "1.5.0")]
+ #[inline]
+ pub fn split_last(&self) -> Option<(&T, &[T])> {
+ SliceExt::split_last(self)
+
+ }
+
+ /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some((last, elements)) = x.split_last_mut() {
+ /// *last = 3;
+ /// elements[0] = 4;
+ /// elements[1] = 5;
+ /// }
+ /// assert_eq!(x, &[4, 5, 3]);
+ /// ```
+ #[stable(feature = "slice_splits", since = "1.5.0")]
+ #[inline]
+ pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> {
+ SliceExt::split_last_mut(self)
+ }
+
+ /// Returns the last element of the slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = [10, 40, 30];
+ /// assert_eq!(Some(&30), v.last());
+ ///
+ /// let w: &[i32] = &[];
+ /// assert_eq!(None, w.last());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn last(&self) -> Option<&T> {
+ SliceExt::last(self)
+ }
+
+ /// Returns a mutable pointer to the last item in the slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some(last) = x.last_mut() {
+ /// *last = 10;
+ /// }
+ /// assert_eq!(x, &[0, 1, 10]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn last_mut(&mut self) -> Option<&mut T> {
+ SliceExt::last_mut(self)
+ }
+
+ /// Returns a reference to an element or subslice depending on the type of
+ /// index.
+ ///
+ /// - If given a position, returns a reference to the element at that
+ /// position or `None` if out of bounds.
+ /// - If given a range, returns the subslice corresponding to that range,
+ /// or `None` if out of bounds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = [10, 40, 30];
+ /// assert_eq!(Some(&40), v.get(1));
+ /// assert_eq!(Some(&[10, 40][..]), v.get(0..2));
+ /// assert_eq!(None, v.get(3));
+ /// assert_eq!(None, v.get(0..4));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn get<I>(&self, index: I) -> Option<&I::Output>
+ where I: SliceIndex<Self>
+ {
+ SliceExt::get(self, index)
+ }
+
+ /// Returns a mutable reference to an element or subslice depending on the
+ /// type of index (see [`get`]) or `None` if the index is out of bounds.
+ ///
+ /// [`get`]: #method.get
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some(elem) = x.get_mut(1) {
+ /// *elem = 42;
+ /// }
+ /// assert_eq!(x, &[0, 42, 2]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
+ where I: SliceIndex<Self>
+ {
+ SliceExt::get_mut(self, index)
+ }
+
+ /// Returns a reference to an element or subslice, without doing bounds
+ /// checking.
+ ///
+ /// This is generally not recommended, use with caution! For a safe
+ /// alternative see [`get`].
+ ///
+ /// [`get`]: #method.get
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &[1, 2, 4];
+ ///
+ /// unsafe {
+ /// assert_eq!(x.get_unchecked(1), &2);
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
+ where I: SliceIndex<Self>
+ {
+ SliceExt::get_unchecked(self, index)
+ }
+
+ /// Returns a mutable reference to an element or subslice, without doing
+ /// bounds checking.
+ ///
+ /// This is generally not recommended, use with caution! For a safe
+ /// alternative see [`get_mut`].
+ ///
+ /// [`get_mut`]: #method.get_mut
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [1, 2, 4];
+ ///
+ /// unsafe {
+ /// let elem = x.get_unchecked_mut(1);
+ /// *elem = 13;
+ /// }
+ /// assert_eq!(x, &[1, 13, 4]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
+ where I: SliceIndex<Self>
+ {
+ SliceExt::get_unchecked_mut(self, index)
+ }
+
+ /// Returns a raw pointer to the slice's buffer.
+ ///
+ /// The caller must ensure that the slice outlives the pointer this
+ /// function returns, or else it will end up pointing to garbage.
+ ///
+ /// Modifying the container referenced by this slice may cause its buffer
+ /// to be reallocated, which would also make any pointers to it invalid.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &[1, 2, 4];
+ /// let x_ptr = x.as_ptr();
+ ///
+ /// unsafe {
+ /// for i in 0..x.len() {
+ /// assert_eq!(x.get_unchecked(i), &*x_ptr.offset(i as isize));
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn as_ptr(&self) -> *const T {
+ SliceExt::as_ptr(self)
+ }
+
+ /// Returns an unsafe mutable pointer to the slice's buffer.
+ ///
+ /// The caller must ensure that the slice outlives the pointer this
+ /// function returns, or else it will end up pointing to garbage.
+ ///
+ /// Modifying the container referenced by this slice may cause its buffer
+ /// to be reallocated, which would also make any pointers to it invalid.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [1, 2, 4];
+ /// let x_ptr = x.as_mut_ptr();
+ ///
+ /// unsafe {
+ /// for i in 0..x.len() {
+ /// *x_ptr.offset(i as isize) += 2;
+ /// }
+ /// }
+ /// assert_eq!(x, &[3, 4, 6]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn as_mut_ptr(&mut self) -> *mut T {
+ SliceExt::as_mut_ptr(self)
+ }
+
+ /// Swaps two elements in the slice.
+ ///
+ /// # Arguments
+ ///
+ /// * a - The index of the first element
+ /// * b - The index of the second element
+ ///
+ /// # Panics
+ ///
+ /// Panics if `a` or `b` are out of bounds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = ["a", "b", "c", "d"];
+ /// v.swap(1, 3);
+ /// assert!(v == ["a", "d", "c", "b"]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn swap(&mut self, a: usize, b: usize) {
+ SliceExt::swap(self, a, b)
+ }
+
+ /// Reverses the order of elements in the slice, in place.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [1, 2, 3];
+ /// v.reverse();
+ /// assert!(v == [3, 2, 1]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn reverse(&mut self) {
+ SliceExt::reverse(self)
+ }
+
+ /// Returns an iterator over the slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &[1, 2, 4];
+ /// let mut iterator = x.iter();
+ ///
+ /// assert_eq!(iterator.next(), Some(&1));
+ /// assert_eq!(iterator.next(), Some(&2));
+ /// assert_eq!(iterator.next(), Some(&4));
+ /// assert_eq!(iterator.next(), None);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn iter(&self) -> Iter<T> {
+ SliceExt::iter(self)
+ }
+
+ /// Returns an iterator that allows modifying each value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [1, 2, 4];
+ /// for elem in x.iter_mut() {
+ /// *elem += 2;
+ /// }
+ /// assert_eq!(x, &[3, 4, 6]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn iter_mut(&mut self) -> IterMut<T> {
+ SliceExt::iter_mut(self)
+ }
+
+ /// Returns an iterator over all contiguous windows of length
+ /// `size`. The windows overlap. If the slice is shorter than
+ /// `size`, the iterator returns no values.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `size` is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let slice = ['r', 'u', 's', 't'];
+ /// let mut iter = slice.windows(2);
+ /// assert_eq!(iter.next().unwrap(), &['r', 'u']);
+ /// assert_eq!(iter.next().unwrap(), &['u', 's']);
+ /// assert_eq!(iter.next().unwrap(), &['s', 't']);
+ /// assert!(iter.next().is_none());
+ /// ```
+ ///
+ /// If the slice is shorter than `size`:
+ ///
+ /// ```
+ /// let slice = ['f', 'o', 'o'];
+ /// let mut iter = slice.windows(4);
+ /// assert!(iter.next().is_none());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn windows(&self, size: usize) -> Windows<T> {
+ SliceExt::windows(self, size)
+ }
+
+ /// Returns an iterator over `chunk_size` elements of the slice at a
+ /// time. The chunks are slices and do not overlap. If `chunk_size` does
+ /// 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
+ /// of always exactly `chunk_size` elements.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `chunk_size` is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let slice = ['l', 'o', 'r', 'e', 'm'];
+ /// let mut iter = slice.chunks(2);
+ /// assert_eq!(iter.next().unwrap(), &['l', 'o']);
+ /// assert_eq!(iter.next().unwrap(), &['r', 'e']);
+ /// assert_eq!(iter.next().unwrap(), &['m']);
+ /// assert!(iter.next().is_none());
+ /// ```
+ ///
+ /// [`exact_chunks`]: #method.exact_chunks
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn chunks(&self, chunk_size: usize) -> Chunks<T> {
+ SliceExt::chunks(self, chunk_size)
+ }
+
+ /// Returns an iterator over `chunk_size` elements of the slice at a
+ /// time. The chunks are slices and do not overlap. If `chunk_size` does
+ /// not divide the length of the slice, then the last up to `chunk_size-1`
+ /// elements will be omitted.
+ ///
+ /// Due to each chunk having exactly `chunk_size` elements, the compiler
+ /// can often optimize the resulting code better than in the case of
+ /// [`chunks`].
+ ///
+ /// # Panics
+ ///
+ /// Panics if `chunk_size` is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(exact_chunks)]
+ ///
+ /// let slice = ['l', 'o', 'r', 'e', 'm'];
+ /// let mut iter = slice.exact_chunks(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")]
+ #[inline]
+ pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks<T> {
+ SliceExt::exact_chunks(self, chunk_size)
+ }
+
+ /// Returns an iterator over `chunk_size` elements of the slice at a time.
+ /// The chunks are mutable slices, and do not overlap. If `chunk_size` does
+ /// 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
+ /// of always exactly `chunk_size` elements.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `chunk_size` is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = &mut [0, 0, 0, 0, 0];
+ /// let mut count = 1;
+ ///
+ /// for chunk in v.chunks_mut(2) {
+ /// for elem in chunk.iter_mut() {
+ /// *elem += count;
+ /// }
+ /// count += 1;
+ /// }
+ /// assert_eq!(v, &[1, 1, 2, 2, 3]);
+ /// ```
+ ///
+ /// [`exact_chunks_mut`]: #method.exact_chunks_mut
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> {
+ SliceExt::chunks_mut(self, chunk_size)
+ }
+
+ /// Returns an iterator over `chunk_size` elements of the slice at a time.
+ /// The chunks are mutable slices, and do not overlap. If `chunk_size` does
+ /// not divide the length of the slice, then the last up to `chunk_size-1`
+ /// elements will be omitted.
+ ///
+ ///
+ /// Due to each chunk having exactly `chunk_size` elements, the compiler
+ /// can often optimize the resulting code better than in the case of
+ /// [`chunks_mut`].
+ ///
+ /// # Panics
+ ///
+ /// Panics if `chunk_size` is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(exact_chunks)]
+ ///
+ /// let v = &mut [0, 0, 0, 0, 0];
+ /// let mut count = 1;
+ ///
+ /// for chunk in v.exact_chunks_mut(2) {
+ /// for elem in chunk.iter_mut() {
+ /// *elem += count;
+ /// }
+ /// count += 1;
+ /// }
+ /// assert_eq!(v, &[1, 1, 2, 2, 0]);
+ /// ```
+ ///
+ /// [`chunks_mut`]: #method.chunks_mut
+ #[unstable(feature = "exact_chunks", issue = "47115")]
+ #[inline]
+ pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut<T> {
+ SliceExt::exact_chunks_mut(self, chunk_size)
+ }
+
+ /// Divides one slice 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).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `mid > len`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = [1, 2, 3, 4, 5, 6];
+ ///
+ /// {
+ /// let (left, right) = v.split_at(0);
+ /// assert!(left == []);
+ /// assert!(right == [1, 2, 3, 4, 5, 6]);
+ /// }
+ ///
+ /// {
+ /// let (left, right) = v.split_at(2);
+ /// assert!(left == [1, 2]);
+ /// assert!(right == [3, 4, 5, 6]);
+ /// }
+ ///
+ /// {
+ /// let (left, right) = v.split_at(6);
+ /// assert!(left == [1, 2, 3, 4, 5, 6]);
+ /// assert!(right == []);
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn split_at(&self, mid: usize) -> (&[T], &[T]) {
+ SliceExt::split_at(self, mid)
+ }
+
+ /// Divides one mutable slice 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).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `mid > len`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [1, 0, 3, 0, 5, 6];
+ /// // scoped to restrict the lifetime of the borrows
+ /// {
+ /// let (left, right) = v.split_at_mut(2);
+ /// assert!(left == [1, 0]);
+ /// assert!(right == [3, 0, 5, 6]);
+ /// left[1] = 2;
+ /// right[1] = 4;
+ /// }
+ /// assert!(v == [1, 2, 3, 4, 5, 6]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
+ SliceExt::split_at_mut(self, mid)
+ }
+
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred`. The matched element is not contained in the subslices.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let slice = [10, 40, 33, 20];
+ /// let mut iter = slice.split(|num| num % 3 == 0);
+ ///
+ /// assert_eq!(iter.next().unwrap(), &[10, 40]);
+ /// assert_eq!(iter.next().unwrap(), &[20]);
+ /// assert!(iter.next().is_none());
+ /// ```
+ ///
+ /// If the first element is matched, an empty slice will be the first item
+ /// returned by the iterator. Similarly, if the last element in the slice
+ /// is matched, an empty slice will be the last item returned by the
+ /// iterator:
+ ///
+ /// ```
+ /// let slice = [10, 40, 33];
+ /// let mut iter = slice.split(|num| num % 3 == 0);
+ ///
+ /// assert_eq!(iter.next().unwrap(), &[10, 40]);
+ /// assert_eq!(iter.next().unwrap(), &[]);
+ /// assert!(iter.next().is_none());
+ /// ```
+ ///
+ /// If two matched elements are directly adjacent, an empty slice will be
+ /// present between them:
+ ///
+ /// ```
+ /// let slice = [10, 6, 33, 20];
+ /// let mut iter = slice.split(|num| num % 3 == 0);
+ ///
+ /// assert_eq!(iter.next().unwrap(), &[10]);
+ /// assert_eq!(iter.next().unwrap(), &[]);
+ /// assert_eq!(iter.next().unwrap(), &[20]);
+ /// assert!(iter.next().is_none());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn split<F>(&self, pred: F) -> Split<T, F>
+ where F: FnMut(&T) -> bool
+ {
+ SliceExt::split(self, pred)
+ }
+
+ /// Returns an iterator over mutable subslices separated by elements that
+ /// match `pred`. The matched element is not contained in the subslices.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [10, 40, 30, 20, 60, 50];
+ ///
+ /// for group in v.split_mut(|num| *num % 3 == 0) {
+ /// group[0] = 1;
+ /// }
+ /// assert_eq!(v, [1, 40, 30, 1, 60, 1]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<T, F>
+ where F: FnMut(&T) -> bool
+ {
+ SliceExt::split_mut(self, pred)
+ }
+
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred`, starting at the end of the slice and working backwards.
+ /// The matched element is not contained in the subslices.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let slice = [11, 22, 33, 0, 44, 55];
+ /// let mut iter = slice.rsplit(|num| *num == 0);
+ ///
+ /// assert_eq!(iter.next().unwrap(), &[44, 55]);
+ /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]);
+ /// assert_eq!(iter.next(), None);
+ /// ```
+ ///
+ /// As with `split()`, if the first or last element is matched, an empty
+ /// slice will be the first (or last) item returned by the iterator.
+ ///
+ /// ```
+ /// let v = &[0, 1, 1, 2, 3, 5, 8];
+ /// let mut it = v.rsplit(|n| *n % 2 == 0);
+ /// assert_eq!(it.next().unwrap(), &[]);
+ /// assert_eq!(it.next().unwrap(), &[3, 5]);
+ /// assert_eq!(it.next().unwrap(), &[1, 1]);
+ /// assert_eq!(it.next().unwrap(), &[]);
+ /// assert_eq!(it.next(), None);
+ /// ```
+ #[stable(feature = "slice_rsplit", since = "1.27.0")]
+ #[inline]
+ pub fn rsplit<F>(&self, pred: F) -> RSplit<T, F>
+ where F: FnMut(&T) -> bool
+ {
+ SliceExt::rsplit(self, pred)
+ }
+
+ /// Returns an iterator over mutable subslices separated by elements that
+ /// match `pred`, starting at the end of the slice and working
+ /// backwards. The matched element is not contained in the subslices.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [100, 400, 300, 200, 600, 500];
+ ///
+ /// let mut count = 0;
+ /// for group in v.rsplit_mut(|num| *num % 3 == 0) {
+ /// count += 1;
+ /// group[0] = count;
+ /// }
+ /// assert_eq!(v, [3, 400, 300, 2, 600, 1]);
+ /// ```
+ ///
+ #[stable(feature = "slice_rsplit", since = "1.27.0")]
+ #[inline]
+ pub fn rsplit_mut<F>(&mut self, pred: F) -> RSplitMut<T, F>
+ where F: FnMut(&T) -> bool
+ {
+ SliceExt::rsplit_mut(self, pred)
+ }
+
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred`, limited to returning at most `n` items. The matched element is
+ /// not contained in the subslices.
+ ///
+ /// The last element returned, if any, will contain the remainder of the
+ /// slice.
+ ///
+ /// # Examples
+ ///
+ /// Print the slice split once by numbers divisible by 3 (i.e. `[10, 40]`,
+ /// `[20, 60, 50]`):
+ ///
+ /// ```
+ /// let v = [10, 40, 30, 20, 60, 50];
+ ///
+ /// for group in v.splitn(2, |num| *num % 3 == 0) {
+ /// println!("{:?}", group);
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<T, F>
+ where F: FnMut(&T) -> bool
+ {
+ SliceExt::splitn(self, n, pred)
+ }
+
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred`, limited to returning at most `n` items. The matched element is
+ /// not contained in the subslices.
+ ///
+ /// The last element returned, if any, will contain the remainder of the
+ /// slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [10, 40, 30, 20, 60, 50];
+ ///
+ /// for group in v.splitn_mut(2, |num| *num % 3 == 0) {
+ /// group[0] = 1;
+ /// }
+ /// assert_eq!(v, [1, 40, 30, 1, 60, 50]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<T, F>
+ where F: FnMut(&T) -> bool
+ {
+ SliceExt::splitn_mut(self, n, pred)
+ }
+
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred` limited to returning at most `n` items. This starts at the end of
+ /// the slice and works backwards. The matched element is not contained in
+ /// the subslices.
+ ///
+ /// The last element returned, if any, will contain the remainder of the
+ /// slice.
+ ///
+ /// # Examples
+ ///
+ /// Print the slice split once, starting from the end, by numbers divisible
+ /// by 3 (i.e. `[50]`, `[10, 40, 30, 20]`):
+ ///
+ /// ```
+ /// let v = [10, 40, 30, 20, 60, 50];
+ ///
+ /// for group in v.rsplitn(2, |num| *num % 3 == 0) {
+ /// println!("{:?}", group);
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<T, F>
+ where F: FnMut(&T) -> bool
+ {
+ SliceExt::rsplitn(self, n, pred)
+ }
+
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred` limited to returning at most `n` items. This starts at the end of
+ /// the slice and works backwards. The matched element is not contained in
+ /// the subslices.
+ ///
+ /// The last element returned, if any, will contain the remainder of the
+ /// slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut s = [10, 40, 30, 20, 60, 50];
+ ///
+ /// for group in s.rsplitn_mut(2, |num| *num % 3 == 0) {
+ /// group[0] = 1;
+ /// }
+ /// assert_eq!(s, [1, 40, 30, 20, 60, 1]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<T, F>
+ where F: FnMut(&T) -> bool
+ {
+ SliceExt::rsplitn_mut(self, n, pred)
+ }
+
+ /// Returns `true` if the slice contains an element with the given value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = [10, 40, 30];
+ /// assert!(v.contains(&30));
+ /// assert!(!v.contains(&50));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn contains(&self, x: &T) -> bool
+ where T: PartialEq
+ {
+ SliceExt::contains(self, x)
+ }
+
+ /// Returns `true` if `needle` is a prefix of the slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = [10, 40, 30];
+ /// assert!(v.starts_with(&[10]));
+ /// assert!(v.starts_with(&[10, 40]));
+ /// assert!(!v.starts_with(&[50]));
+ /// assert!(!v.starts_with(&[10, 50]));
+ /// ```
+ ///
+ /// Always returns `true` if `needle` is an empty slice:
+ ///
+ /// ```
+ /// let v = &[10, 40, 30];
+ /// assert!(v.starts_with(&[]));
+ /// let v: &[u8] = &[];
+ /// assert!(v.starts_with(&[]));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn starts_with(&self, needle: &[T]) -> bool
+ where T: PartialEq
+ {
+ SliceExt::starts_with(self, needle)
+ }
+
+ /// Returns `true` if `needle` is a suffix of the slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = [10, 40, 30];
+ /// assert!(v.ends_with(&[30]));
+ /// assert!(v.ends_with(&[40, 30]));
+ /// assert!(!v.ends_with(&[50]));
+ /// assert!(!v.ends_with(&[50, 30]));
+ /// ```
+ ///
+ /// Always returns `true` if `needle` is an empty slice:
+ ///
+ /// ```
+ /// let v = &[10, 40, 30];
+ /// assert!(v.ends_with(&[]));
+ /// let v: &[u8] = &[];
+ /// assert!(v.ends_with(&[]));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn ends_with(&self, needle: &[T]) -> bool
+ where T: PartialEq
+ {
+ SliceExt::ends_with(self, needle)
+ }
+
+ /// Binary searches this sorted slice for a given element.
+ ///
+ /// If the value is found then `Ok` is returned, containing the
+ /// index of the matching element; if the value is not found then
+ /// `Err` is returned, containing the index where a matching
+ /// element could be inserted while maintaining sorted order.
+ ///
+ /// # Examples
+ ///
+ /// Looks up a series of four elements. The first is found, with a
+ /// uniquely determined position; the second and third are not
+ /// found; the fourth could match any position in `[1, 4]`.
+ ///
+ /// ```
+ /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+ ///
+ /// assert_eq!(s.binary_search(&13), Ok(9));
+ /// assert_eq!(s.binary_search(&4), Err(7));
+ /// assert_eq!(s.binary_search(&100), Err(13));
+ /// let r = s.binary_search(&1);
+ /// assert!(match r { Ok(1...4) => true, _ => false, });
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn binary_search(&self, x: &T) -> Result<usize, usize>
+ where T: Ord
+ {
+ SliceExt::binary_search(self, x)
+ }
+
+ /// Binary searches this sorted slice with a comparator function.
+ ///
+ /// The comparator function should implement an order consistent
+ /// with the sort order of the underlying slice, returning an
+ /// order code that indicates whether its argument is `Less`,
+ /// `Equal` or `Greater` the desired target.
+ ///
+ /// If a matching value is found then returns `Ok`, containing
+ /// the index for the matched element; if no match is found then
+ /// `Err` is returned, containing the index where a matching
+ /// element could be inserted while maintaining sorted order.
+ ///
+ /// # Examples
+ ///
+ /// Looks up a series of four elements. The first is found, with a
+ /// uniquely determined position; the second and third are not
+ /// found; the fourth could match any position in `[1, 4]`.
+ ///
+ /// ```
+ /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+ ///
+ /// let seek = 13;
+ /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9));
+ /// let seek = 4;
+ /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7));
+ /// let seek = 100;
+ /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13));
+ /// let seek = 1;
+ /// let r = s.binary_search_by(|probe| probe.cmp(&seek));
+ /// assert!(match r { Ok(1...4) => true, _ => false, });
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
+ where F: FnMut(&'a T) -> Ordering
+ {
+ SliceExt::binary_search_by(self, f)
+ }
+
+ /// Binary searches this sorted slice with a key extraction function.
+ ///
+ /// Assumes that the slice is sorted by the key, for instance with
+ /// [`sort_by_key`] using the same key extraction function.
+ ///
+ /// If a matching value is found then returns `Ok`, containing the
+ /// index for the matched element; if no match is found then `Err`
+ /// is returned, containing the index where a matching element could
+ /// be inserted while maintaining sorted order.
+ ///
+ /// [`sort_by_key`]: #method.sort_by_key
+ ///
+ /// # Examples
+ ///
+ /// Looks up a series of four elements in a slice of pairs sorted by
+ /// their second elements. The first is found, with a uniquely
+ /// determined position; the second and third are not found; the
+ /// fourth could match any position in `[1, 4]`.
+ ///
+ /// ```
+ /// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1),
+ /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
+ /// (1, 21), (2, 34), (4, 55)];
+ ///
+ /// assert_eq!(s.binary_search_by_key(&13, |&(a,b)| b), Ok(9));
+ /// assert_eq!(s.binary_search_by_key(&4, |&(a,b)| b), Err(7));
+ /// assert_eq!(s.binary_search_by_key(&100, |&(a,b)| b), Err(13));
+ /// let r = s.binary_search_by_key(&1, |&(a,b)| b);
+ /// assert!(match r { Ok(1...4) => true, _ => false, });
+ /// ```
+ #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")]
+ #[inline]
+ pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result<usize, usize>
+ where F: FnMut(&'a T) -> B,
+ B: Ord
+ {
+ SliceExt::binary_search_by_key(self, b, f)
+ }
+
+ /// 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),
+ /// and `O(n log n)` worst-case.
+ ///
+ /// # 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.
+ ///
+ /// It is typically faster than stable sorting, except in a few special cases, e.g. when the
+ /// slice consists of several concatenated sorted sequences.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [-5, 4, 1, -3, 2];
+ ///
+ /// v.sort_unstable();
+ /// assert!(v == [-5, -3, 1, 2, 4]);
+ /// ```
+ ///
+ /// [pdqsort]: https://github.com/orlp/pdqsort
+ #[stable(feature = "sort_unstable", since = "1.20.0")]
+ #[inline]
+ pub fn sort_unstable(&mut self)
+ where T: Ord
+ {
+ SliceExt::sort_unstable(self);
+ }
+
+ /// Sorts the slice with a comparator function, 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),
+ /// and `O(n log n)` worst-case.
+ ///
+ /// # 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.
+ ///
+ /// It is typically faster than stable sorting, except in a few special cases, e.g. when the
+ /// slice consists of several concatenated sorted sequences.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [5, 4, 1, 3, 2];
+ /// v.sort_unstable_by(|a, b| a.cmp(b));
+ /// assert!(v == [1, 2, 3, 4, 5]);
+ ///
+ /// // reverse sorting
+ /// v.sort_unstable_by(|a, b| b.cmp(a));
+ /// assert!(v == [5, 4, 3, 2, 1]);
+ /// ```
+ ///
+ /// [pdqsort]: https://github.com/orlp/pdqsort
+ #[stable(feature = "sort_unstable", since = "1.20.0")]
+ #[inline]
+ pub fn sort_unstable_by<F>(&mut self, compare: F)
+ where F: FnMut(&T, &T) -> Ordering
+ {
+ SliceExt::sort_unstable_by(self, compare);
+ }
+
+ /// Sorts the slice with a key extraction function, 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),
+ /// and `O(m n log(m n))` worst-case, where the key function is `O(m)`.
+ ///
+ /// # 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.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [-5i32, 4, 1, -3, 2];
+ ///
+ /// v.sort_unstable_by_key(|k| k.abs());
+ /// assert!(v == [1, 2, -3, 4, -5]);
+ /// ```
+ ///
+ /// [pdqsort]: https://github.com/orlp/pdqsort
+ #[stable(feature = "sort_unstable", since = "1.20.0")]
+ #[inline]
+ pub fn sort_unstable_by_key<K, F>(&mut self, f: F)
+ where F: FnMut(&T) -> K, K: Ord
+ {
+ SliceExt::sort_unstable_by_key(self, f);
+ }
+
+ /// 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
+ /// `mid` will become the first element in the slice.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `mid` is greater than the length of the
+ /// slice. Note that `mid == self.len()` does _not_ panic and is a no-op
+ /// rotation.
+ ///
+ /// # Complexity
+ ///
+ /// Takes linear (in `self.len()`) time.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
+ /// a.rotate_left(2);
+ /// assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']);
+ /// ```
+ ///
+ /// Rotating a subslice:
+ ///
+ /// ```
+ /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
+ /// a[1..5].rotate_left(1);
+ /// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']);
+ /// ```
+ #[stable(feature = "slice_rotate", since = "1.26.0")]
+ pub fn rotate_left(&mut self, mid: usize) {
+ SliceExt::rotate_left(self, mid);
+ }
+
+ /// Rotates the slice in-place such that the first `self.len() - k`
+ /// elements of the slice move to the end while the last `k` elements move
+ /// to the front. After calling `rotate_right`, the element previously at
+ /// index `self.len() - k` will become the first element in the slice.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `k` is greater than the length of the
+ /// slice. Note that `k == self.len()` does _not_ panic and is a no-op
+ /// rotation.
+ ///
+ /// # Complexity
+ ///
+ /// Takes linear (in `self.len()`) time.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
+ /// a.rotate_right(2);
+ /// assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']);
+ /// ```
+ ///
+ /// Rotate a subslice:
+ ///
+ /// ```
+ /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
+ /// a[1..5].rotate_right(1);
+ /// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']);
+ /// ```
+ #[stable(feature = "slice_rotate", since = "1.26.0")]
+ pub fn rotate_right(&mut self, k: usize) {
+ SliceExt::rotate_right(self, k);
+ }
+
+ /// Copies the elements from `src` into `self`.
+ ///
+ /// The length of `src` must be the same as `self`.
+ ///
+ /// If `src` implements `Copy`, it can be more performant to use
+ /// [`copy_from_slice`].
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the two slices have different lengths.
+ ///
+ /// # Examples
+ ///
+ /// Cloning two elements from a slice into another:
+ ///
+ /// ```
+ /// let src = [1, 2, 3, 4];
+ /// let mut dst = [0, 0];
+ ///
+ /// dst.clone_from_slice(&src[2..]);
+ ///
+ /// assert_eq!(src, [1, 2, 3, 4]);
+ /// assert_eq!(dst, [3, 4]);
+ /// ```
+ ///
+ /// Rust enforces that there can only be one mutable reference with no
+ /// immutable references to a particular piece of data in a particular
+ /// scope. Because of this, attempting to use `clone_from_slice` on a
+ /// single slice will result in a compile failure:
+ ///
+ /// ```compile_fail
+ /// let mut slice = [1, 2, 3, 4, 5];
+ ///
+ /// slice[..2].clone_from_slice(&slice[3..]); // compile fail!
+ /// ```
+ ///
+ /// To work around this, we can use [`split_at_mut`] to create two distinct
+ /// sub-slices from a slice:
+ ///
+ /// ```
+ /// let mut slice = [1, 2, 3, 4, 5];
+ ///
+ /// {
+ /// let (left, right) = slice.split_at_mut(2);
+ /// left.clone_from_slice(&right[1..]);
+ /// }
+ ///
+ /// assert_eq!(slice, [4, 5, 3, 4, 5]);
+ /// ```
+ ///
+ /// [`copy_from_slice`]: #method.copy_from_slice
+ /// [`split_at_mut`]: #method.split_at_mut
+ #[stable(feature = "clone_from_slice", since = "1.7.0")]
+ pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone {
+ SliceExt::clone_from_slice(self, src)
+ }
+
+ /// Copies all elements from `src` into `self`, using a memcpy.
+ ///
+ /// The length of `src` must be the same as `self`.
+ ///
+ /// If `src` does not implement `Copy`, use [`clone_from_slice`].
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the two slices have different lengths.
+ ///
+ /// # Examples
+ ///
+ /// Copying two elements from a slice into another:
+ ///
+ /// ```
+ /// let src = [1, 2, 3, 4];
+ /// let mut dst = [0, 0];
+ ///
+ /// dst.copy_from_slice(&src[2..]);
+ ///
+ /// assert_eq!(src, [1, 2, 3, 4]);
+ /// assert_eq!(dst, [3, 4]);
+ /// ```
+ ///
+ /// Rust enforces that there can only be one mutable reference with no
+ /// immutable references to a particular piece of data in a particular
+ /// scope. Because of this, attempting to use `copy_from_slice` on a
+ /// single slice will result in a compile failure:
+ ///
+ /// ```compile_fail
+ /// let mut slice = [1, 2, 3, 4, 5];
+ ///
+ /// slice[..2].copy_from_slice(&slice[3..]); // compile fail!
+ /// ```
+ ///
+ /// To work around this, we can use [`split_at_mut`] to create two distinct
+ /// sub-slices from a slice:
+ ///
+ /// ```
+ /// let mut slice = [1, 2, 3, 4, 5];
+ ///
+ /// {
+ /// let (left, right) = slice.split_at_mut(2);
+ /// left.copy_from_slice(&right[1..]);
+ /// }
+ ///
+ /// assert_eq!(slice, [4, 5, 3, 4, 5]);
+ /// ```
+ ///
+ /// [`clone_from_slice`]: #method.clone_from_slice
+ /// [`split_at_mut`]: #method.split_at_mut
+ #[stable(feature = "copy_from_slice", since = "1.9.0")]
+ pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy {
+ SliceExt::copy_from_slice(self, src)
+ }
+
+ /// Swaps all elements in `self` with those in `other`.
+ ///
+ /// The length of `other` must be the same as `self`.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the two slices have different lengths.
+ ///
+ /// # Example
+ ///
+ /// Swapping two elements across slices:
+ ///
+ /// ```
+ /// let mut slice1 = [0, 0];
+ /// let mut slice2 = [1, 2, 3, 4];
+ ///
+ /// slice1.swap_with_slice(&mut slice2[2..]);
+ ///
+ /// assert_eq!(slice1, [3, 4]);
+ /// assert_eq!(slice2, [1, 2, 0, 0]);
+ /// ```
+ ///
+ /// Rust enforces that there can only be one mutable reference to a
+ /// particular piece of data in a particular scope. Because of this,
+ /// attempting to use `swap_with_slice` on a single slice will result in
+ /// a compile failure:
+ ///
+ /// ```compile_fail
+ /// let mut slice = [1, 2, 3, 4, 5];
+ /// slice[..2].swap_with_slice(&mut slice[3..]); // compile fail!
+ /// ```
+ ///
+ /// To work around this, we can use [`split_at_mut`] to create two distinct
+ /// mutable sub-slices from a slice:
+ ///
+ /// ```
+ /// let mut slice = [1, 2, 3, 4, 5];
+ ///
+ /// {
+ /// let (left, right) = slice.split_at_mut(2);
+ /// left.swap_with_slice(&mut right[1..]);
+ /// }
+ ///
+ /// assert_eq!(slice, [4, 5, 3, 1, 2]);
+ /// ```
+ ///
+ /// [`split_at_mut`]: #method.split_at_mut
+ #[stable(feature = "swap_with_slice", since = "1.27.0")]
+ pub fn swap_with_slice(&mut self, other: &mut [T]) {
+ SliceExt::swap_with_slice(self, other)
+ }
+}}
+
+#[lang = "slice"]
+#[cfg(not(test))]
+#[cfg(not(stage0))]
+impl<T> [T] {
+ slice_core_methods!();
+}
+
+// FIXME: remove (inline) this macro
+// when updating to a bootstrap compiler that has the new lang items.
+#[cfg_attr(stage0, macro_export)]
+#[unstable(feature = "core_slice_ext", issue = "32110")]
+macro_rules! slice_u8_core_methods { () => {
+ /// Checks if all bytes in this slice are within the ASCII range.
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[inline]
+ pub fn is_ascii(&self) -> bool {
+ self.iter().all(|b| b.is_ascii())
+ }
+
+ /// Checks that two slices are an ASCII case-insensitive match.
+ ///
+ /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
+ /// but without allocating and copying temporaries.
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[inline]
+ pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
+ self.len() == other.len() &&
+ self.iter().zip(other).all(|(a, b)| {
+ a.eq_ignore_ascii_case(b)
+ })
+ }
+
+ /// Converts this slice to its ASCII upper case equivalent in-place.
+ ///
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new uppercased value without modifying the existing one, use
+ /// [`to_ascii_uppercase`].
+ ///
+ /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[inline]
+ pub fn make_ascii_uppercase(&mut self) {
+ for byte in self {
+ byte.make_ascii_uppercase();
+ }
+ }
+
+ /// Converts this slice to its ASCII lower case equivalent in-place.
+ ///
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new lowercased value without modifying the existing one, use
+ /// [`to_ascii_lowercase`].
+ ///
+ /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[inline]
+ pub fn make_ascii_lowercase(&mut self) {
+ for byte in self {
+ byte.make_ascii_lowercase();
+ }
+ }
+}}
+
+#[lang = "slice_u8"]
+#[cfg(not(test))]
+#[cfg(not(stage0))]
+impl [u8] {
+ slice_u8_core_methods!();
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"]
impl<T, I> ops::Index<I> for [T]
fn index(self, slice: &str) -> &Self::Output {
assert!(self.end != usize::max_value(),
"attempted to index str up to maximum usize");
- let end = self.end + 1;
- self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end))
+ (..self.end+1).index(slice)
}
#[inline]
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
assert!(self.end != usize::max_value(),
"attempted to index str up to maximum usize");
- if slice.is_char_boundary(self.end) {
- unsafe { self.get_unchecked_mut(slice) }
- } else {
- super::slice_error_fail(slice, 0, self.end + 1)
- }
+ (..self.end+1).index_mut(slice)
}
}
}
-
+public_in_stage0! {
+{
/// Methods for string slices
#[allow(missing_docs)]
#[doc(hidden)]
#[unstable(feature = "core_str_ext",
reason = "stable interface provided by `impl str` in later crates",
issue = "32110")]
-pub trait StrExt {
+}
+trait StrExt {
// NB there are no docs here are they're all located on the StrExt trait in
// liballoc, not here.
fn parse<T: FromStr>(&self) -> Result<T, T::Err>;
#[stable(feature = "split_whitespace", since = "1.1.0")]
fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>;
- #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")]
- fn is_whitespace(&self) -> bool;
- #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")]
- fn is_alphanumeric(&self) -> bool;
#[stable(feature = "rust1", since = "1.0.0")]
fn trim(&self) -> &str;
#[stable(feature = "rust1", since = "1.0.0")]
fn trim_left(&self) -> &str;
#[stable(feature = "rust1", since = "1.0.0")]
fn trim_right(&self) -> &str;
-}
+}}
// truncate `&str` to length at most equal to `max`
// return `true` if it were truncated, and the new str.
SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) }
}
- #[inline]
- fn is_whitespace(&self) -> bool {
- self.chars().all(|c| c.is_whitespace())
- }
-
- #[inline]
- fn is_alphanumeric(&self) -> bool {
- self.chars().all(|c| c.is_alphanumeric())
- }
-
#[inline]
fn trim(&self) -> &str {
self.trim_matches(|c: char| c.is_whitespace())
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsRef<[u8]> for str {
+// FIXME: remove (inline) this macro and the SliceExt trait
+// when updating to a bootstrap compiler that has the new lang items.
+#[cfg_attr(stage0, macro_export)]
+#[unstable(feature = "core_str_ext", issue = "32110")]
+macro_rules! str_core_methods { () => {
+ /// Returns the length of `self`.
+ ///
+ /// This length is in bytes, not [`char`]s or graphemes. In other words,
+ /// it may not be what a human considers the length of the string.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let len = "foo".len();
+ /// assert_eq!(3, len);
+ ///
+ /// let len = "ƒoo".len(); // fancy f!
+ /// assert_eq!(4, len);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- fn as_ref(&self) -> &[u8] {
- self.as_bytes()
+ pub fn len(&self) -> usize {
+ StrExt::len(self)
}
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Default for &'a str {
- /// Creates an empty str
- fn default() -> &'a str { "" }
-}
+ /// Returns `true` if `self` has a length of zero bytes.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = "";
+ /// assert!(s.is_empty());
+ ///
+ /// let s = "not empty";
+ /// assert!(!s.is_empty());
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_empty(&self) -> bool {
+ StrExt::is_empty(self)
+ }
-/// An iterator over the non-whitespace substrings of a string,
-/// separated by any amount of whitespace.
-///
-/// This struct is created by the [`split_whitespace`] method on [`str`].
-/// See its documentation for more.
-///
-/// [`split_whitespace`]: ../../std/primitive.str.html#method.split_whitespace
-/// [`str`]: ../../std/primitive.str.html
-#[stable(feature = "split_whitespace", since = "1.1.0")]
-#[derive(Clone, Debug)]
-pub struct SplitWhitespace<'a> {
- inner: Filter<Split<'a, IsWhitespace>, IsNotEmpty>,
-}
+ /// Checks that `index`-th byte lies at the start and/or end of a
+ /// UTF-8 code point sequence.
+ ///
+ /// The start and end of the string (when `index == self.len()`) are
+ /// considered to be
+ /// boundaries.
+ ///
+ /// Returns `false` if `index` is greater than `self.len()`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ /// assert!(s.is_char_boundary(0));
+ /// // start of `老`
+ /// assert!(s.is_char_boundary(6));
+ /// assert!(s.is_char_boundary(s.len()));
+ ///
+ /// // second byte of `ö`
+ /// assert!(!s.is_char_boundary(2));
+ ///
+ /// // third byte of `老`
+ /// assert!(!s.is_char_boundary(8));
+ /// ```
+ #[stable(feature = "is_char_boundary", since = "1.9.0")]
+ #[inline]
+ pub fn is_char_boundary(&self, index: usize) -> bool {
+ StrExt::is_char_boundary(self, index)
+ }
-#[derive(Clone)]
-struct IsWhitespace;
+ /// Converts a string slice to a byte slice. To convert the byte slice back
+ /// into a string slice, use the [`str::from_utf8`] function.
+ ///
+ /// [`str::from_utf8`]: ./str/fn.from_utf8.html
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let bytes = "bors".as_bytes();
+ /// assert_eq!(b"bors", bytes);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline(always)]
+ pub fn as_bytes(&self) -> &[u8] {
+ StrExt::as_bytes(self)
+ }
-impl FnOnce<(char, )> for IsWhitespace {
- type Output = bool;
+ /// Converts a mutable string slice to a mutable byte slice. To convert the
+ /// mutable byte slice back into a mutable string slice, use the
+ /// [`str::from_utf8_mut`] function.
+ ///
+ /// [`str::from_utf8_mut`]: ./str/fn.from_utf8_mut.html
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let mut s = String::from("Hello");
+ /// let bytes = unsafe { s.as_bytes_mut() };
+ ///
+ /// assert_eq!(b"Hello", bytes);
+ /// ```
+ ///
+ /// Mutability:
+ ///
+ /// ```
+ /// let mut s = String::from("🗻∈🌏");
+ ///
+ /// unsafe {
+ /// let bytes = s.as_bytes_mut();
+ ///
+ /// bytes[0] = 0xF0;
+ /// bytes[1] = 0x9F;
+ /// bytes[2] = 0x8D;
+ /// bytes[3] = 0x94;
+ /// }
+ ///
+ /// assert_eq!("🍔∈🌏", s);
+ /// ```
+ #[stable(feature = "str_mut_extras", since = "1.20.0")]
+ #[inline(always)]
+ pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
+ StrExt::as_bytes_mut(self)
+ }
+ /// Converts a string slice to a raw pointer.
+ ///
+ /// As string slices are a slice of bytes, the raw pointer points to a
+ /// [`u8`]. This pointer will be pointing to the first byte of the string
+ /// slice.
+ ///
+ /// [`u8`]: primitive.u8.html
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = "Hello";
+ /// let ptr = s.as_ptr();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- extern "rust-call" fn call_once(mut self, arg: (char, )) -> bool {
- self.call_mut(arg)
+ pub fn as_ptr(&self) -> *const u8 {
+ StrExt::as_ptr(self)
}
-}
-impl FnMut<(char, )> for IsWhitespace {
+ /// Returns a subslice of `str`.
+ ///
+ /// This is the non-panicking alternative to indexing the `str`. Returns
+ /// [`None`] whenever equivalent indexing operation would panic.
+ ///
+ /// [`None`]: option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = String::from("🗻∈🌏");
+ ///
+ /// assert_eq!(Some("🗻"), v.get(0..4));
+ ///
+ /// // indices not on UTF-8 sequence boundaries
+ /// assert!(v.get(1..).is_none());
+ /// assert!(v.get(..8).is_none());
+ ///
+ /// // out of bounds
+ /// assert!(v.get(..42).is_none());
+ /// ```
+ #[stable(feature = "str_checked_slicing", since = "1.20.0")]
#[inline]
- extern "rust-call" fn call_mut(&mut self, arg: (char, )) -> bool {
- arg.0.is_whitespace()
+ pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
+ StrExt::get(self, i)
}
-}
-
-#[derive(Clone)]
-struct IsNotEmpty;
-impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty {
- type Output = bool;
+ /// Returns a mutable subslice of `str`.
+ ///
+ /// This is the non-panicking alternative to indexing the `str`. Returns
+ /// [`None`] whenever equivalent indexing operation would panic.
+ ///
+ /// [`None`]: option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = String::from("hello");
+ /// // correct length
+ /// assert!(v.get_mut(0..5).is_some());
+ /// // out of bounds
+ /// assert!(v.get_mut(..42).is_none());
+ /// assert_eq!(Some("he"), v.get_mut(0..2).map(|v| &*v));
+ ///
+ /// assert_eq!("hello", v);
+ /// {
+ /// let s = v.get_mut(0..2);
+ /// let s = s.map(|s| {
+ /// s.make_ascii_uppercase();
+ /// &*s
+ /// });
+ /// assert_eq!(Some("HE"), s);
+ /// }
+ /// assert_eq!("HEllo", v);
+ /// ```
+ #[stable(feature = "str_checked_slicing", since = "1.20.0")]
+ #[inline]
+ pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
+ StrExt::get_mut(self, i)
+ }
+ /// Returns a unchecked subslice of `str`.
+ ///
+ /// This is the unchecked alternative to indexing the `str`.
+ ///
+ /// # Safety
+ ///
+ /// Callers of this function are responsible that these preconditions are
+ /// satisfied:
+ ///
+ /// * The starting index must come before the ending index;
+ /// * Indexes must be within bounds of the original slice;
+ /// * Indexes must lie on UTF-8 sequence boundaries.
+ ///
+ /// Failing that, the returned string slice may reference invalid memory or
+ /// violate the invariants communicated by the `str` type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = "🗻∈🌏";
+ /// unsafe {
+ /// assert_eq!("🗻", v.get_unchecked(0..4));
+ /// assert_eq!("∈", v.get_unchecked(4..7));
+ /// assert_eq!("🌏", v.get_unchecked(7..11));
+ /// }
+ /// ```
+ #[stable(feature = "str_checked_slicing", since = "1.20.0")]
#[inline]
- extern "rust-call" fn call_once(mut self, arg: (&&str, )) -> bool {
- self.call_mut(arg)
+ pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
+ StrExt::get_unchecked(self, i)
}
-}
-impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty {
+ /// Returns a mutable, unchecked subslice of `str`.
+ ///
+ /// This is the unchecked alternative to indexing the `str`.
+ ///
+ /// # Safety
+ ///
+ /// Callers of this function are responsible that these preconditions are
+ /// satisfied:
+ ///
+ /// * The starting index must come before the ending index;
+ /// * Indexes must be within bounds of the original slice;
+ /// * Indexes must lie on UTF-8 sequence boundaries.
+ ///
+ /// Failing that, the returned string slice may reference invalid memory or
+ /// violate the invariants communicated by the `str` type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = String::from("🗻∈🌏");
+ /// unsafe {
+ /// assert_eq!("🗻", v.get_unchecked_mut(0..4));
+ /// assert_eq!("∈", v.get_unchecked_mut(4..7));
+ /// assert_eq!("🌏", v.get_unchecked_mut(7..11));
+ /// }
+ /// ```
+ #[stable(feature = "str_checked_slicing", since = "1.20.0")]
#[inline]
- extern "rust-call" fn call_mut(&mut self, arg: (&&str, )) -> bool {
- !arg.0.is_empty()
+ pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
+ StrExt::get_unchecked_mut(self, i)
}
-}
+ /// Creates a string slice from another string slice, bypassing safety
+ /// checks.
+ ///
+ /// This is generally not recommended, use with caution! For a safe
+ /// alternative see [`str`] and [`Index`].
+ ///
+ /// [`str`]: primitive.str.html
+ /// [`Index`]: ops/trait.Index.html
+ ///
+ /// This new slice goes from `begin` to `end`, including `begin` but
+ /// excluding `end`.
+ ///
+ /// To get a mutable string slice instead, see the
+ /// [`slice_mut_unchecked`] method.
+ ///
+ /// [`slice_mut_unchecked`]: #method.slice_mut_unchecked
+ ///
+ /// # Safety
+ ///
+ /// Callers of this function are responsible that three preconditions are
+ /// satisfied:
+ ///
+ /// * `begin` must come before `end`.
+ /// * `begin` and `end` must be byte positions within the string slice.
+ /// * `begin` and `end` must lie on UTF-8 sequence boundaries.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ ///
+ /// unsafe {
+ /// assert_eq!("Löwe 老虎 Léopard", s.slice_unchecked(0, 21));
+ /// }
+ ///
+ /// let s = "Hello, world!";
+ ///
+ /// unsafe {
+ /// assert_eq!("world", s.slice_unchecked(7, 12));
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
+ StrExt::slice_unchecked(self, begin, end)
+ }
-#[stable(feature = "split_whitespace", since = "1.1.0")]
-impl<'a> Iterator for SplitWhitespace<'a> {
- type Item = &'a str;
+ /// Creates a string slice from another string slice, bypassing safety
+ /// checks.
+ /// This is generally not recommended, use with caution! For a safe
+ /// alternative see [`str`] and [`IndexMut`].
+ ///
+ /// [`str`]: primitive.str.html
+ /// [`IndexMut`]: ops/trait.IndexMut.html
+ ///
+ /// This new slice goes from `begin` to `end`, including `begin` but
+ /// excluding `end`.
+ ///
+ /// To get an immutable string slice instead, see the
+ /// [`slice_unchecked`] method.
+ ///
+ /// [`slice_unchecked`]: #method.slice_unchecked
+ ///
+ /// # Safety
+ ///
+ /// Callers of this function are responsible that three preconditions are
+ /// satisfied:
+ ///
+ /// * `begin` must come before `end`.
+ /// * `begin` and `end` must be byte positions within the string slice.
+ /// * `begin` and `end` must lie on UTF-8 sequence boundaries.
+ #[stable(feature = "str_slice_mut", since = "1.5.0")]
+ #[inline]
+ pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
+ StrExt::slice_mut_unchecked(self, begin, end)
+ }
- fn next(&mut self) -> Option<&'a str> {
- self.inner.next()
+ /// Divide one string slice into two at an index.
+ ///
+ /// The argument, `mid`, should be a byte offset from the start of the
+ /// string. It must also be on the boundary of a UTF-8 code point.
+ ///
+ /// The two slices returned go from the start of the string slice to `mid`,
+ /// and from `mid` to the end of the string slice.
+ ///
+ /// To get mutable string slices instead, see the [`split_at_mut`]
+ /// method.
+ ///
+ /// [`split_at_mut`]: #method.split_at_mut
+ ///
+ /// # Panics
+ ///
+ /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is
+ /// beyond the last code point of the string slice.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = "Per Martin-Löf";
+ ///
+ /// let (first, last) = s.split_at(3);
+ ///
+ /// assert_eq!("Per", first);
+ /// assert_eq!(" Martin-Löf", last);
+ /// ```
+ #[inline]
+ #[stable(feature = "str_split_at", since = "1.4.0")]
+ pub fn split_at(&self, mid: usize) -> (&str, &str) {
+ StrExt::split_at(self, mid)
}
-}
-#[stable(feature = "split_whitespace", since = "1.1.0")]
-impl<'a> DoubleEndedIterator for SplitWhitespace<'a> {
- fn next_back(&mut self) -> Option<&'a str> {
- self.inner.next_back()
+ /// Divide one mutable string slice into two at an index.
+ ///
+ /// The argument, `mid`, should be a byte offset from the start of the
+ /// string. It must also be on the boundary of a UTF-8 code point.
+ ///
+ /// The two slices returned go from the start of the string slice to `mid`,
+ /// and from `mid` to the end of the string slice.
+ ///
+ /// To get immutable string slices instead, see the [`split_at`] method.
+ ///
+ /// [`split_at`]: #method.split_at
+ ///
+ /// # Panics
+ ///
+ /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is
+ /// beyond the last code point of the string slice.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let mut s = "Per Martin-Löf".to_string();
+ /// {
+ /// let (first, last) = s.split_at_mut(3);
+ /// first.make_ascii_uppercase();
+ /// assert_eq!("PER", first);
+ /// assert_eq!(" Martin-Löf", last);
+ /// }
+ /// assert_eq!("PER Martin-Löf", s);
+ /// ```
+ #[inline]
+ #[stable(feature = "str_split_at", since = "1.4.0")]
+ pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
+ StrExt::split_at_mut(self, mid)
}
-}
-#[stable(feature = "fused", since = "1.26.0")]
-impl<'a> FusedIterator for SplitWhitespace<'a> {}
+ /// Returns an iterator over the [`char`]s of a string slice.
+ ///
+ /// As a string slice consists of valid UTF-8, we can iterate through a
+ /// string slice by [`char`]. This method returns such an iterator.
+ ///
+ /// It's important to remember that [`char`] represents a Unicode Scalar
+ /// Value, and may not match your idea of what a 'character' is. Iteration
+ /// over grapheme clusters may be what you actually want.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let word = "goodbye";
+ ///
+ /// let count = word.chars().count();
+ /// assert_eq!(7, count);
+ ///
+ /// let mut chars = word.chars();
+ ///
+ /// assert_eq!(Some('g'), chars.next());
+ /// assert_eq!(Some('o'), chars.next());
+ /// assert_eq!(Some('o'), chars.next());
+ /// assert_eq!(Some('d'), chars.next());
+ /// assert_eq!(Some('b'), chars.next());
+ /// assert_eq!(Some('y'), chars.next());
+ /// assert_eq!(Some('e'), chars.next());
+ ///
+ /// assert_eq!(None, chars.next());
+ /// ```
+ ///
+ /// Remember, [`char`]s may not match your human intuition about characters:
+ ///
+ /// ```
+ /// let y = "y̆";
+ ///
+ /// let mut chars = y.chars();
+ ///
+ /// assert_eq!(Some('y'), chars.next()); // not 'y̆'
+ /// assert_eq!(Some('\u{0306}'), chars.next());
+ ///
+ /// assert_eq!(None, chars.next());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn chars(&self) -> Chars {
+ StrExt::chars(self)
+ }
+ /// Returns an iterator over the [`char`]s of a string slice, and their
+ /// positions.
+ ///
+ /// As a string slice consists of valid UTF-8, we can iterate through a
+ /// string slice by [`char`]. This method returns an iterator of both
+ /// these [`char`]s, as well as their byte positions.
+ ///
+ /// The iterator yields tuples. The position is first, the [`char`] is
+ /// second.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let word = "goodbye";
+ ///
+ /// let count = word.char_indices().count();
+ /// assert_eq!(7, count);
+ ///
+ /// let mut char_indices = word.char_indices();
+ ///
+ /// assert_eq!(Some((0, 'g')), char_indices.next());
+ /// assert_eq!(Some((1, 'o')), char_indices.next());
+ /// assert_eq!(Some((2, 'o')), char_indices.next());
+ /// assert_eq!(Some((3, 'd')), char_indices.next());
+ /// assert_eq!(Some((4, 'b')), char_indices.next());
+ /// assert_eq!(Some((5, 'y')), char_indices.next());
+ /// assert_eq!(Some((6, 'e')), char_indices.next());
+ ///
+ /// assert_eq!(None, char_indices.next());
+ /// ```
+ ///
+ /// Remember, [`char`]s may not match your human intuition about characters:
+ ///
+ /// ```
+ /// let yes = "y̆es";
+ ///
+ /// let mut char_indices = yes.char_indices();
+ ///
+ /// assert_eq!(Some((0, 'y')), char_indices.next()); // not (0, 'y̆')
+ /// assert_eq!(Some((1, '\u{0306}')), char_indices.next());
+ ///
+ /// // note the 3 here - the last character took up two bytes
+ /// assert_eq!(Some((3, 'e')), char_indices.next());
+ /// assert_eq!(Some((4, 's')), char_indices.next());
+ ///
+ /// assert_eq!(None, char_indices.next());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn char_indices(&self) -> CharIndices {
+ StrExt::char_indices(self)
+ }
+
+ /// An iterator over the bytes of a string slice.
+ ///
+ /// As a string slice consists of a sequence of bytes, we can iterate
+ /// through a string slice by byte. This method returns such an iterator.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let mut bytes = "bors".bytes();
+ ///
+ /// assert_eq!(Some(b'b'), bytes.next());
+ /// assert_eq!(Some(b'o'), bytes.next());
+ /// assert_eq!(Some(b'r'), bytes.next());
+ /// assert_eq!(Some(b's'), bytes.next());
+ ///
+ /// assert_eq!(None, bytes.next());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn bytes(&self) -> Bytes {
+ StrExt::bytes(self)
+ }
+
+ /// Split a string slice by whitespace.
+ ///
+ /// The iterator returned will return string slices that are sub-slices of
+ /// the original string slice, separated by any amount of whitespace.
+ ///
+ /// 'Whitespace' is defined according to the terms of the Unicode Derived
+ /// Core Property `White_Space`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let mut iter = "A few words".split_whitespace();
+ ///
+ /// assert_eq!(Some("A"), iter.next());
+ /// assert_eq!(Some("few"), iter.next());
+ /// assert_eq!(Some("words"), iter.next());
+ ///
+ /// assert_eq!(None, iter.next());
+ /// ```
+ ///
+ /// All kinds of whitespace are considered:
+ ///
+ /// ```
+ /// let mut iter = " Mary had\ta\u{2009}little \n\t lamb".split_whitespace();
+ /// assert_eq!(Some("Mary"), iter.next());
+ /// assert_eq!(Some("had"), iter.next());
+ /// assert_eq!(Some("a"), iter.next());
+ /// assert_eq!(Some("little"), iter.next());
+ /// assert_eq!(Some("lamb"), iter.next());
+ ///
+ /// assert_eq!(None, iter.next());
+ /// ```
+ #[stable(feature = "split_whitespace", since = "1.1.0")]
+ #[inline]
+ pub fn split_whitespace(&self) -> SplitWhitespace {
+ StrExt::split_whitespace(self)
+ }
+
+ /// An iterator over the lines of a string, as string slices.
+ ///
+ /// Lines are ended with either a newline (`\n`) or a carriage return with
+ /// a line feed (`\r\n`).
+ ///
+ /// The final line ending is optional.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let text = "foo\r\nbar\n\nbaz\n";
+ /// let mut lines = text.lines();
+ ///
+ /// assert_eq!(Some("foo"), lines.next());
+ /// assert_eq!(Some("bar"), lines.next());
+ /// assert_eq!(Some(""), lines.next());
+ /// assert_eq!(Some("baz"), lines.next());
+ ///
+ /// assert_eq!(None, lines.next());
+ /// ```
+ ///
+ /// The final line ending isn't required:
+ ///
+ /// ```
+ /// let text = "foo\nbar\n\r\nbaz";
+ /// let mut lines = text.lines();
+ ///
+ /// assert_eq!(Some("foo"), lines.next());
+ /// assert_eq!(Some("bar"), lines.next());
+ /// assert_eq!(Some(""), lines.next());
+ /// assert_eq!(Some("baz"), lines.next());
+ ///
+ /// assert_eq!(None, lines.next());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn lines(&self) -> Lines {
+ StrExt::lines(self)
+ }
+
+ /// An iterator over the lines of a string.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_deprecated(since = "1.4.0", reason = "use lines() instead now")]
+ #[inline]
+ #[allow(deprecated)]
+ pub fn lines_any(&self) -> LinesAny {
+ StrExt::lines_any(self)
+ }
+
+ /// Returns an iterator of `u16` over the string encoded as UTF-16.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let text = "Zażółć gęślą jaźń";
+ ///
+ /// let utf8_len = text.len();
+ /// let utf16_len = text.encode_utf16().count();
+ ///
+ /// assert!(utf16_len <= utf8_len);
+ /// ```
+ #[stable(feature = "encode_utf16", since = "1.8.0")]
+ pub fn encode_utf16(&self) -> EncodeUtf16 {
+ EncodeUtf16::new(self)
+ }
+
+ /// Returns `true` if the given pattern matches a sub-slice of
+ /// this string slice.
+ ///
+ /// Returns `false` if it does not.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let bananas = "bananas";
+ ///
+ /// assert!(bananas.contains("nana"));
+ /// assert!(!bananas.contains("apples"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
+ StrExt::contains(self, pat)
+ }
+
+ /// Returns `true` if the given pattern matches a prefix of this
+ /// string slice.
+ ///
+ /// Returns `false` if it does not.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let bananas = "bananas";
+ ///
+ /// assert!(bananas.starts_with("bana"));
+ /// assert!(!bananas.starts_with("nana"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
+ StrExt::starts_with(self, pat)
+ }
+
+ /// Returns `true` if the given pattern matches a suffix of this
+ /// string slice.
+ ///
+ /// Returns `false` if it does not.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let bananas = "bananas";
+ ///
+ /// assert!(bananas.ends_with("anas"));
+ /// assert!(!bananas.ends_with("nana"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ StrExt::ends_with(self, pat)
+ }
+
+ /// Returns the byte index of the first character of this string slice that
+ /// matches the pattern.
+ ///
+ /// Returns [`None`] if the pattern doesn't match.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines if
+ /// a character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ /// [`None`]: option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ ///
+ /// assert_eq!(s.find('L'), Some(0));
+ /// assert_eq!(s.find('é'), Some(14));
+ /// assert_eq!(s.find("Léopard"), Some(13));
+ /// ```
+ ///
+ /// More complex patterns using point-free style and closures:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ ///
+ /// assert_eq!(s.find(char::is_whitespace), Some(5));
+ /// assert_eq!(s.find(char::is_lowercase), Some(1));
+ /// assert_eq!(s.find(|c: char| c.is_whitespace() || c.is_lowercase()), Some(1));
+ /// assert_eq!(s.find(|c: char| (c < 'o') && (c > 'a')), Some(4));
+ /// ```
+ ///
+ /// Not finding the pattern:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ /// let x: &[_] = &['1', '2'];
+ ///
+ /// assert_eq!(s.find(x), None);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
+ StrExt::find(self, pat)
+ }
+
+ /// Returns the byte index of the last character of this string slice that
+ /// matches the pattern.
+ ///
+ /// Returns [`None`] if the pattern doesn't match.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines if
+ /// a character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ /// [`None`]: option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ ///
+ /// assert_eq!(s.rfind('L'), Some(13));
+ /// assert_eq!(s.rfind('é'), Some(14));
+ /// ```
+ ///
+ /// More complex patterns with closures:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ ///
+ /// assert_eq!(s.rfind(char::is_whitespace), Some(12));
+ /// assert_eq!(s.rfind(char::is_lowercase), Some(20));
+ /// ```
+ ///
+ /// Not finding the pattern:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ /// let x: &[_] = &['1', '2'];
+ ///
+ /// assert_eq!(s.rfind(x), None);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ StrExt::rfind(self, pat)
+ }
+
+ /// An iterator over substrings of this string slice, separated by
+ /// characters matched by a pattern.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines the
+ /// split.
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
+ /// allows a reverse search and forward/reverse search yields the same
+ /// elements. This is true for, eg, [`char`] but not for `&str`.
+ ///
+ /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
+ ///
+ /// If the pattern allows a reverse search but its results might differ
+ /// from a forward search, the [`rsplit`] method can be used.
+ ///
+ /// [`char`]: primitive.char.html
+ /// [`rsplit`]: #method.rsplit
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect();
+ /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
+ ///
+ /// let v: Vec<&str> = "".split('X').collect();
+ /// assert_eq!(v, [""]);
+ ///
+ /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect();
+ /// assert_eq!(v, ["lion", "", "tiger", "leopard"]);
+ ///
+ /// let v: Vec<&str> = "lion::tiger::leopard".split("::").collect();
+ /// assert_eq!(v, ["lion", "tiger", "leopard"]);
+ ///
+ /// let v: Vec<&str> = "abc1def2ghi".split(char::is_numeric).collect();
+ /// assert_eq!(v, ["abc", "def", "ghi"]);
+ ///
+ /// let v: Vec<&str> = "lionXtigerXleopard".split(char::is_uppercase).collect();
+ /// assert_eq!(v, ["lion", "tiger", "leopard"]);
+ /// ```
+ ///
+ /// A more complex pattern, using a closure:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "abc1defXghi".split(|c| c == '1' || c == 'X').collect();
+ /// assert_eq!(v, ["abc", "def", "ghi"]);
+ /// ```
+ ///
+ /// If a string contains multiple contiguous separators, you will end up
+ /// with empty strings in the output:
+ ///
+ /// ```
+ /// let x = "||||a||b|c".to_string();
+ /// let d: Vec<_> = x.split('|').collect();
+ ///
+ /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]);
+ /// ```
+ ///
+ /// Contiguous separators are separated by the empty string.
+ ///
+ /// ```
+ /// let x = "(///)".to_string();
+ /// let d: Vec<_> = x.split('/').collect();
+ ///
+ /// assert_eq!(d, &["(", "", "", ")"]);
+ /// ```
+ ///
+ /// Separators at the start or end of a string are neighbored
+ /// by empty strings.
+ ///
+ /// ```
+ /// let d: Vec<_> = "010".split("0").collect();
+ /// assert_eq!(d, &["", "1", ""]);
+ /// ```
+ ///
+ /// When the empty string is used as a separator, it separates
+ /// every character in the string, along with the beginning
+ /// and end of the string.
+ ///
+ /// ```
+ /// let f: Vec<_> = "rust".split("").collect();
+ /// assert_eq!(f, &["", "r", "u", "s", "t", ""]);
+ /// ```
+ ///
+ /// Contiguous separators can lead to possibly surprising behavior
+ /// when whitespace is used as the separator. This code is correct:
+ ///
+ /// ```
+ /// let x = " a b c".to_string();
+ /// let d: Vec<_> = x.split(' ').collect();
+ ///
+ /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]);
+ /// ```
+ ///
+ /// It does _not_ give you:
+ ///
+ /// ```,ignore
+ /// assert_eq!(d, &["a", "b", "c"]);
+ /// ```
+ ///
+ /// Use [`split_whitespace`] for this behavior.
+ ///
+ /// [`split_whitespace`]: #method.split_whitespace
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
+ StrExt::split(self, pat)
+ }
+
+ /// An iterator over substrings of the given string slice, separated by
+ /// characters matched by a pattern and yielded in reverse order.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines the
+ /// split.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator requires that the pattern supports a reverse
+ /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
+ /// search yields the same elements.
+ ///
+ /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
+ ///
+ /// For iterating from the front, the [`split`] method can be used.
+ ///
+ /// [`split`]: #method.split
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect();
+ /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]);
+ ///
+ /// let v: Vec<&str> = "".rsplit('X').collect();
+ /// assert_eq!(v, [""]);
+ ///
+ /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect();
+ /// assert_eq!(v, ["leopard", "tiger", "", "lion"]);
+ ///
+ /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect();
+ /// assert_eq!(v, ["leopard", "tiger", "lion"]);
+ /// ```
+ ///
+ /// A more complex pattern, using a closure:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "abc1defXghi".rsplit(|c| c == '1' || c == 'X').collect();
+ /// assert_eq!(v, ["ghi", "def", "abc"]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ StrExt::rsplit(self, pat)
+ }
+
+ /// An iterator over substrings of the given string slice, separated by
+ /// characters matched by a pattern.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines the
+ /// split.
+ ///
+ /// Equivalent to [`split`], except that the trailing substring
+ /// is skipped if empty.
+ ///
+ /// [`split`]: #method.split
+ ///
+ /// This method can be used for string data that is _terminated_,
+ /// rather than _separated_ by a pattern.
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
+ /// allows a reverse search and forward/reverse search yields the same
+ /// elements. This is true for, eg, [`char`] but not for `&str`.
+ ///
+ /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
+ /// [`char`]: primitive.char.html
+ ///
+ /// If the pattern allows a reverse search but its results might differ
+ /// from a forward search, the [`rsplit_terminator`] method can be used.
+ ///
+ /// [`rsplit_terminator`]: #method.rsplit_terminator
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "A.B.".split_terminator('.').collect();
+ /// assert_eq!(v, ["A", "B"]);
+ ///
+ /// let v: Vec<&str> = "A..B..".split_terminator(".").collect();
+ /// assert_eq!(v, ["A", "", "B", ""]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> {
+ StrExt::split_terminator(self, pat)
+ }
+
+ /// An iterator over substrings of `self`, separated by characters
+ /// matched by a pattern and yielded in reverse order.
+ ///
+ /// The pattern can be a simple `&str`, [`char`], or a closure that
+ /// determines the split.
+ /// Additional libraries might provide more complex patterns like
+ /// regular expressions.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// Equivalent to [`split`], except that the trailing substring is
+ /// skipped if empty.
+ ///
+ /// [`split`]: #method.split
+ ///
+ /// This method can be used for string data that is _terminated_,
+ /// rather than _separated_ by a pattern.
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator requires that the pattern supports a
+ /// reverse search, and it will be double ended if a forward/reverse
+ /// search yields the same elements.
+ ///
+ /// For iterating from the front, the [`split_terminator`] method can be
+ /// used.
+ ///
+ /// [`split_terminator`]: #method.split_terminator
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v: Vec<&str> = "A.B.".rsplit_terminator('.').collect();
+ /// assert_eq!(v, ["B", "A"]);
+ ///
+ /// let v: Vec<&str> = "A..B..".rsplit_terminator(".").collect();
+ /// assert_eq!(v, ["", "B", "", "A"]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ StrExt::rsplit_terminator(self, pat)
+ }
+
+ /// An iterator over substrings of the given string slice, separated by a
+ /// pattern, restricted to returning at most `n` items.
+ ///
+ /// If `n` substrings are returned, the last substring (the `n`th substring)
+ /// will contain the remainder of the string.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines the
+ /// split.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator will not be double ended, because it is
+ /// not efficient to support.
+ ///
+ /// If the pattern allows a reverse search, the [`rsplitn`] method can be
+ /// used.
+ ///
+ /// [`rsplitn`]: #method.rsplitn
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "Mary had a little lambda".splitn(3, ' ').collect();
+ /// assert_eq!(v, ["Mary", "had", "a little lambda"]);
+ ///
+ /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(3, "X").collect();
+ /// assert_eq!(v, ["lion", "", "tigerXleopard"]);
+ ///
+ /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect();
+ /// assert_eq!(v, ["abcXdef"]);
+ ///
+ /// let v: Vec<&str> = "".splitn(1, 'X').collect();
+ /// assert_eq!(v, [""]);
+ /// ```
+ ///
+ /// A more complex pattern, using a closure:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "abc1defXghi".splitn(2, |c| c == '1' || c == 'X').collect();
+ /// assert_eq!(v, ["abc", "defXghi"]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> {
+ StrExt::splitn(self, n, pat)
+ }
+
+ /// An iterator over substrings of this string slice, separated by a
+ /// pattern, starting from the end of the string, restricted to returning
+ /// at most `n` items.
+ ///
+ /// If `n` substrings are returned, the last substring (the `n`th substring)
+ /// will contain the remainder of the string.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that
+ /// determines the split.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator will not be double ended, because it is not
+ /// efficient to support.
+ ///
+ /// For splitting from the front, the [`splitn`] method can be used.
+ ///
+ /// [`splitn`]: #method.splitn
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect();
+ /// assert_eq!(v, ["lamb", "little", "Mary had a"]);
+ ///
+ /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(3, 'X').collect();
+ /// assert_eq!(v, ["leopard", "tiger", "lionX"]);
+ ///
+ /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect();
+ /// assert_eq!(v, ["leopard", "lion::tiger"]);
+ /// ```
+ ///
+ /// A more complex pattern, using a closure:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "abc1defXghi".rsplitn(2, |c| c == '1' || c == 'X').collect();
+ /// assert_eq!(v, ["ghi", "abc1def"]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ StrExt::rsplitn(self, n, pat)
+ }
+
+ /// An iterator over the disjoint matches of a pattern within the given string
+ /// slice.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that
+ /// determines if a character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
+ /// allows a reverse search and forward/reverse search yields the same
+ /// elements. This is true for, eg, [`char`] but not for `&str`.
+ ///
+ /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
+ /// [`char`]: primitive.char.html
+ ///
+ /// If the pattern allows a reverse search but its results might differ
+ /// from a forward search, the [`rmatches`] method can be used.
+ ///
+ /// [`rmatches`]: #method.rmatches
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect();
+ /// assert_eq!(v, ["abc", "abc", "abc"]);
+ ///
+ /// let v: Vec<&str> = "1abc2abc3".matches(char::is_numeric).collect();
+ /// assert_eq!(v, ["1", "2", "3"]);
+ /// ```
+ #[stable(feature = "str_matches", since = "1.2.0")]
+ #[inline]
+ pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
+ StrExt::matches(self, pat)
+ }
+
+ /// An iterator over the disjoint matches of a pattern within this string slice,
+ /// yielded in reverse order.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines if
+ /// a character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator requires that the pattern supports a reverse
+ /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
+ /// search yields the same elements.
+ ///
+ /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
+ ///
+ /// For iterating from the front, the [`matches`] method can be used.
+ ///
+ /// [`matches`]: #method.matches
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "abcXXXabcYYYabc".rmatches("abc").collect();
+ /// assert_eq!(v, ["abc", "abc", "abc"]);
+ ///
+ /// let v: Vec<&str> = "1abc2abc3".rmatches(char::is_numeric).collect();
+ /// assert_eq!(v, ["3", "2", "1"]);
+ /// ```
+ #[stable(feature = "str_matches", since = "1.2.0")]
+ #[inline]
+ pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ StrExt::rmatches(self, pat)
+ }
+
+ /// An iterator over the disjoint matches of a pattern within this string
+ /// slice as well as the index that the match starts at.
+ ///
+ /// For matches of `pat` within `self` that overlap, only the indices
+ /// corresponding to the first match are returned.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines
+ /// if a character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
+ /// allows a reverse search and forward/reverse search yields the same
+ /// elements. This is true for, eg, [`char`] but not for `&str`.
+ ///
+ /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
+ ///
+ /// If the pattern allows a reverse search but its results might differ
+ /// from a forward search, the [`rmatch_indices`] method can be used.
+ ///
+ /// [`rmatch_indices`]: #method.rmatch_indices
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect();
+ /// assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]);
+ ///
+ /// let v: Vec<_> = "1abcabc2".match_indices("abc").collect();
+ /// assert_eq!(v, [(1, "abc"), (4, "abc")]);
+ ///
+ /// let v: Vec<_> = "ababa".match_indices("aba").collect();
+ /// assert_eq!(v, [(0, "aba")]); // only the first `aba`
+ /// ```
+ #[stable(feature = "str_match_indices", since = "1.5.0")]
+ #[inline]
+ pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
+ StrExt::match_indices(self, pat)
+ }
+
+ /// An iterator over the disjoint matches of a pattern within `self`,
+ /// yielded in reverse order along with the index of the match.
+ ///
+ /// For matches of `pat` within `self` that overlap, only the indices
+ /// corresponding to the last match are returned.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines if a
+ /// character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator requires that the pattern supports a reverse
+ /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
+ /// search yields the same elements.
+ ///
+ /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
+ ///
+ /// For iterating from the front, the [`match_indices`] method can be used.
+ ///
+ /// [`match_indices`]: #method.match_indices
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_indices("abc").collect();
+ /// assert_eq!(v, [(12, "abc"), (6, "abc"), (0, "abc")]);
+ ///
+ /// let v: Vec<_> = "1abcabc2".rmatch_indices("abc").collect();
+ /// assert_eq!(v, [(4, "abc"), (1, "abc")]);
+ ///
+ /// let v: Vec<_> = "ababa".rmatch_indices("aba").collect();
+ /// assert_eq!(v, [(2, "aba")]); // only the last `aba`
+ /// ```
+ #[stable(feature = "str_match_indices", since = "1.5.0")]
+ #[inline]
+ pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ StrExt::rmatch_indices(self, pat)
+ }
+
+ /// Returns a string slice with leading and trailing whitespace removed.
+ ///
+ /// 'Whitespace' is defined according to the terms of the Unicode Derived
+ /// Core Property `White_Space`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = " Hello\tworld\t";
+ ///
+ /// assert_eq!("Hello\tworld", s.trim());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn trim(&self) -> &str {
+ StrExt::trim(self)
+ }
+
+ /// Returns a string slice with leading whitespace removed.
+ ///
+ /// 'Whitespace' is defined according to the terms of the Unicode Derived
+ /// Core Property `White_Space`.
+ ///
+ /// # Text directionality
+ ///
+ /// A string is a sequence of bytes. 'Left' in this context means the first
+ /// position of that byte string; for a language like Arabic or Hebrew
+ /// which are 'right to left' rather than 'left to right', this will be
+ /// the _right_ side, not the left.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = " Hello\tworld\t";
+ ///
+ /// assert_eq!("Hello\tworld\t", s.trim_left());
+ /// ```
+ ///
+ /// Directionality:
+ ///
+ /// ```
+ /// let s = " English";
+ /// assert!(Some('E') == s.trim_left().chars().next());
+ ///
+ /// let s = " עברית";
+ /// assert!(Some('ע') == s.trim_left().chars().next());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn trim_left(&self) -> &str {
+ StrExt::trim_left(self)
+ }
+
+ /// Returns a string slice with trailing whitespace removed.
+ ///
+ /// 'Whitespace' is defined according to the terms of the Unicode Derived
+ /// Core Property `White_Space`.
+ ///
+ /// # Text directionality
+ ///
+ /// A string is a sequence of bytes. 'Right' in this context means the last
+ /// position of that byte string; for a language like Arabic or Hebrew
+ /// which are 'right to left' rather than 'left to right', this will be
+ /// the _left_ side, not the right.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = " Hello\tworld\t";
+ ///
+ /// assert_eq!(" Hello\tworld", s.trim_right());
+ /// ```
+ ///
+ /// Directionality:
+ ///
+ /// ```
+ /// let s = "English ";
+ /// assert!(Some('h') == s.trim_right().chars().rev().next());
+ ///
+ /// let s = "עברית ";
+ /// assert!(Some('ת') == s.trim_right().chars().rev().next());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn trim_right(&self) -> &str {
+ StrExt::trim_right(self)
+ }
+
+ /// Returns a string slice with all prefixes and suffixes that match a
+ /// pattern repeatedly removed.
+ ///
+ /// The pattern can be a [`char`] or a closure that determines if a
+ /// character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar");
+ /// assert_eq!("123foo1bar123".trim_matches(char::is_numeric), "foo1bar");
+ ///
+ /// let x: &[_] = &['1', '2'];
+ /// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar");
+ /// ```
+ ///
+ /// A more complex pattern, using a closure:
+ ///
+ /// ```
+ /// assert_eq!("1foo1barXX".trim_matches(|c| c == '1' || c == 'X'), "foo1bar");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
+ where P::Searcher: DoubleEndedSearcher<'a>
+ {
+ StrExt::trim_matches(self, pat)
+ }
+
+ /// Returns a string slice with all prefixes that match a pattern
+ /// repeatedly removed.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines if
+ /// a character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Text directionality
+ ///
+ /// A string is a sequence of bytes. 'Left' in this context means the first
+ /// position of that byte string; for a language like Arabic or Hebrew
+ /// which are 'right to left' rather than 'left to right', this will be
+ /// the _right_ side, not the left.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11");
+ /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123");
+ ///
+ /// let x: &[_] = &['1', '2'];
+ /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
+ StrExt::trim_left_matches(self, pat)
+ }
+
+ /// Returns a string slice with all suffixes that match a pattern
+ /// repeatedly removed.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that
+ /// determines if a character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Text directionality
+ ///
+ /// A string is a sequence of bytes. 'Right' in this context means the last
+ /// position of that byte string; for a language like Arabic or Hebrew
+ /// which are 'right to left' rather than 'left to right', this will be
+ /// the _left_ side, not the right.
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar");
+ /// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar");
+ ///
+ /// let x: &[_] = &['1', '2'];
+ /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar");
+ /// ```
+ ///
+ /// A more complex pattern, using a closure:
+ ///
+ /// ```
+ /// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ StrExt::trim_right_matches(self, pat)
+ }
+
+ /// Parses this string slice into another type.
+ ///
+ /// Because `parse` is so general, it can cause problems with type
+ /// inference. As such, `parse` is one of the few times you'll see
+ /// the syntax affectionately known as the 'turbofish': `::<>`. This
+ /// helps the inference algorithm understand specifically which type
+ /// you're trying to parse into.
+ ///
+ /// `parse` can parse any type that implements the [`FromStr`] trait.
+ ///
+ /// [`FromStr`]: str/trait.FromStr.html
+ ///
+ /// # Errors
+ ///
+ /// Will return [`Err`] if it's not possible to parse this string slice into
+ /// the desired type.
+ ///
+ /// [`Err`]: str/trait.FromStr.html#associatedtype.Err
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// let four: u32 = "4".parse().unwrap();
+ ///
+ /// assert_eq!(4, four);
+ /// ```
+ ///
+ /// Using the 'turbofish' instead of annotating `four`:
+ ///
+ /// ```
+ /// let four = "4".parse::<u32>();
+ ///
+ /// assert_eq!(Ok(4), four);
+ /// ```
+ ///
+ /// Failing to parse:
+ ///
+ /// ```
+ /// let nope = "j".parse::<u32>();
+ ///
+ /// assert!(nope.is_err());
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
+ StrExt::parse(self)
+ }
+
+ /// Checks if all characters in this string are within the ASCII range.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let ascii = "hello!\n";
+ /// let non_ascii = "Grüße, Jürgen ❤";
+ ///
+ /// assert!(ascii.is_ascii());
+ /// assert!(!non_ascii.is_ascii());
+ /// ```
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[inline]
+ pub fn is_ascii(&self) -> bool {
+ // We can treat each byte as character here: all multibyte characters
+ // start with a byte that is not in the ascii range, so we will stop
+ // there already.
+ self.bytes().all(|b| b.is_ascii())
+ }
+
+ /// Checks that two strings are an ASCII case-insensitive match.
+ ///
+ /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
+ /// but without allocating and copying temporaries.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// assert!("Ferris".eq_ignore_ascii_case("FERRIS"));
+ /// assert!("Ferrös".eq_ignore_ascii_case("FERRöS"));
+ /// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS"));
+ /// ```
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[inline]
+ pub fn eq_ignore_ascii_case(&self, other: &str) -> bool {
+ self.as_bytes().eq_ignore_ascii_case(other.as_bytes())
+ }
+
+ /// Converts this string to its ASCII upper case equivalent in-place.
+ ///
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new uppercased value without modifying the existing one, use
+ /// [`to_ascii_uppercase`].
+ ///
+ /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ pub fn make_ascii_uppercase(&mut self) {
+ let me = unsafe { self.as_bytes_mut() };
+ me.make_ascii_uppercase()
+ }
+
+ /// Converts this string to its ASCII lower case equivalent in-place.
+ ///
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new lowercased value without modifying the existing one, use
+ /// [`to_ascii_lowercase`].
+ ///
+ /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ pub fn make_ascii_lowercase(&mut self) {
+ let me = unsafe { self.as_bytes_mut() };
+ me.make_ascii_lowercase()
+ }
+}}
+
+#[lang = "str"]
+#[cfg(not(test))]
+#[cfg(not(stage0))]
+impl str {
+ str_core_methods!();
+}
+
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<[u8]> for str {
+ #[inline]
+ fn as_ref(&self) -> &[u8] {
+ self.as_bytes()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Default for &'a str {
+ /// Creates an empty str
+ fn default() -> &'a str { "" }
+}
+
+/// An iterator over the non-whitespace substrings of a string,
+/// separated by any amount of whitespace.
+///
+/// This struct is created by the [`split_whitespace`] method on [`str`].
+/// See its documentation for more.
+///
+/// [`split_whitespace`]: ../../std/primitive.str.html#method.split_whitespace
+/// [`str`]: ../../std/primitive.str.html
+#[stable(feature = "split_whitespace", since = "1.1.0")]
+#[derive(Clone, Debug)]
+pub struct SplitWhitespace<'a> {
+ inner: Filter<Split<'a, IsWhitespace>, IsNotEmpty>,
+}
+
+#[derive(Clone)]
+struct IsWhitespace;
+
+impl FnOnce<(char, )> for IsWhitespace {
+ type Output = bool;
+
+ #[inline]
+ extern "rust-call" fn call_once(mut self, arg: (char, )) -> bool {
+ self.call_mut(arg)
+ }
+}
+
+impl FnMut<(char, )> for IsWhitespace {
+ #[inline]
+ extern "rust-call" fn call_mut(&mut self, arg: (char, )) -> bool {
+ arg.0.is_whitespace()
+ }
+}
+
+#[derive(Clone)]
+struct IsNotEmpty;
+
+impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty {
+ type Output = bool;
+
+ #[inline]
+ extern "rust-call" fn call_once(mut self, arg: (&&str, )) -> bool {
+ self.call_mut(arg)
+ }
+}
+
+impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty {
+ #[inline]
+ extern "rust-call" fn call_mut(&mut self, arg: (&&str, )) -> bool {
+ !arg.0.is_empty()
+ }
+}
+
+
+#[stable(feature = "split_whitespace", since = "1.1.0")]
+impl<'a> Iterator for SplitWhitespace<'a> {
+ type Item = &'a str;
+
+ fn next(&mut self) -> Option<&'a str> {
+ self.inner.next()
+ }
+}
+
+#[stable(feature = "split_whitespace", since = "1.1.0")]
+impl<'a> DoubleEndedIterator for SplitWhitespace<'a> {
+ fn next_back(&mut self) -> Option<&'a str> {
+ self.inner.next_back()
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<'a> FusedIterator for SplitWhitespace<'a> {}
+
+/// An iterator of [`u16`] over the string encoded as UTF-16.
+///
+/// [`u16`]: ../../std/primitive.u16.html
+///
+/// This struct is created by the [`encode_utf16`] method on [`str`].
+/// See its documentation for more.
+///
+/// [`encode_utf16`]: ../../std/primitive.str.html#method.encode_utf16
+/// [`str`]: ../../std/primitive.str.html
+#[derive(Clone)]
+#[stable(feature = "encode_utf16", since = "1.8.0")]
+pub struct EncodeUtf16<'a> {
+ chars: Chars<'a>,
+ extra: u16,
+}
+
+// FIXME: remove (inline) this method
+// when updating to a bootstrap compiler that has the new lang items.
+// For grepping purpose: #[cfg(stage0)]
+impl<'a> EncodeUtf16<'a> {
+ #[unstable(feature = "core_str_ext", issue = "32110")]
+ #[doc(hidden)]
+ pub fn new(s: &'a str) -> Self {
+ EncodeUtf16 { chars: s.chars(), extra: 0 }
+ }
+}
+
+#[stable(feature = "collection_debug", since = "1.17.0")]
+impl<'a> fmt::Debug for EncodeUtf16<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.pad("EncodeUtf16 { .. }")
+ }
+}
+
+#[stable(feature = "encode_utf16", since = "1.8.0")]
+impl<'a> Iterator for EncodeUtf16<'a> {
+ type Item = u16;
+
+ #[inline]
+ fn next(&mut self) -> Option<u16> {
+ if self.extra != 0 {
+ let tmp = self.extra;
+ self.extra = 0;
+ return Some(tmp);
+ }
+
+ let mut buf = [0; 2];
+ self.chars.next().map(|ch| {
+ let n = ch.encode_utf16(&mut buf).len();
+ if n == 2 {
+ self.extra = buf[1];
+ }
+ buf[0]
+ })
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (low, high) = self.chars.size_hint();
+ // every char gets either one u16 or two u16,
+ // so this iterator is between 1 or 2 times as
+ // long as the underlying iterator.
+ (low, high.and_then(|n| n.checked_mul(2)))
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<'a> FusedIterator for EncodeUtf16<'a> {}
assert!(y.get() == (30, 40));
}
+#[test]
+fn cell_update() {
+ let x = Cell::new(10);
+
+ assert_eq!(x.update(|x| x + 5), 15);
+ assert_eq!(x.get(), 15);
+
+ assert_eq!(x.update(|x| x / 3), 5);
+ assert_eq!(x.get(), 5);
+}
+
#[test]
fn cell_has_sensible_show() {
let x = Cell::new("foo bar");
}
#[test]
+#[allow(deprecated)]
fn test_decode_utf8() {
macro_rules! assert_decode_utf8 {
($input_bytes: expr, $expected_str: expr) => {
#![feature(ascii_ctype)]
#![feature(box_syntax)]
+#![feature(cell_update)]
#![feature(core_float)]
#![feature(core_private_bignum)]
#![feature(core_private_diy_float)]
#![feature(dec2flt)]
#![feature(decode_utf8)]
+#![feature(euclidean_division)]
#![feature(exact_size_is_empty)]
#![feature(fixed_size_array)]
+#![feature(float_internals)]
#![feature(flt2dec)]
#![feature(fmt_internals)]
#![feature(hashmap_internals)]
#![feature(str_internals)]
#![feature(test)]
#![feature(trusted_len)]
+#![feature(try_from)]
#![feature(try_trait)]
#![feature(exact_chunks)]
#![cfg_attr(stage0, feature(atomic_nand))]
num::test_num(10 as $T, 2 as $T);
}
+ #[test]
+ fn test_mod_euc() {
+ assert!((-1 as $T).mod_euc(MIN) == MAX);
+ }
+
#[test]
pub fn test_abs() {
assert!((1 as $T).abs() == 1 as $T);
[input] Features,
[] ProgramClausesFor(DefId),
+ [] ProgramClausesForEnv(ParamEnv<'tcx>),
[] WasmImportModuleMap(CrateNum),
[] ForeignModules(CrateNum),
// information we encapsulate into
let def_data = match i.node {
ItemKind::Impl(..) => DefPathData::Impl,
+ ItemKind::Trait(..) => DefPathData::Trait(i.ident.name.as_str()),
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) |
- ItemKind::Trait(..) | ItemKind::TraitAlias(..) |
+ ItemKind::TraitAlias(..) |
ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
DefPathData::TypeNs(i.ident.name.as_str()),
ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
let def_data = match ti.node {
TraitItemKind::Method(..) | TraitItemKind::Const(..) =>
DefPathData::ValueNs(ti.ident.name.as_str()),
- TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name.as_str()),
+ TraitItemKind::Type(..) => DefPathData::AssocTypeInTrait(ti.ident.name.as_str()),
TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false),
};
let def_data = match ii.node {
ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
DefPathData::ValueNs(ii.ident.name.as_str()),
- ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name.as_str()),
+ ImplItemKind::Type(..) => DefPathData::AssocTypeInImpl(ii.ident.name.as_str()),
ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false),
};
::std::mem::discriminant(data).hash(&mut hasher);
match *data {
DefPathData::TypeNs(name) |
+ DefPathData::Trait(name) |
+ DefPathData::AssocTypeInTrait(name) |
+ DefPathData::AssocTypeInImpl(name) |
DefPathData::ValueNs(name) |
DefPathData::Module(name) |
DefPathData::MacroDef(name) |
// Different kinds of items and item-like things:
/// An impl
Impl,
+ /// A trait
+ Trait(InternedString),
+ /// An associated type **declaration** (i.e., in a trait)
+ AssocTypeInTrait(InternedString),
+ /// An associated type **value** (i.e., in an impl)
+ AssocTypeInImpl(InternedString),
/// Something in the type NS
TypeNs(InternedString),
/// Something in the value NS
use self::DefPathData::*;
match *self {
TypeNs(name) |
+ Trait(name) |
+ AssocTypeInTrait(name) |
+ AssocTypeInImpl(name) |
ValueNs(name) |
Module(name) |
MacroDef(name) |
use self::DefPathData::*;
let s = match *self {
TypeNs(name) |
+ Trait(name) |
+ AssocTypeInTrait(name) |
+ AssocTypeInImpl(name) |
ValueNs(name) |
Module(name) |
MacroDef(name) |
}
);
-impl_stable_hash_for!(struct infer::canonical::QueryRegionConstraints<'tcx> {
- region_outlives, ty_outlives
-});
-
impl_stable_hash_for!(enum infer::canonical::Certainty {
Proven, Ambiguous
});
quantifier.hash_stable(hcx, hasher);
goal.hash_stable(hcx, hasher);
},
+ CannotProve => { },
}
}
}
use ty::{self, CanonicalVar, Lift, Region, Slice, Ty, TyCtxt, TypeFlags};
use ty::subst::{Kind, UnpackedKind};
use ty::fold::{TypeFoldable, TypeFolder};
-use util::captures::Captures;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::fx::FxHashMap;
#[derive(Clone, Debug)]
pub struct QueryResult<'tcx, R> {
pub var_values: CanonicalVarValues<'tcx>,
- pub region_constraints: QueryRegionConstraints<'tcx>,
+ pub region_constraints: Vec<QueryRegionConstraint<'tcx>>,
pub certainty: Certainty,
pub value: R,
}
}
}
-/// Subset of `RegionConstraintData` produced by trait query.
-#[derive(Clone, Debug, Default)]
-pub struct QueryRegionConstraints<'tcx> {
- pub region_outlives: Vec<(Region<'tcx>, Region<'tcx>)>,
- pub ty_outlives: Vec<(Ty<'tcx>, Region<'tcx>)>,
-}
+pub type QueryRegionConstraint<'tcx> = ty::Binder<ty::OutlivesPredicate<Kind<'tcx>, Region<'tcx>>>;
/// Trait implemented by values that can be canonicalized. It mainly
/// serves to identify the interning table we will use.
&'a self,
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- unsubstituted_region_constraints: &'a QueryRegionConstraints<'tcx>,
+ unsubstituted_region_constraints: &'a [QueryRegionConstraint<'tcx>],
result_subst: &'a CanonicalVarValues<'tcx>,
- ) -> impl Iterator<Item = PredicateObligation<'tcx>> + Captures<'gcx> + 'a {
- let QueryRegionConstraints {
- region_outlives,
- ty_outlives,
- } = unsubstituted_region_constraints;
-
- let region_obligations = region_outlives.iter().map(move |(r1, r2)| {
- let r1 = substitute_value(self.tcx, result_subst, r1);
- let r2 = substitute_value(self.tcx, result_subst, r2);
- Obligation::new(
- cause.clone(),
- param_env,
- ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r1, r2))),
- )
- });
-
- let ty_obligations = ty_outlives.iter().map(move |(t1, r2)| {
- let t1 = substitute_value(self.tcx, result_subst, t1);
+ ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a {
+ Box::new(unsubstituted_region_constraints.iter().map(move |constraint| {
+ let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below
+ let k1 = substitute_value(self.tcx, result_subst, k1);
let r2 = substitute_value(self.tcx, result_subst, r2);
- Obligation::new(
- cause.clone(),
- param_env,
- ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t1, r2))),
- )
- });
-
- region_obligations.chain(ty_obligations)
+ match k1.unpack() {
+ UnpackedKind::Lifetime(r1) =>
+ Obligation::new(
+ cause.clone(),
+ param_env,
+ ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r1, r2))),
+ ),
+
+ UnpackedKind::Type(t1) =>
+ Obligation::new(
+ cause.clone(),
+ param_env,
+ ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t1, r2))),
+ ),
+ }
+ })) as Box<dyn Iterator<Item = _>>
}
/// Given two sets of values for the same set of canonical variables, unify them.
}
}
-BraceStructTypeFoldableImpl! {
- impl<'tcx> TypeFoldable<'tcx> for QueryRegionConstraints<'tcx> {
- region_outlives, ty_outlives
- }
-}
-
-BraceStructLiftImpl! {
- impl<'a, 'tcx> Lift<'tcx> for QueryRegionConstraints<'a> {
- type Lifted = QueryRegionConstraints<'tcx>;
- region_outlives, ty_outlives
- }
-}
-
BraceStructTypeFoldableImpl! {
impl<'tcx, R> TypeFoldable<'tcx> for QueryResult<'tcx, R> {
var_values, region_constraints, certainty, value
#![cfg_attr(windows, feature(libc))]
#![feature(macro_lifetime_matcher)]
#![feature(macro_vis_matcher)]
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![feature(non_exhaustive)]
#![feature(nonzero)]
"suggest using `dyn Trait` for trait objects"
}
+declare_lint! {
+ pub ABSOLUTE_PATH_STARTING_WITH_MODULE,
+ Allow,
+ "fully qualified paths that start with a module name \
+ instead of `crate`, `self`, or an extern crate name"
+}
+
declare_lint! {
pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
Warn,
TYVAR_BEHIND_RAW_POINTER,
ELIDED_LIFETIME_IN_PATH,
BARE_TRAIT_OBJECT,
+ ABSOLUTE_PATH_STARTING_WITH_MODULE,
UNSTABLE_NAME_COLLISION,
)
}
#[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
pub enum BuiltinLintDiagnostics {
Normal,
- BareTraitObject(Span, /* is_global */ bool)
+ BareTraitObject(Span, /* is_global */ bool),
+ AbsPathWithModule(Span),
}
impl BuiltinLintDiagnostics {
};
db.span_suggestion(span, "use `dyn`", sugg);
}
+ BuiltinLintDiagnostics::AbsPathWithModule(span) => {
+ let sugg = match sess.codemap().span_to_snippet(span) {
+ Ok(ref s) => {
+ // FIXME(Manishearth) ideally the emitting code
+ // can tell us whether or not this is global
+ let opt_colon = if s.trim_left().starts_with("::") {
+ ""
+ } else {
+ "::"
+ };
+
+ format!("crate{}{}", opt_colon, s)
+ }
+ Err(_) => format!("crate::<path>")
+ };
+ db.span_suggestion(span, "use `crate`", sugg);
+ }
}
}
}
StrImplItem, "str", str_impl;
SliceImplItem, "slice", slice_impl;
SliceU8ImplItem, "slice_u8", slice_u8_impl;
+ StrAllocImplItem, "str_alloc", str_alloc_impl;
+ SliceAllocImplItem, "slice_alloc", slice_alloc_impl;
+ SliceU8AllocImplItem, "slice_u8_alloc", slice_u8_alloc_impl;
ConstPtrImplItem, "const_ptr", const_ptr_impl;
MutPtrImplItem, "mut_ptr", mut_ptr_impl;
I8ImplItem, "i8", i8_impl;
UsizeImplItem, "usize", usize_impl;
F32ImplItem, "f32", f32_impl;
F64ImplItem, "f64", f64_impl;
+ F32RuntimeImplItem, "f32_runtime", f32_runtime_impl;
+ F64RuntimeImplItem, "f64_runtime", f64_runtime_impl;
SizedTraitLangItem, "sized", sized_trait;
UnsizeTraitLangItem, "unsize", unsize_trait;
ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn;
BoxFreeFnLangItem, "box_free", box_free_fn;
- DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn;
+ DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn;
+ OomLangItem, "oom", oom;
StartFnLangItem, "start", start_fn;
b: hir::BodyId, s: Span, id: NodeId) {
visit_fn(self, fk, fd, b, s, id);
}
+
fn visit_local(&mut self, l: &'tcx hir::Local) { visit_local(self, l); }
fn visit_expr(&mut self, ex: &'tcx Expr) { visit_expr(self, ex); }
fn visit_arm(&mut self, a: &'tcx hir::Arm) { visit_arm(self, a); }
// swap in a new set of IR maps for this function body:
let mut fn_maps = IrMaps::new(ir.tcx);
+ // Don't run unused pass for #[derive()]
+ if let FnKind::Method(..) = fk {
+ let parent = ir.tcx.hir.get_parent(id);
+ if let Some(hir::map::Node::NodeItem(i)) = ir.tcx.hir.find(parent) {
+ if i.attrs.iter().any(|a| a.check_name("automatically_derived")) {
+ return;
+ }
+ }
+ }
+
debug!("creating fn_maps: {:?}", &fn_maps as *const IrMaps);
let body = ir.tcx.hir.body(body_id);
use std::fmt;
use std::mem;
+use rustc_data_structures::small_vec::SmallVec;
use rustc_data_structures::sync::Lrc;
use syntax::codemap;
use syntax::ast;
-> Scope {
if scope_a == scope_b { return scope_a; }
- // [1] The initial values for `a_buf` and `b_buf` are not used.
- // The `ancestors_of` function will return some prefix that
- // is re-initialized with new values (or else fallback to a
- // heap-allocated vector).
- let mut a_buf: [Scope; 32] = [scope_a /* [1] */; 32];
- let mut a_vec: Vec<Scope> = vec![];
- let mut b_buf: [Scope; 32] = [scope_b /* [1] */; 32];
- let mut b_vec: Vec<Scope> = vec![];
- let parent_map = &self.parent_map;
- let a_ancestors = ancestors_of(parent_map, scope_a, &mut a_buf, &mut a_vec);
- let b_ancestors = ancestors_of(parent_map, scope_b, &mut b_buf, &mut b_vec);
- let mut a_index = a_ancestors.len() - 1;
- let mut b_index = b_ancestors.len() - 1;
-
- // Here, [ab]_ancestors is a vector going from narrow to broad.
- // The end of each vector will be the item where the scope is
- // defined; if there are any common ancestors, then the tails of
- // the vector will be the same. So basically we want to walk
- // backwards from the tail of each vector and find the first point
- // where they diverge. If one vector is a suffix of the other,
- // then the corresponding scope is a superscope of the other.
-
- if a_ancestors[a_index] != b_ancestors[b_index] {
- // In this case, the two regions belong to completely
- // different functions. Compare those fn for lexical
- // nesting. The reasoning behind this is subtle. See the
- // "Modeling closures" section of the README in
- // infer::region_constraints for more details.
- let a_root_scope = a_ancestors[a_index];
- let b_root_scope = a_ancestors[a_index];
- return match (a_root_scope.data(), b_root_scope.data()) {
- (ScopeData::Destruction(a_root_id),
- ScopeData::Destruction(b_root_id)) => {
- if self.closure_is_enclosed_by(a_root_id, b_root_id) {
- // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a`
- scope_b
- } else if self.closure_is_enclosed_by(b_root_id, a_root_id) {
- // `b` is enclosed by `a`, hence `a` is the ancestor of everything in `b`
- scope_a
- } else {
- // neither fn encloses the other
- bug!()
- }
+ // Process the lists in tandem from the innermost scope, recording the
+ // scopes seen so far. The first scope that comes up for a second time
+ // is the nearest common ancestor.
+ //
+ // Note: another way to compute the nearest common ancestor is to get
+ // the full scope chain for both scopes and then compare the chains to
+ // find the first scope in a common tail. But getting a parent scope
+ // requires a hash table lookup, and we often have very long scope
+ // chains (10s or 100s of scopes) that only differ by a few elements at
+ // the start. So this algorithm is faster.
+ let mut ma = Some(scope_a);
+ let mut mb = Some(scope_b);
+ let mut seen: SmallVec<[Scope; 32]> = SmallVec::new();
+ loop {
+ if let Some(a) = ma {
+ if seen.iter().position(|s| *s == a).is_some() {
+ return a;
}
- _ => {
- // root ids are always Node right now
- bug!()
+ seen.push(a);
+ ma = self.parent_map.get(&a).map(|s| *s);
+ }
+
+ if let Some(b) = mb {
+ if seen.iter().position(|s| *s == b).is_some() {
+ return b;
}
- };
- }
+ seen.push(b);
+ mb = self.parent_map.get(&b).map(|s| *s);
+ }
- loop {
- // Loop invariant: a_ancestors[a_index] == b_ancestors[b_index]
- // for all indices between a_index and the end of the array
- if a_index == 0 { return scope_a; }
- if b_index == 0 { return scope_b; }
- a_index -= 1;
- b_index -= 1;
- if a_ancestors[a_index] != b_ancestors[b_index] {
- return a_ancestors[a_index + 1];
+ if ma.is_none() && mb.is_none() {
+ break;
}
- }
+ };
- fn ancestors_of<'a, 'tcx>(parent_map: &FxHashMap<Scope, Scope>,
- scope: Scope,
- buf: &'a mut [Scope; 32],
- vec: &'a mut Vec<Scope>)
- -> &'a [Scope] {
- // debug!("ancestors_of(scope={:?})", scope);
+ fn outermost_scope(parent_map: &FxHashMap<Scope, Scope>, scope: Scope) -> Scope {
let mut scope = scope;
-
- let mut i = 0;
- while i < 32 {
- buf[i] = scope;
- match parent_map.get(&scope) {
- Some(&superscope) => scope = superscope,
- _ => return &buf[..i+1]
- }
- i += 1;
+ loop {
+ match parent_map.get(&scope) {
+ Some(&superscope) => scope = superscope,
+ None => break scope,
+ }
}
+ }
- *vec = Vec::with_capacity(64);
- vec.extend_from_slice(buf);
- loop {
- vec.push(scope);
- match parent_map.get(&scope) {
- Some(&superscope) => scope = superscope,
- _ => return &*vec
+ // In this (rare) case, the two regions belong to completely different
+ // functions. Compare those fn for lexical nesting. The reasoning
+ // behind this is subtle. See the "Modeling closures" section of the
+ // README in infer::region_constraints for more details.
+ let a_root_scope = outermost_scope(&self.parent_map, scope_a);
+ let b_root_scope = outermost_scope(&self.parent_map, scope_b);
+ match (a_root_scope.data(), b_root_scope.data()) {
+ (ScopeData::Destruction(a_root_id),
+ ScopeData::Destruction(b_root_id)) => {
+ if self.closure_is_enclosed_by(a_root_id, b_root_id) {
+ // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a`
+ scope_b
+ } else if self.closure_is_enclosed_by(b_root_id, a_root_id) {
+ // `b` is enclosed by `a`, hence `a` is the ancestor of everything in `b`
+ scope_a
+ } else {
+ // neither fn encloses the other
+ bug!()
}
}
+ _ => {
+ // root ids are always Node right now
+ bug!()
+ }
}
}
panic_fmt, PanicFmtLangItem, rust_begin_unwind;
eh_personality, EhPersonalityLangItem, rust_eh_personality;
eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume;
+ oom, OomLangItem, rust_oom;
}
pub use self::Passes::*;
pub use self::DebugInfoLevel::*;
+use std::str::FromStr;
+
use session::{early_error, early_warn, Session};
use session::search_paths::SearchPaths;
use syntax::ast::{self, IntTy, UintTy};
use syntax::codemap::{FileName, FilePathMapping};
-use syntax::edition::Edition;
+use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
use syntax::parse::token;
use syntax::parse;
use syntax::symbol::Symbol;
// Remap source path prefixes in all output (messages, object files, debug, etc)
remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
+ edition: Edition [TRACKED],
}
);
cli_forced_codegen_units: None,
cli_forced_thinlto_off: false,
remap_path_prefix: Vec::new(),
+ edition: DEFAULT_EDITION,
}
}
Some("`string` or `string=string`");
pub const parse_lto: Option<&'static str> =
Some("one of `thin`, `fat`, or omitted");
- pub const parse_edition: Option<&'static str> =
- Some("one of: `2015`, `2018`");
}
#[allow(dead_code)]
use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto};
use rustc_back::{LinkerFlavor, PanicStrategy, RelroLevel};
use std::path::PathBuf;
- use syntax::edition::Edition;
$(
pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
true
}
- fn parse_edition(slot: &mut Edition, v: Option<&str>) -> bool {
- match v {
- Some(s) => {
- let edition = s.parse();
- if let Ok(parsed) = edition {
- *slot = parsed;
- true
- } else {
- false
- }
- }
- _ => false,
- }
- }
}
) }
`everybody_loops` (all function bodies replaced with `loop {}`),
`hir` (the HIR), `hir,identified`, or
`hir,typed` (HIR with types for each node)."),
- edition: Edition = (Edition::Edition2015, parse_edition, [TRACKED],
- "The edition to build Rust with. Newer editions may include features
- that require breaking changes. The default edition is 2015 (the first
- edition). Crates compiled with different editions can be linked together."),
run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
"run `dsymutil` and delete intermediate object files"),
ui_testing: bool = (false, parse_bool, [UNTRACKED],
"tell the linker to strip debuginfo when building without debuginfo enabled."),
share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
"make the current crate share its generic instantiations"),
+ chalk: bool = (false, parse_bool, [TRACKED],
+ "enable the experimental Chalk-based trait solving engine"),
}
pub fn default_lib_output() -> CrateType {
`expanded,identified` (fully parenthesized, AST nodes with IDs).",
"TYPE",
),
+ opt::opt_s(
+ "",
+ "edition",
+ "Specify which edition of the compiler to use when compiling code.",
+ EDITION_NAME_LIST,
+ ),
opt::multi_s(
"",
"remap-path-prefix",
),
};
+ let edition = match matches.opt_str("edition") {
+ Some(arg) => match Edition::from_str(&arg){
+ Ok(edition) => edition,
+ Err(_) => early_error(
+ ErrorOutputType::default(),
+ &format!(
+ "argument for --edition must be one of: \
+ {}. (instead was `{}`)",
+ EDITION_NAME_LIST,
+ arg
+ ),
+ ),
+ }
+ None => DEFAULT_EDITION,
+ };
+
+ if !edition.is_stable() && !nightly_options::is_nightly_build() {
+ early_error(
+ ErrorOutputType::default(),
+ &format!(
+ "Edition {} is unstable an only\
+ available for nightly builds of rustc.",
+ edition,
+ )
+ )
+ }
+
+
// We need the opts_present check because the driver will send us Matches
// with only stable options if no unstable options are used. Since error-format
// is unstable, it will not be present. We have to use opts_present not
cli_forced_codegen_units: codegen_units,
cli_forced_thinlto_off: disable_thinlto,
remap_path_prefix,
+ edition,
},
cfg,
)
use std::hash::Hash;
use std::path::PathBuf;
use std::collections::hash_map::DefaultHasher;
- use super::{CrateType, DebugInfoLevel, Edition, ErrorOutputType, Lto, OptLevel, OutputTypes,
+ use super::{CrateType, DebugInfoLevel, ErrorOutputType, Lto, OptLevel, OutputTypes,
Passes, Sanitizer};
use syntax::feature_gate::UnstableFeatures;
use rustc_back::{PanicStrategy, RelroLevel};
use rustc_back::target::TargetTriple;
+ use syntax::edition::Edition;
pub trait DepTrackingHash {
fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
impl_dep_tracking_hash_via_hash!(Sanitizer);
impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
- impl_dep_tracking_hash_via_hash!(Edition);
impl_dep_tracking_hash_via_hash!(TargetTriple);
+ impl_dep_tracking_hash_via_hash!(Edition);
impl_dep_tracking_hash_for_sortable_vec_of!(String);
impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
use super::{Externs, OutputType, OutputTypes};
use rustc_back::{PanicStrategy, RelroLevel};
use syntax::symbol::Symbol;
+ use syntax::edition::{Edition, DEFAULT_EDITION};
use syntax;
fn optgroups() -> getopts::Options {
opts.debugging_opts.relro_level = Some(RelroLevel::Full);
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
}
+
+ #[test]
+ fn test_edition_parsing() {
+ // test default edition
+ let options = super::basic_options();
+ assert!(options.edition == DEFAULT_EDITION);
+
+ let matches = optgroups()
+ .parse(&["--edition=2018".to_string()])
+ .unwrap();
+ let (sessopts, _) = build_session_options_and_crate_config(&matches);
+ assert!(sessopts.edition == Edition::Edition2018)
+ }
}
/// Are we allowed to use features from the Rust 2018 edition?
pub fn rust_2018(&self) -> bool {
- self.opts.debugging_opts.edition >= Edition::Edition2018
+ self.opts.edition >= Edition::Edition2018
}
pub fn edition(&self) -> Edition {
- self.opts.debugging_opts.edition
+ self.opts.edition
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Goal<'tcx> {
- Implies(&'tcx Slice<Clause<'tcx>>, &'tcx Goal<'tcx>),
+ Implies(Clauses<'tcx>, &'tcx Goal<'tcx>),
And(&'tcx Goal<'tcx>, &'tcx Goal<'tcx>),
Not(&'tcx Goal<'tcx>),
DomainGoal(DomainGoal<'tcx>),
- Quantified(QuantifierKind, ty::Binder<&'tcx Goal<'tcx>>)
+ Quantified(QuantifierKind, ty::Binder<&'tcx Goal<'tcx>>),
+ CannotProve,
}
+pub type Goals<'tcx> = &'tcx Slice<Goal<'tcx>>;
+
impl<'tcx> Goal<'tcx> {
pub fn from_poly_domain_goal<'a>(
domain_goal: PolyDomainGoal<'tcx>,
ForAll(ty::Binder<ProgramClause<'tcx>>),
}
+/// Multiple clauses.
+pub type Clauses<'tcx> = &'tcx Slice<Clause<'tcx>>;
+
/// A "program clause" has the form `D :- G1, ..., Gn`. It is saying
/// that the domain goal `D` is true if `G1...Gn` are provable. This
/// is equivalent to the implication `G1..Gn => D`; we usually write
pub goal: DomainGoal<'tcx>,
/// ...if we can prove these hypotheses (there may be no hypotheses at all):
- pub hypotheses: &'tcx Slice<Goal<'tcx>>,
+ pub hypotheses: Goals<'tcx>,
}
pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
// FIXME: appropriate binder names
write!(fmt, "{}<> {{ {} }}", qkind, goal.skip_binder())
}
+ CannotProve => write!(fmt, "CannotProve"),
}
}
}
(traits::Goal::Not)(goal),
(traits::Goal::DomainGoal)(domain_goal),
(traits::Goal::Quantified)(qkind, goal),
+ (traits::Goal::CannotProve),
}
}
use ty::ReprOptions;
use ty::Instance;
use traits;
-use traits::{Clause, Goal};
+use traits::{Clause, Clauses, Goal, Goals};
use ty::{self, Ty, TypeAndMut};
use ty::{TyS, TypeVariants, Slice};
use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorInterior, Region, Const};
self.intern_tup(&[])
}
+ pub fn mk_diverging_default(self) -> Ty<'tcx> {
+ if self.features().never_type {
+ self.types.never
+ } else {
+ self.intern_tup(&[])
+ }
+ }
+
pub fn mk_bool(self) -> Ty<'tcx> {
self.mk_ty(TyBool)
}
}
}
- pub fn intern_clauses(self, ts: &[Clause<'tcx>]) -> &'tcx Slice<Clause<'tcx>> {
+ pub fn intern_clauses(self, ts: &[Clause<'tcx>]) -> Clauses<'tcx> {
if ts.len() == 0 {
Slice::empty()
} else {
}
}
- pub fn intern_goals(self, ts: &[Goal<'tcx>]) -> &'tcx Slice<Goal<'tcx>> {
+ pub fn intern_goals(self, ts: &[Goal<'tcx>]) -> Goals<'tcx> {
if ts.len() == 0 {
Slice::empty()
} else {
self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from))
}
- pub fn mk_clauses<I: InternAs<[Clause<'tcx>],
- &'tcx Slice<Clause<'tcx>>>>(self, iter: I) -> I::Output {
+ pub fn mk_clauses<I: InternAs<[Clause<'tcx>], Clauses<'tcx>>>(self, iter: I) -> I::Output {
iter.intern_with(|xs| self.intern_clauses(xs))
}
- pub fn mk_goals<I: InternAs<[Goal<'tcx>],
- &'tcx Slice<Goal<'tcx>>>>(self, iter: I) -> I::Output {
+ pub fn mk_goals<I: InternAs<[Goal<'tcx>], Goals<'tcx>>>(self, iter: I) -> I::Output {
iter.intern_with(|xs| self.intern_goals(xs))
}
// finer-grained distinctions, e.g. between enum/struct).
data @ DefPathData::Misc |
data @ DefPathData::TypeNs(..) |
+ data @ DefPathData::Trait(..) |
+ data @ DefPathData::AssocTypeInTrait(..) |
+ data @ DefPathData::AssocTypeInImpl(..) |
data @ DefPathData::ValueNs(..) |
data @ DefPathData::Module(..) |
data @ DefPathData::TypeParam(..) |
}
}
+impl<'tcx> QueryDescription<'tcx> for queries::program_clauses_for_env<'tcx> {
+ fn describe(_tcx: TyCtxt, _: ty::ParamEnv<'tcx>) -> String {
+ format!("generating chalk-style clauses for param env")
+ }
+}
+
impl<'tcx> QueryDescription<'tcx> for queries::wasm_import_module_map<'tcx> {
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
format!("wasm import module map")
}
}
+impl<'tcx> Key for ty::ParamEnv<'tcx> {
+ fn map_crate(&self) -> CrateNum {
+ LOCAL_CRATE
+ }
+ fn default_span(&self, _: TyCtxt) -> Span {
+ DUMMY_SP
+ }
+}
+
impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
fn map_crate(&self) -> CrateNum {
self.value.map_crate()
use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
use traits::query::normalize::NormalizationResult;
use traits::specialization_graph;
-use traits::Clause;
-use ty::{self, CrateInherentImpls, ParamEnvAnd, Slice, Ty, TyCtxt};
+use traits::Clauses;
+use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
use ty::steal::Steal;
use ty::subst::Substs;
use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet};
[] fn features_query: features_node(CrateNum) -> Lrc<feature_gate::Features>,
- [] fn program_clauses_for: ProgramClausesFor(DefId) -> Lrc<&'tcx Slice<Clause<'tcx>>>,
+ [] fn program_clauses_for: ProgramClausesFor(DefId) -> Clauses<'tcx>,
+
+ [] fn program_clauses_for_env: ProgramClausesForEnv(
+ ty::ParamEnv<'tcx>
+ ) -> Clauses<'tcx>,
[] fn wasm_custom_sections: WasmCustomSections(CrateNum) -> Lrc<Vec<DefId>>,
[] fn wasm_import_module_map: WasmImportModuleMap(CrateNum)
DepKind::DropckOutlives |
DepKind::SubstituteNormalizeAndTestPredicates |
DepKind::InstanceDefSizeEstimate |
+ DepKind::ProgramClausesForEnv |
// This one should never occur in this context
DepKind::Null => {
pub type PolyProjectionPredicate<'tcx> = Binder<ProjectionPredicate<'tcx>>;
impl<'tcx> PolyProjectionPredicate<'tcx> {
+ /// Returns the def-id of the associated item being projected.
+ pub fn item_def_id(&self) -> DefId {
+ self.skip_binder().projection_ty.item_def_id
+ }
+
pub fn to_poly_trait_ref(&self, tcx: TyCtxt) -> PolyTraitRef<'tcx> {
// Note: unlike with TraitRef::to_poly_trait_ref(),
// self.0.trait_ref is permitted to have escaping regions.
loop {
let key = tcx.def_key(item_def_id);
match key.disambiguated_data.data {
+ DefPathData::AssocTypeInTrait(_) |
+ DefPathData::AssocTypeInImpl(_) |
+ DefPathData::Trait(_) |
DefPathData::TypeNs(_) => {
break;
}
- DefPathData::ValueNs(_) | DefPathData::EnumVariant(_) => {
+ DefPathData::ValueNs(_) |
+ DefPathData::EnumVariant(_) => {
is_value_path = true;
break;
}
- _ => {
+ DefPathData::CrateRoot |
+ DefPathData::Misc |
+ DefPathData::Impl |
+ DefPathData::Module(_) |
+ DefPathData::MacroDef(_) |
+ DefPathData::ClosureExpr |
+ DefPathData::TypeParam(_) |
+ DefPathData::LifetimeDef(_) |
+ DefPathData::Field(_) |
+ DefPathData::StructCtor |
+ DefPathData::Initializer |
+ DefPathData::ImplTrait |
+ DefPathData::Typeof |
+ DefPathData::GlobalMetaData(_) => {
// if we're making a symbol for something, there ought
// to be a value or type-def or something in there
// *somewhere*
self.cx.expr_ident(self.span, ident)
}
- AllocatorTy::ResultPtr | AllocatorTy::Bang | AllocatorTy::Unit => {
+ AllocatorTy::ResultPtr | AllocatorTy::Unit => {
panic!("can't convert AllocatorTy to an argument")
}
}
(self.ptr_u8(), expr)
}
- AllocatorTy::Bang => (self.cx.ty(self.span, TyKind::Never), expr),
-
AllocatorTy::Unit => (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr),
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
inputs: &[AllocatorTy::Layout],
output: AllocatorTy::ResultPtr,
},
- AllocatorMethod {
- name: "oom",
- inputs: &[],
- output: AllocatorTy::Bang,
- },
AllocatorMethod {
name: "dealloc",
inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout],
}
pub enum AllocatorTy {
- Bang,
Layout,
Ptr,
ResultPtr,
html_root_url = "https://doc.rust-lang.org/nightly/")]
#![forbid(unsafe_code)]
+#![feature(try_from)]
// See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
#[allow(unused_extern_crates)]
extern crate rustc_cratesio_shim;
base.is_like_android = true;
base.position_independent_executables = true;
base.has_elf_tls = false;
+ base.requires_uwtable = true;
base
}
/// Whether a .debug_gdb_scripts section will be added to the output object file
pub emit_debug_gdb_scripts: bool,
+
+ /// Whether or not to unconditionally `uwtable` attributes on functions,
+ /// typically because the platform needs to unwind for things like stack
+ /// unwinders.
+ pub requires_uwtable: bool,
}
impl Default for TargetOptions {
default_hidden_visibility: false,
embed_bitcode: false,
emit_debug_gdb_scripts: true,
+ requires_uwtable: false,
}
}
}
key!(default_hidden_visibility, bool);
key!(embed_bitcode, bool);
key!(emit_debug_gdb_scripts, bool);
+ key!(requires_uwtable, bool);
if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
for name in array.iter().filter_map(|abi| abi.as_string()) {
target_option_val!(default_hidden_visibility);
target_option_val!(embed_bitcode);
target_option_val!(emit_debug_gdb_scripts);
+ target_option_val!(requires_uwtable);
if default.abi_blacklist != self.options.abi_blacklist {
d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter()
custom_unwind_resume: true,
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
+ requires_uwtable: true,
.. Default::default()
}
crt_static_respected: true,
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
+ requires_uwtable: true,
.. Default::default()
}
krate,
&sess.parse_sess,
sess.opts.test,
- sess.opts.debugging_opts.edition,
+ sess.edition(),
);
// these need to be set "early" so that expansion sees `quote` if enabled.
sess.init_features(features);
}
});
+ time(sess, "dumping chalk-like clauses", || {
+ rustc_traits::lowering::dump_program_clauses(tcx);
+ });
+
time(sess, "MIR effect checking", || {
for def_id in tcx.body_owners() {
mir::transform::check_unsafety::check_unsafety(tcx, def_id)
time(sess, "lint checking", || lint::check_crate(tcx));
- time(sess, "dumping chalk-like clauses", || {
- rustc_traits::lowering::dump_program_clauses(tcx)
- });
-
return Ok(f(tcx, analysis, rx, tcx.sess.compile_status()));
},
)
}
}
}
+
+/// Lint constants that are erroneous.
+/// Without this lint, we might not get any diagnostic if the constant is
+/// unused within this crate, even though downstream crates can't use it
+/// without producing an error.
+pub struct UnusedBrokenConst;
+
+impl LintPass for UnusedBrokenConst {
+ fn get_lints(&self) -> LintArray {
+ lint_array!()
+ }
+}
+
+fn check_const(cx: &LateContext, body_id: hir::BodyId, what: &str) {
+ let def_id = cx.tcx.hir.body_owner_def_id(body_id);
+ let param_env = cx.tcx.param_env(def_id);
+ let cid = ::rustc::mir::interpret::GlobalId {
+ instance: ty::Instance::mono(cx.tcx, def_id),
+ promoted: None
+ };
+ if let Err(err) = cx.tcx.const_eval(param_env.and(cid)) {
+ let span = cx.tcx.def_span(def_id);
+ let mut diag = cx.struct_span_lint(
+ CONST_ERR,
+ span,
+ &format!("this {} cannot be used", what),
+ );
+ use rustc::middle::const_val::ConstEvalErrDescription;
+ match err.description() {
+ ConstEvalErrDescription::Simple(message) => {
+ diag.span_label(span, message);
+ }
+ ConstEvalErrDescription::Backtrace(miri, frames) => {
+ diag.span_label(span, format!("{}", miri));
+ for frame in frames {
+ diag.span_label(frame.span, format!("inside call to `{}`", frame.location));
+ }
+ }
+ }
+ diag.emit()
+ }
+}
+
+struct UnusedBrokenConstVisitor<'a, 'tcx: 'a>(&'a LateContext<'a, 'tcx>);
+
+impl<'a, 'tcx, 'v> hir::intravisit::Visitor<'v> for UnusedBrokenConstVisitor<'a, 'tcx> {
+ fn visit_nested_body(&mut self, id: hir::BodyId) {
+ check_const(self.0, id, "array length");
+ }
+ fn nested_visit_map<'this>(&'this mut self) -> hir::intravisit::NestedVisitorMap<'this, 'v> {
+ hir::intravisit::NestedVisitorMap::None
+ }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedBrokenConst {
+ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
+ match it.node {
+ hir::ItemConst(_, body_id) => {
+ check_const(cx, body_id, "constant");
+ },
+ hir::ItemTy(ref ty, _) => hir::intravisit::walk_ty(
+ &mut UnusedBrokenConstVisitor(cx),
+ ty
+ ),
+ _ => {},
+ }
+ }
+}
extern crate syntax_pos;
use rustc::lint;
-use rustc::lint::builtin::BARE_TRAIT_OBJECT;
+use rustc::lint::builtin::{BARE_TRAIT_OBJECT, ABSOLUTE_PATH_STARTING_WITH_MODULE};
use rustc::session;
use rustc::util;
UnionsWithDropFields,
UnreachablePub,
TypeAliasBounds,
+ UnusedBrokenConst,
);
add_builtin_with_new!(sess,
// Note: this item represents future incompatibility of all unstable functions in the
// standard library, and thus should never be removed or changed to an error.
},
+ FutureIncompatibleInfo {
+ id: LintId::of(ABSOLUTE_PATH_STARTING_WITH_MODULE),
+ reference: "issue TBD",
+ edition: Some(Edition::Edition2018),
+ },
]);
// Register renamed and removed lints
};
let mir =
- if let hir::ImplItemKind::Const(..) = ast_item.node {
- true
- } else if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
- let generics = self.tcx.generics_of(def_id);
- let types = generics.parent_types as usize + generics.types.len();
- let needs_inline = (types > 0 || tcx.trans_fn_attrs(def_id).requests_inline()) &&
- !self.metadata_output_only();
- let is_const_fn = sig.constness == hir::Constness::Const;
- let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
- needs_inline || is_const_fn || always_encode_mir
- } else {
- false
+ match ast_item.node {
+ hir::ImplItemKind::Const(..) => true,
+ hir::ImplItemKind::Method(ref sig, _) => {
+ let generics = self.tcx.generics_of(def_id);
+ let types = generics.parent_types as usize + generics.types.len();
+ let needs_inline =
+ (types > 0 || tcx.trans_fn_attrs(def_id).requests_inline())
+ && !self.metadata_output_only();
+ let is_const_fn = sig.constness == hir::Constness::Const;
+ let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
+ needs_inline || is_const_fn || always_encode_mir
+ },
+ hir::ImplItemKind::Type(..) => false,
};
Entry {
tcx.predicates_of(def_id).instantiate(tcx, substs);
let predicates =
type_checker.normalize(&instantiated_predicates.predicates, location);
- type_checker.prove_predicates(predicates.iter().cloned(), location);
+ type_checker.prove_predicates(predicates, location);
}
value.ty
let predicates = self.normalize(&instantiated_predicates.predicates, location);
debug!("prove_aggregate_predicates: predicates={:?}", predicates);
- self.prove_predicates(predicates.iter().cloned(), location);
+ self.prove_predicates(predicates, location);
}
fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, location: Location) {
self.prove_predicates(
- [ty::Predicate::Trait(
+ Some(ty::Predicate::Trait(
trait_ref.to_poly_trait_ref().to_poly_trait_predicate(),
- )].iter()
- .cloned(),
+ )),
location,
);
}
- fn prove_predicates(
- &mut self,
- predicates: impl IntoIterator<Item = ty::Predicate<'tcx>>,
- location: Location,
- ) {
- let mut predicates_iter = predicates.into_iter();
+ fn prove_predicates<T>(&mut self, predicates: T, location: Location)
+ where
+ T: IntoIterator<Item = ty::Predicate<'tcx>>,
+ T::IntoIter: Clone,
+ {
+ let predicates = predicates.into_iter();
debug!(
"prove_predicates(predicates={:?}, location={:?})",
- predicates_iter.by_ref().collect::<Vec<_>>(),
- location
+ predicates.clone().collect::<Vec<_>>(),
+ location,
);
self.fully_perform_op(location.at_self(), |this| {
let cause = this.misc(this.last_span);
- let obligations = predicates_iter
+ let obligations = predicates
+ .into_iter()
.map(|p| traits::Obligation::new(cause.clone(), this.param_env, p))
.collect();
Ok(InferOk {
PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| {
i == variant_index || {
+ self.hir.tcx().features().never_type &&
self.hir.tcx().features().exhaustive_patterns &&
self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs)
}
pub use self::check_match::check_crate;
pub(crate) use self::check_match::check_match;
-use interpret::{const_val_field, const_discr, self};
+use interpret::{const_val_field, const_variant_index, self};
use rustc::middle::const_val::ConstVal;
use rustc::mir::{Field, BorrowKind, Mutability};
ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
match cv.val {
ConstVal::Value(val) => {
- let discr_val = const_discr(
+ let variant_index = const_variant_index(
self.tcx, self.param_env, instance, val, cv.ty
- ).expect("const_discr failed");
- let layout = self
- .tcx
- .layout_of(self.param_env.and(cv.ty))
- .expect("layout of enum not available");
- let variant_index = match layout.variants {
- ty::layout::Variants::Single { index } => index,
- ty::layout::Variants::Tagged { ref discr, .. } => {
- // raw discriminants for enums are isize or bigger during
- // their computation, but later shrunk to the smallest possible
- // representation
- let size = discr.value.size(self.tcx).bits();
- let amt = 128 - size;
- adt_def
- .discriminants(self.tcx)
- .position(|var| ((var.val << amt) >> amt) == discr_val)
- .unwrap_or_else(|| {
- bug!("discriminant {} not found in {:#?}",
- discr_val,
- adt_def
- .discriminants(self.tcx)
- .collect::<Vec<_>>(),
- );
- })
- }
- ty::layout::Variants::NicheFilling { .. } => {
- assert_eq!(discr_val as usize as u128, discr_val);
- discr_val as usize
- },
- };
+ ).expect("const_variant_index failed");
let subpatterns = adt_subpatterns(
adt_def.variants[variant_index].fields.len(),
Some(variant_index),
Ok(ecx)
}
-pub fn eval_body_with_mir<'a, 'mir, 'tcx>(
+pub fn eval_promoted<'a, 'mir, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
cid: GlobalId<'tcx>,
mir: &'mir mir::Mir<'tcx>,
match res {
Ok(val) => Some(val),
Err(mut err) => {
- ecx.report(&mut err, true, None);
+ ecx.report(&mut err, false, None);
None
}
}
}
}
-pub fn const_discr<'a, 'tcx>(
+pub fn const_variant_index<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
value: Value,
ty: Ty<'tcx>,
-) -> EvalResult<'tcx, u128> {
- trace!("const_discr: {:?}, {:?}, {:?}", instance, value, ty);
+) -> EvalResult<'tcx, usize> {
+ trace!("const_variant_index: {:?}, {:?}, {:?}", instance, value, ty);
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
let (ptr, align) = match value {
Value::ByValPair(..) | Value::ByVal(_) => {
Value::ByRef(ptr, align) => (ptr, align),
};
let place = Place::from_primval_ptr(ptr, align);
- ecx.read_discriminant_value(place, ty)
+ ecx.read_discriminant_as_variant_index(place, ty)
}
pub fn const_eval_provider<'a, 'tcx>(
Discriminant(ref place) => {
let ty = self.place_ty(place);
- let layout = self.layout_of(ty)?;
let place = self.eval_place(place)?;
let discr_val = self.read_discriminant_value(place, ty)?;
- match layout.variants {
- layout::Variants::Single { index } => {
- assert_eq!(discr_val, index as u128);
- }
- layout::Variants::Tagged { .. } |
- layout::Variants::NicheFilling { .. } => {
- if let ty::TyAdt(adt_def, _) = ty.sty {
- trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(*self.tcx).collect::<Vec<_>>());
- if adt_def.discriminants(*self.tcx).all(|v| {
- discr_val != v.val
- })
- {
- return err!(InvalidDiscriminant);
- }
- } else {
- bug!("rustc only generates Rvalue::Discriminant for enums");
- }
- }
- }
self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?;
}
}
}
}
+ /// reads a tag and produces the corresponding variant index
+ pub fn read_discriminant_as_variant_index(
+ &mut self,
+ place: Place,
+ ty: Ty<'tcx>,
+ ) -> EvalResult<'tcx, usize> {
+ let layout = self.layout_of(ty)?;
+ match layout.variants {
+ ty::layout::Variants::Single { index } => Ok(index),
+ ty::layout::Variants::Tagged { .. } => {
+ let discr_val = self.read_discriminant_value(place, ty)?;
+ ty
+ .ty_adt_def()
+ .expect("tagged layout for non adt")
+ .discriminants(self.tcx.tcx)
+ .position(|var| var.val == discr_val)
+ .ok_or_else(|| EvalErrorKind::InvalidDiscriminant.into())
+ }
+ ty::layout::Variants::NicheFilling { .. } => {
+ let discr_val = self.read_discriminant_value(place, ty)?;
+ assert_eq!(discr_val as usize as u128, discr_val);
+ Ok(discr_val as usize)
+ },
+ }
+ }
+
pub fn read_discriminant_value(
&mut self,
place: Place,
ty: Ty<'tcx>,
) -> EvalResult<'tcx, u128> {
let layout = self.layout_of(ty)?;
- //trace!("read_discriminant_value {:#?}", layout);
+ trace!("read_discriminant_value {:#?}", layout);
match layout.variants {
layout::Variants::Single { index } => {
}
let (discr_place, discr) = self.place_field(place, mir::Field::new(0), layout)?;
+ trace!("discr place: {:?}, {:?}", discr_place, discr);
let raw_discr = self.value_to_primval(ValTy {
value: self.read_place(discr_place)?,
ty: discr.ty
})?;
let discr_val = match layout.variants {
layout::Variants::Single { .. } => bug!(),
- layout::Variants::Tagged { .. } => raw_discr.to_bytes()?,
+ // FIXME: should we catch invalid discriminants here?
+ layout::Variants::Tagged { .. } => {
+ if discr.ty.is_signed() {
+ let i = raw_discr.to_bytes()? as i128;
+ // going from layout tag type to typeck discriminant type
+ // requires first sign extending with the layout discriminant
+ let amt = 128 - discr.size.bits();
+ let sexted = (i << amt) >> amt;
+ // and then zeroing with the typeck discriminant type
+ let discr_ty = ty
+ .ty_adt_def().expect("tagged layout corresponds to adt")
+ .repr
+ .discr_type();
+ let discr_ty = layout::Integer::from_attr(self.tcx.tcx, discr_ty);
+ let amt = 128 - discr_ty.size().bits();
+ let truncatee = sexted as u128;
+ (truncatee << amt) >> amt
+ } else {
+ raw_discr.to_bytes()?
+ }
+ },
layout::Variants::NicheFilling {
dataful_variant,
ref niche_variants,
layout::Abi::Uninhabited);
}
}
- layout::Variants::Tagged { .. } => {
+ layout::Variants::Tagged { ref discr, .. } => {
let discr_val = dest_ty.ty_adt_def().unwrap()
.discriminant_for_variant(*self.tcx, variant_index)
.val;
+ // raw discriminants for enums are isize or bigger during
+ // their computation, but the in-memory tag is the smallest possible
+ // representation
+ let size = discr.value.size(self.tcx.tcx).bits();
+ let amt = 128 - size;
+ let discr_val = (discr_val << amt) >> amt;
+
let (discr_dest, discr) = self.place_field(dest, mir::Field::new(0), layout)?;
self.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?;
}
_ if primval.is_undef() => false,
_ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout)
};
- self.memory.write_primval(dest.to_ptr()?, dest_align, primval, layout.size.bytes(), signed)
+ self.memory.write_primval(dest, dest_align, primval, layout.size.bytes(), signed)
}
Value::ByValPair(a_val, b_val) => {
- let ptr = dest.to_ptr()?;
trace!("write_value_to_ptr valpair: {:#?}", layout);
let (a, b) = match layout.abi {
layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
_ => bug!("write_value_to_ptr: invalid ByValPair layout: {:#?}", layout)
};
let (a_size, b_size) = (a.size(&self), b.size(&self));
- let a_ptr = ptr;
+ let a_ptr = dest;
let b_offset = a_size.abi_align(b.align(&self));
- let b_ptr = ptr.offset(b_offset.bytes(), &self)?.into();
+ let b_ptr = dest.offset(b_offset.bytes(), &self)?.into();
// TODO: What about signedess?
self.memory.write_primval(a_ptr, dest_align, a_val, a_size.bytes(), false)?;
self.memory.write_primval(b_ptr, dest_align, b_val, b_size.bytes(), false)
self.read_primval(ptr, ptr_align, self.pointer_size())
}
- pub fn write_primval(&mut self, ptr: MemoryPointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> {
+ pub fn write_primval(&mut self, ptr: Pointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> {
let endianness = self.endianness();
let bytes = match val {
PrimVal::Bytes(bytes) => bytes,
PrimVal::Undef => {
- self.mark_definedness(PrimVal::Ptr(ptr).into(), size, false)?;
+ self.check_align(ptr.into(), ptr_align)?;
+ self.mark_definedness(ptr, size, false)?;
return Ok(());
}
};
+ let ptr = ptr.to_ptr()?;
+
{
let align = self.int_align(size);
let dst = self.get_bytes_mut(ptr, size, ptr_align.min(align))?;
pub fn write_ptr_sized_unsigned(&mut self, ptr: MemoryPointer, ptr_align: Align, val: PrimVal) -> EvalResult<'tcx> {
let ptr_size = self.pointer_size();
- self.write_primval(ptr, ptr_align, val, ptr_size, false)
+ self.write_primval(ptr.into(), ptr_align, val, ptr_size, false)
}
fn int_align(&self, size: u64) -> Align {
pub use self::memory::{Memory, MemoryKind, HasMemory};
pub use self::const_eval::{
- eval_body_with_mir,
+ eval_promoted,
mk_borrowck_eval_cx,
eval_body,
CompileTimeEvaluator,
const_eval_provider,
const_val_field,
- const_discr,
+ const_variant_index,
};
pub use self::machine::Machine;
ref targets,
..
} => {
- // FIXME(CTFE): forbid branching
let discr_val = self.eval_operand(discr)?;
let discr_prim = self.value_to_primval(discr_val)?;
let mut target_block = targets[targets.len() - 1];
for (index, &const_int) in values.iter().enumerate() {
- let prim = PrimVal::Bytes(const_int);
- if discr_prim.to_bytes()? == prim.to_bytes()? {
+ if discr_prim.to_bytes()? == const_int {
target_block = targets[index];
break;
}
#![feature(nonzero)]
#![feature(inclusive_range_fields)]
#![feature(crate_visibility_modifier)]
+#![feature(never_type)]
#![cfg_attr(stage0, feature(try_trait))]
extern crate arena;
param_substs: instance.substs,
}.visit_mir(&mir);
let param_env = ty::ParamEnv::reveal_all();
- for (i, promoted) in mir.promoted.iter().enumerate() {
+ for i in 0..mir.promoted.len() {
use rustc_data_structures::indexed_vec::Idx;
let cid = GlobalId {
instance,
};
match tcx.const_eval(param_env.and(cid)) {
Ok(val) => collect_const(tcx, val, instance.substs, output),
- Err(err) => {
- err.report(tcx, promoted.span, "promoted");
- }
+ Err(_) => {},
}
}
}
use rustc::middle::const_val::ConstVal;
use rustc::ty::{TyCtxt, self, Instance};
use rustc::mir::interpret::{Value, PrimVal, GlobalId};
-use interpret::{eval_body_with_mir, mk_borrowck_eval_cx, ValTy};
+use interpret::{eval_promoted, mk_borrowck_eval_cx, ValTy};
use transform::{MirPass, MirSource};
use syntax::codemap::Span;
use rustc::ty::subst::Substs;
};
// cannot use `const_eval` here, because that would require having the MIR
// for the current function available, but we're producing said MIR right now
- let (value, _, ty) = eval_body_with_mir(self.tcx, cid, self.mir, self.param_env)?;
+ let (value, _, ty) = eval_promoted(self.tcx, cid, self.mir, self.param_env)?;
let val = (value, ty, c.span);
trace!("evaluated {:?} to {:?}", c, val);
Some(val)
self.err_handler().span_err(item.span, "inherent impls cannot be negative");
}
if defaultness == Defaultness::Default {
- self.err_handler().span_err(item.span, "inherent impls cannot be default");
+ self.err_handler()
+ .struct_span_err(item.span, "inherent impls cannot be default")
+ .note("only trait implementations may be annotated with default").emit();
}
}
ItemKind::ForeignMod(..) => {
let path: Vec<Ident> = segments.iter()
.map(|seg| Ident::new(seg.name, span))
.collect();
- match self.resolve_path(&path, Some(namespace), true, span) {
+ // FIXME (Manishearth): Intra doc links won't get warned of epoch changes
+ match self.resolve_path(&path, Some(namespace), true, span, None) {
PathResult::Module(module) => *def = module.def().unwrap(),
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 =>
*def = path_res.base_def(),
- PathResult::NonModule(..) => match self.resolve_path(&path, None, true, span) {
+ PathResult::NonModule(..) => match self.resolve_path(&path, None, true, span, None) {
PathResult::Failed(span, msg, _) => {
error_callback(self, span, ResolutionError::FailedToResolve(&msg));
}
if def != Def::Err {
new_id = Some(def.def_id());
let span = trait_ref.path.span;
- if let PathResult::Module(module) = self.resolve_path(&path, None, false, span) {
+ if let PathResult::Module(module) = self.resolve_path(&path, None, false, span,
+ Some(trait_ref.ref_id)) {
new_val = Some((module, trait_ref.clone()));
}
}
(format!(""), format!("the crate root"))
} else {
let mod_path = &path[..path.len() - 1];
- let mod_prefix = match this.resolve_path(mod_path, Some(TypeNS), false, span) {
+ let mod_prefix = match this.resolve_path(mod_path, Some(TypeNS),
+ false, span, None) {
PathResult::Module(module) => module.def(),
_ => None,
}.map_or(format!(""), |def| format!("{} ", def.kind_name()));
));
}
- let result = match self.resolve_path(&path, Some(ns), true, span) {
+ let result = match self.resolve_path(&path, Some(ns), true, span, Some(id)) {
PathResult::NonModule(path_res) => path_res,
PathResult::Module(module) if !module.is_normal() => {
PathResolution::new(module.def().unwrap())
path[0].name != keywords::CrateRoot.name() &&
path[0].name != keywords::DollarCrate.name() {
let unqualified_result = {
- match self.resolve_path(&[*path.last().unwrap()], Some(ns), false, span) {
+ match self.resolve_path(&[*path.last().unwrap()], Some(ns), false, span, None) {
PathResult::NonModule(path_res) => path_res.base_def(),
PathResult::Module(module) => module.def().unwrap(),
_ => return Some(result),
path: &[Ident],
opt_ns: Option<Namespace>, // `None` indicates a module path
record_used: bool,
- path_span: Span)
+ path_span: Span,
+ node_id: Option<NodeId>) // None indicates that we don't care about linting
+ // `::module` paths
-> PathResult<'a> {
let mut module = None;
let mut allow_super = true;
let prev_name = path[0].name;
if prev_name == keywords::Extern.name() ||
prev_name == keywords::CrateRoot.name() &&
+ // Note: When this feature stabilizes, this should
+ // be gated on sess.rust_2018()
self.session.features_untracked().extern_absolute_paths {
// `::extern_crate::a::b`
let crate_id = self.crate_loader.process_path_extern(name, ident.span);
format!("Not a module `{}`", ident),
is_last);
}
+
+ if let Some(id) = node_id {
+ if i == 1 && self.session.features_untracked().crate_in_paths
+ && !self.session.rust_2018() {
+ let prev_name = path[0].name;
+ if prev_name == keywords::Extern.name() ||
+ prev_name == keywords::CrateRoot.name() {
+ let mut is_crate = false;
+ if let NameBindingKind::Import { directive: d, .. } = binding.kind {
+ if let ImportDirectiveSubclass::ExternCrate(..) = d.subclass {
+ is_crate = true;
+ }
+ }
+
+ if !is_crate {
+ let diag = lint::builtin::BuiltinLintDiagnostics
+ ::AbsPathWithModule(path_span);
+ self.session.buffer_lint_with_diagnostic(
+ lint::builtin::ABSOLUTE_PATH_STARTING_WITH_MODULE,
+ id, path_span,
+ "Absolute paths must start with `self`, `super`, \
+ `crate`, or an external crate name in the 2018 edition",
+ diag);
+ }
+ }
+ }
+ }
}
Err(Undetermined) => return PathResult::Indeterminate,
Err(Determined) => {
// Search in module.
let mod_path = &path[..path.len() - 1];
if let PathResult::Module(module) = self.resolve_path(mod_path, Some(TypeNS),
- false, span) {
+ false, span, None) {
add_module_candidates(module, &mut names);
}
}
fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
-> Result<Def, Determinacy> {
+ if path.segments.len() > 1 {
+ if !self.session.features_untracked().proc_macro_path_invoc {
+ emit_feature_err(
+ &self.session.parse_sess,
+ "proc_macro_path_invoc",
+ path.span,
+ GateIssue::Language,
+ "paths of length greater than one in macro invocations are \
+ currently unstable",
+ );
+ }
+ }
let def = self.resolve_macro_to_def_inner(scope, path, kind, force);
if def != Err(Determinacy::Undetermined) {
// Do not report duplicated errors on every undetermined resolution.
return Err(Determinacy::Determined);
}
- let def = match self.resolve_path(&path, Some(MacroNS), false, span) {
+ let def = match self.resolve_path(&path, Some(MacroNS), false, span, None) {
PathResult::NonModule(path_res) => match path_res.base_def() {
Def::Err => Err(Determinacy::Determined),
def @ _ => {
pub fn finalize_current_module_macro_resolutions(&mut self) {
let module = self.current_module;
for &(ref path, span) in module.macro_resolutions.borrow().iter() {
- match self.resolve_path(&path, Some(MacroNS), true, span) {
+ match self.resolve_path(&path, Some(MacroNS), true, span, None) {
PathResult::NonModule(_) => {},
PathResult::Failed(span, msg, _) => {
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
// For better failure detection, pretend that the import will not define any names
// while resolving its module path.
directive.vis.set(ty::Visibility::Invisible);
- let result = self.resolve_path(&directive.module_path[..], None, false, directive.span);
+ let result = self.resolve_path(&directive.module_path[..], None, false,
+ directive.span, Some(directive.id));
directive.vis.set(vis);
match result {
}
}
- let module_result = self.resolve_path(&module_path, None, true, span);
+ let module_result = self.resolve_path(&module_path, None, true, span, Some(directive.id));
let module = match module_result {
PathResult::Module(module) => module,
PathResult::Failed(span, msg, false) => {
if !self_path.is_empty() && !is_special(self_path[0]) &&
!(self_path.len() > 1 && is_special(self_path[1])) {
self_path[0].name = keywords::SelfValue.name();
- self_result = Some(self.resolve_path(&self_path, None, false, span));
+ self_result = Some(self.resolve_path(&self_path, None, false,
+ span, None));
}
return if let Some(PathResult::Module(..)) = self_result {
Some((span, format!("Did you mean `{}`?", names_to_string(&self_path[..]))))
normalize_ty_after_erasing_regions:
normalize_erasing_regions::normalize_ty_after_erasing_regions,
program_clauses_for: lowering::program_clauses_for,
+ program_clauses_for_env: lowering::program_clauses_for_env,
..*p
};
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc::hir::{self, ImplPolarity};
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc::ty::{self, Slice, TyCtxt};
+use rustc::hir::map::definitions::DefPathData;
+use rustc::hir::{self, ImplPolarity};
+use rustc::traits::{Clause, Clauses, DomainGoal, Goal, PolyDomainGoal, ProgramClause,
+ WhereClauseAtom};
use rustc::ty::subst::Substs;
-use rustc::traits::{WhereClauseAtom, PolyDomainGoal, DomainGoal, ProgramClause, Clause, Goal};
+use rustc::ty::{self, Slice, TyCtxt};
+use rustc_data_structures::fx::FxHashSet;
+use std::mem;
use syntax::ast;
-use rustc_data_structures::sync::Lrc;
use std::iter;
fn lower(&self) -> T;
}
-impl<T, U> Lower<Vec<U>> for Vec<T> where T: Lower<U> {
+impl<T, U> Lower<Vec<U>> for Vec<T>
+where
+ T: Lower<U>,
+{
fn lower(&self) -> Vec<U> {
self.iter().map(|item| item.lower()).collect()
}
}
}
-impl<'tcx, T> Lower<DomainGoal<'tcx>> for T where T: Lower<WhereClauseAtom<'tcx>> {
+impl<'tcx, T> Lower<DomainGoal<'tcx>> for T
+where
+ T: Lower<WhereClauseAtom<'tcx>>,
+{
fn lower(&self) -> DomainGoal<'tcx> {
DomainGoal::Holds(self.lower())
}
/// `forall<'a> { T: Fn(&'a i32) }` which corresponds to something like
/// `Binder<Holds(Implemented(TraitPredicate))>`.
impl<'tcx, T> Lower<PolyDomainGoal<'tcx>> for ty::Binder<T>
- where T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx>
+where
+ T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx>,
{
fn lower(&self) -> PolyDomainGoal<'tcx> {
self.map_bound_ref(|p| p.lower())
TypeOutlives(predicate) => predicate.lower(),
Projection(predicate) => predicate.lower(),
WellFormed(ty) => ty::Binder::dummy(DomainGoal::WellFormedTy(*ty)),
- ObjectSafe(..) |
- ClosureKind(..) |
- Subtype(..) |
- ConstEvaluatable(..) => unimplemented!(),
+ ObjectSafe(..) | ClosureKind(..) | Subtype(..) | ConstEvaluatable(..) => {
+ unimplemented!()
+ }
}
}
}
use self::DomainGoal::*;
match self {
Holds(wc_atom) => FromEnv(wc_atom),
- WellFormed(..) |
- FromEnv(..) |
- WellFormedTy(..) |
- FromEnvTy(..) |
- Normalize(..) |
- RegionOutlives(..) |
- TypeOutlives(..) => self,
+ WellFormed(..) | FromEnv(..) | WellFormedTy(..) | FromEnvTy(..) | Normalize(..)
+ | RegionOutlives(..) | TypeOutlives(..) => self,
}
}
}
-crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
- -> Lrc<&'tcx Slice<Clause<'tcx>>>
-{
- let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
- let node = tcx.hir.find(node_id).unwrap();
- match node {
- hir::map::Node::NodeItem(item) => match item.node {
- hir::ItemTrait(..) => program_clauses_for_trait(tcx, def_id),
- hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id),
- _ => Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())),
- }
- hir::map::Node::NodeImplItem(item) => {
- if let hir::ImplItemKind::Type(..) = item.node {
- program_clauses_for_associated_type_value(tcx, def_id)
- } else {
- Lrc::new(tcx.mk_clauses(iter::empty::<Clause>()))
- }
- },
+crate fn program_clauses_for<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId,
+) -> Clauses<'tcx> {
+ match tcx.def_key(def_id).disambiguated_data.data {
+ DefPathData::Trait(_) => program_clauses_for_trait(tcx, def_id),
+ DefPathData::Impl => program_clauses_for_impl(tcx, def_id),
+ DefPathData::AssocTypeInImpl(..) => program_clauses_for_associated_type_value(tcx, def_id),
+ _ => Slice::empty(),
+ }
+}
- // FIXME: other constructions e.g. traits, associated types...
- _ => Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())),
+crate fn program_clauses_for_env<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+) -> Clauses<'tcx> {
+ debug!("program_clauses_for_env(param_env={:?})", param_env);
+
+ let mut last_round = FxHashSet();
+ last_round.extend(
+ param_env
+ .caller_bounds
+ .iter()
+ .flat_map(|&p| predicate_def_id(p)),
+ );
+
+ let mut closure = last_round.clone();
+ let mut next_round = FxHashSet();
+ while !last_round.is_empty() {
+ next_round.extend(
+ last_round
+ .drain()
+ .flat_map(|def_id| {
+ tcx.predicates_of(def_id)
+ .instantiate_identity(tcx)
+ .predicates
+ })
+ .flat_map(|p| predicate_def_id(p))
+ .filter(|&def_id| closure.insert(def_id)),
+ );
+ mem::swap(&mut next_round, &mut last_round);
+ }
+
+ debug!("program_clauses_for_env: closure = {:#?}", closure);
+
+ return tcx.mk_clauses(
+ closure
+ .into_iter()
+ .flat_map(|def_id| tcx.program_clauses_for(def_id).iter().cloned()),
+ );
+
+ /// Given that `predicate` is in the environment, returns the
+ /// def-id of something (e.g., a trait, associated item, etc)
+ /// whose predicates can also be assumed to be true. We will
+ /// compute the transitive closure of such things.
+ fn predicate_def_id<'tcx>(predicate: ty::Predicate<'tcx>) -> Option<DefId> {
+ match predicate {
+ ty::Predicate::Trait(predicate) => Some(predicate.def_id()),
+
+ ty::Predicate::Projection(projection) => Some(projection.item_def_id()),
+
+ ty::Predicate::WellFormed(..)
+ | ty::Predicate::RegionOutlives(..)
+ | ty::Predicate::TypeOutlives(..)
+ | ty::Predicate::ObjectSafe(..)
+ | ty::Predicate::ClosureKind(..)
+ | ty::Predicate::Subtype(..)
+ | ty::Predicate::ConstEvaluatable(..) => None,
+ }
}
}
-fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
- -> Lrc<&'tcx Slice<Clause<'tcx>>>
-{
+fn program_clauses_for_trait<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId,
+) -> Clauses<'tcx> {
// `trait Trait<P1..Pn> where WC { .. } // P0 == Self`
// Rule Implemented-From-Env (see rustc guide)
let trait_pred = ty::TraitPredicate {
trait_ref: ty::TraitRef {
def_id,
- substs: Substs::identity_for_item(tcx, def_id)
- }
+ substs: Substs::identity_for_item(tcx, def_id),
+ },
};
// `FromEnv(Self: Trait<P1..Pn>)`
let from_env = Goal::from(DomainGoal::FromEnv(trait_pred.lower()));
goal: impl_trait,
hypotheses: tcx.mk_goals(iter::once(from_env)),
};
- let clauses = iter::once(
- Clause::ForAll(ty::Binder::dummy(implemented_from_env))
- );
+ let clauses = iter::once(Clause::ForAll(ty::Binder::dummy(implemented_from_env)));
// Rule Implied-Bound-From-Trait
//
// FIXME: Remove the [1..] slice; this is a hack because the query
// predicates_of currently includes the trait itself (`Self: Trait<P1..Pn>`).
let where_clauses = &tcx.predicates_of(def_id).predicates;
- let implied_bound_clauses =
- where_clauses[1..].into_iter()
+ let implied_bound_clauses = where_clauses[1..]
+ .into_iter()
.map(|wc| implied_bound_from_trait(tcx, trait_pred, wc));
- Lrc::new(tcx.mk_clauses(clauses.chain(implied_bound_clauses)))
+ tcx.mk_clauses(clauses.chain(implied_bound_clauses))
}
/// For a given `where_clause`, returns a clause `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`.
let impl_trait = DomainGoal::FromEnv(WhereClauseAtom::Implemented(trait_pred));
// `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`
- Clause::ForAll(
- where_clause.lower().map_bound(|goal| ProgramClause {
- goal: goal.into_from_env_goal(),
- hypotheses: tcx.mk_goals(iter::once(Goal::from(impl_trait))),
- })
- )
+ Clause::ForAll(where_clause.lower().map_bound(|goal| ProgramClause {
+ goal: goal.into_from_env_goal(),
+ hypotheses: tcx.mk_goals(iter::once(Goal::from(impl_trait))),
+ }))
}
-fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
- -> Lrc<&'tcx Slice<Clause<'tcx>>>
-{
+fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Clauses<'tcx> {
if let ImplPolarity::Negative = tcx.impl_polarity(def_id) {
- return Lrc::new(tcx.mk_clauses(iter::empty::<Clause>()));
+ return Slice::empty();
}
// Rule Implemented-From-Impl (see rustc guide)
let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
// `Implemented(A0: Trait<A1..An>)`
let trait_pred = ty::TraitPredicate { trait_ref }.lower();
- // `WC`
+ // `WC`
let where_clauses = tcx.predicates_of(def_id).predicates.lower();
- // `Implemented(A0: Trait<A1..An>) :- WC`
+ // `Implemented(A0: Trait<A1..An>) :- WC`
let clause = ProgramClause {
goal: trait_pred,
hypotheses: tcx.mk_goals(
- where_clauses.into_iter().map(|wc| Goal::from_poly_domain_goal(wc, tcx))
- )
+ where_clauses
+ .into_iter()
+ .map(|wc| Goal::from_poly_domain_goal(wc, tcx)),
+ ),
};
- Lrc::new(tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause)))))
+ tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))
}
pub fn program_clauses_for_associated_type_value<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
item_id: DefId,
-) -> Lrc<&'tcx Slice<Clause<'tcx>>> {
+) -> Clauses<'tcx> {
// Rule Normalize-From-Impl (see rustc guide)
//
// ```impl<P0..Pn> Trait<A1..An> for A0
let clause = ProgramClause {
goal: normalize_goal,
hypotheses: tcx.mk_goals(
- where_clauses.into_iter().map(|wc| Goal::from_poly_domain_goal(wc, tcx))
+ where_clauses
+ .into_iter()
+ .map(|wc| Goal::from_poly_domain_goal(wc, tcx)),
),
};
- Lrc::new(tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause)))))
+ tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))
}
pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
}
let mut visitor = ClauseDumper { tcx };
- tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
+ tcx.hir
+ .krate()
+ .visit_all_item_likes(&mut visitor.as_deep_visitor());
}
struct ClauseDumper<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
-impl<'a, 'tcx> ClauseDumper<'a, 'tcx > {
+impl<'a, 'tcx> ClauseDumper<'a, 'tcx> {
fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) {
let def_id = self.tcx.hir.local_def_id(node_id);
for attr in attrs {
+ let mut clauses = None;
+
if attr.check_name("rustc_dump_program_clauses") {
- let clauses = self.tcx.program_clauses_for(def_id);
- for clause in *clauses {
- // Skip the top-level binder for a less verbose output
- let program_clause = match clause {
- Clause::Implies(program_clause) => program_clause,
- Clause::ForAll(program_clause) => program_clause.skip_binder(),
- };
- self.tcx.sess.struct_span_err(attr.span, &format!("{}", program_clause)).emit();
+ clauses = Some(self.tcx.program_clauses_for(def_id));
+ }
+
+ if attr.check_name("rustc_dump_env_program_clauses") {
+ let param_env = self.tcx.param_env(def_id);
+ clauses = Some(self.tcx.program_clauses_for_env(param_env));
+ }
+
+ if let Some(clauses) = clauses {
+ let mut err = self.tcx
+ .sess
+ .struct_span_err(attr.span, "program clause dump");
+
+ let mut strings: Vec<_> = clauses
+ .iter()
+ .map(|clause| {
+ // Skip the top-level binder for a less verbose output
+ let program_clause = match clause {
+ Clause::Implies(program_clause) => program_clause,
+ Clause::ForAll(program_clause) => program_clause.skip_binder(),
+ };
+ format!("{}", program_clause)
+ })
+ .collect();
+
+ strings.sort();
+
+ for string in strings {
+ err.note(&string);
}
+
+ err.emit();
}
}
}
// except according to those terms.
use rustc::infer::InferCtxt;
-use rustc::infer::canonical::{CanonicalVarValues, Canonicalize, Certainty, QueryRegionConstraints,
- QueryResult};
+use rustc::infer::canonical::{CanonicalVarValues, Canonicalize, Certainty, QueryResult};
use rustc::infer::region_constraints::{Constraint, RegionConstraintData};
use rustc::traits::{FulfillmentContext, TraitEngine};
use rustc::traits::query::NoSolution;
let region_obligations = infcx.take_registered_region_obligations();
- let (region_outlives, ty_outlives) = infcx.with_region_constraints(|region_constraints| {
+ let region_constraints = infcx.with_region_constraints(|region_constraints| {
let RegionConstraintData {
constraints,
verifys,
assert!(verifys.is_empty());
assert!(givens.is_empty());
- let region_outlives: Vec<_> = constraints
+ let mut outlives: Vec<_> = constraints
.into_iter()
.map(|(k, _)| match *k {
- Constraint::VarSubVar(v1, v2) => {
- (tcx.mk_region(ty::ReVar(v1)), tcx.mk_region(ty::ReVar(v2)))
+ Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
+ tcx.mk_region(ty::ReVar(v1)).into(),
+ tcx.mk_region(ty::ReVar(v2)),
+ ),
+ Constraint::VarSubReg(v1, r2) => {
+ ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v1)).into(), r2)
}
- Constraint::VarSubReg(v1, r2) => (tcx.mk_region(ty::ReVar(v1)), r2),
- Constraint::RegSubVar(r1, v2) => (r1, tcx.mk_region(ty::ReVar(v2))),
- Constraint::RegSubReg(r1, r2) => (r1, r2),
+ Constraint::RegSubVar(r1, v2) => {
+ ty::OutlivesPredicate(r1.into(), tcx.mk_region(ty::ReVar(v2)))
+ }
+ Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r1.into(), r2),
})
+ .map(ty::Binder) // no bound regions in the code above
.collect();
- let ty_outlives: Vec<_> = region_obligations
- .into_iter()
- .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region))
- .collect();
+ outlives.extend(
+ region_obligations
+ .into_iter()
+ .map(|(_, r_o)| ty::OutlivesPredicate(r_o.sup_type.into(), r_o.sub_region))
+ .map(ty::Binder) // no bound regions in the code above
+ );
- (region_outlives, ty_outlives)
+ outlives
});
let certainty = if ambig_errors.is_empty() {
let (canonical_result, _) = infcx.canonicalize_response(&QueryResult {
var_values: inference_vars,
- region_constraints: QueryRegionConstraints {
- region_outlives,
- ty_outlives,
- },
+ region_constraints,
certainty,
value: answer,
});
AllocatorTy::Ptr => args.push(i8p),
AllocatorTy::Usize => args.push(usize),
- AllocatorTy::Bang |
AllocatorTy::ResultPtr |
AllocatorTy::Unit => panic!("invalid allocator arg"),
}
}
let output = match method.output {
- AllocatorTy::Bang => None,
AllocatorTy::ResultPtr => Some(i8p),
AllocatorTy::Unit => None,
// You can also find more info on why Windows is whitelisted here in:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1302078
if !cx.sess().no_landing_pads() ||
- cx.sess().target.target.options.is_like_windows {
+ cx.sess().target.target.options.requires_uwtable {
attributes::emit_uwtable(lldecl, true);
}
self.mir_constant_to_miri_value(bx, constant)
.and_then(|c| OperandRef::from_const(bx, c, ty))
.unwrap_or_else(|err| {
- err.report(bx.tcx(), constant.span, "const operand");
+ match constant.literal {
+ mir::Literal::Promoted { .. } => {
+ // don't report errors inside promoteds, just warnings.
+ },
+ mir::Literal::Value { .. } => {
+ err.report(bx.tcx(), constant.span, "const operand")
+ },
+ }
// We've errored, so we don't have to produce working code.
let layout = bx.cx.layout_of(ty);
PlaceRef::new_sized(
ty::TyStr => {
let lang_def_id = lang_items.str_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
+
+ let lang_def_id = lang_items.str_alloc_impl();
+ self.assemble_inherent_impl_for_primitive(lang_def_id);
}
ty::TySlice(_) => {
let lang_def_id = lang_items.slice_impl();
let lang_def_id = lang_items.slice_u8_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
+
+ let lang_def_id = lang_items.slice_alloc_impl();
+ self.assemble_inherent_impl_for_primitive(lang_def_id);
+
+ let lang_def_id = lang_items.slice_u8_alloc_impl();
+ self.assemble_inherent_impl_for_primitive(lang_def_id);
}
ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
let lang_def_id = lang_items.const_ptr_impl();
ty::TyFloat(ast::FloatTy::F32) => {
let lang_def_id = lang_items.f32_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
+
+ let lang_def_id = lang_items.f32_runtime_impl();
+ self.assemble_inherent_impl_for_primitive(lang_def_id);
}
ty::TyFloat(ast::FloatTy::F64) => {
let lang_def_id = lang_items.f64_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
+
+ let lang_def_id = lang_items.f64_runtime_impl();
+ self.assemble_inherent_impl_for_primitive(lang_def_id);
}
_ => {}
}
}
// Tries to apply a fallback to `ty` if it is an unsolved variable.
- // Non-numerics get replaced with !, unconstrained ints with i32,
+ // Non-numerics get replaced with ! or () (depending on whether
+ // feature(never_type) is enabled, unconstrained ints with i32,
// unconstrained floats with f64.
// Fallback becomes very dubious if we have encountered type-checking errors.
// In that case, fallback to TyError.
_ if self.is_tainted_by_errors() => self.tcx().types.err,
UnconstrainedInt => self.tcx.types.i32,
UnconstrainedFloat => self.tcx.types.f64,
- Neither if self.type_var_diverges(ty) => self.tcx.types.never,
+ Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
Neither => return false,
};
debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback);
ty::TyChar => {
self.check_primitive_impl(def_id,
lang_items.char_impl(),
+ None,
"char",
"char",
item.span);
ty::TyStr => {
self.check_primitive_impl(def_id,
lang_items.str_impl(),
+ lang_items.str_alloc_impl(),
"str",
"str",
item.span);
ty::TySlice(slice_item) if slice_item == self.tcx.types.u8 => {
self.check_primitive_impl(def_id,
lang_items.slice_u8_impl(),
+ lang_items.slice_u8_alloc_impl(),
"slice_u8",
"[u8]",
item.span);
ty::TySlice(_) => {
self.check_primitive_impl(def_id,
lang_items.slice_impl(),
+ lang_items.slice_alloc_impl(),
"slice",
"[T]",
item.span);
ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
self.check_primitive_impl(def_id,
lang_items.const_ptr_impl(),
+ None,
"const_ptr",
"*const T",
item.span);
ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
self.check_primitive_impl(def_id,
lang_items.mut_ptr_impl(),
+ None,
"mut_ptr",
"*mut T",
item.span);
ty::TyInt(ast::IntTy::I8) => {
self.check_primitive_impl(def_id,
lang_items.i8_impl(),
+ None,
"i8",
"i8",
item.span);
ty::TyInt(ast::IntTy::I16) => {
self.check_primitive_impl(def_id,
lang_items.i16_impl(),
+ None,
"i16",
"i16",
item.span);
ty::TyInt(ast::IntTy::I32) => {
self.check_primitive_impl(def_id,
lang_items.i32_impl(),
+ None,
"i32",
"i32",
item.span);
ty::TyInt(ast::IntTy::I64) => {
self.check_primitive_impl(def_id,
lang_items.i64_impl(),
+ None,
"i64",
"i64",
item.span);
ty::TyInt(ast::IntTy::I128) => {
self.check_primitive_impl(def_id,
lang_items.i128_impl(),
+ None,
"i128",
"i128",
item.span);
ty::TyInt(ast::IntTy::Isize) => {
self.check_primitive_impl(def_id,
lang_items.isize_impl(),
+ None,
"isize",
"isize",
item.span);
ty::TyUint(ast::UintTy::U8) => {
self.check_primitive_impl(def_id,
lang_items.u8_impl(),
+ None,
"u8",
"u8",
item.span);
ty::TyUint(ast::UintTy::U16) => {
self.check_primitive_impl(def_id,
lang_items.u16_impl(),
+ None,
"u16",
"u16",
item.span);
ty::TyUint(ast::UintTy::U32) => {
self.check_primitive_impl(def_id,
lang_items.u32_impl(),
+ None,
"u32",
"u32",
item.span);
ty::TyUint(ast::UintTy::U64) => {
self.check_primitive_impl(def_id,
lang_items.u64_impl(),
+ None,
"u64",
"u64",
item.span);
ty::TyUint(ast::UintTy::U128) => {
self.check_primitive_impl(def_id,
lang_items.u128_impl(),
+ None,
"u128",
"u128",
item.span);
ty::TyUint(ast::UintTy::Usize) => {
self.check_primitive_impl(def_id,
lang_items.usize_impl(),
+ None,
"usize",
"usize",
item.span);
ty::TyFloat(ast::FloatTy::F32) => {
self.check_primitive_impl(def_id,
lang_items.f32_impl(),
+ lang_items.f32_runtime_impl(),
"f32",
"f32",
item.span);
ty::TyFloat(ast::FloatTy::F64) => {
self.check_primitive_impl(def_id,
lang_items.f64_impl(),
+ lang_items.f64_runtime_impl(),
"f64",
"f64",
item.span);
fn check_primitive_impl(&self,
impl_def_id: DefId,
lang_def_id: Option<DefId>,
+ lang_def_id2: Option<DefId>,
lang: &str,
ty: &str,
span: Span) {
- match lang_def_id {
- Some(lang_def_id) if lang_def_id == impl_def_id => {
+ match (lang_def_id, lang_def_id2) {
+ (Some(lang_def_id), _) if lang_def_id == impl_def_id => {
+ // OK
+ }
+ (_, Some(lang_def_id)) if lang_def_id == impl_def_id => {
// OK
}
_ => {
fn from_target_feature(
tcx: TyCtxt,
+ id: DefId,
attr: &ast::Attribute,
whitelist: &FxHashMap<String, Option<String>>,
target_features: &mut Vec<Symbol>,
Some(name) => bug!("unknown target feature gate {}", name),
None => true,
};
- if !allowed {
+ if !allowed && id.is_local() {
feature_gate::emit_feature_err(
&tcx.sess.parse_sess,
feature_gate.as_ref().unwrap(),
`unsafe` function";
tcx.sess.span_err(attr.span, msg);
}
- from_target_feature(tcx, attr, &whitelist, &mut trans_fn_attrs.target_features);
+ from_target_feature(tcx, id, attr, &whitelist, &mut trans_fn_attrs.target_features);
} else if attr.check_name("linkage") {
if let Some(val) = attr.value_str() {
trans_fn_attrs.linkage = Some(linkage_by_name(tcx, id, &val.as_str()));
The error happens on numeric literals:
```compile_fail,E0689
-2.0.powi(2);
+2.0.recip();
```
and on numeric bindings without an identified concrete type:
```compile_fail,E0689
let x = 2.0;
-x.powi(2); // same error as above
+x.recip(); // same error as above
```
Because of this, you must give the numeric literal or binding a type:
```
-let _ = 2.0_f32.powi(2);
+let _ = 2.0_f32.recip();
let x: f32 = 2.0;
-let _ = x.powi(2);
-let _ = (2.0 as f32).powi(2);
+let _ = x.recip();
+let _ = (2.0 as f32).recip();
```
"##,
#![feature(slice_patterns)]
#![feature(slice_sort_by_cached_key)]
#![feature(dyn_trait)]
+#![feature(never_type)]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
lang_items.u128_impl(),
lang_items.f32_impl(),
lang_items.f64_impl(),
+ lang_items.f32_runtime_impl(),
+ lang_items.f64_runtime_impl(),
lang_items.char_impl(),
lang_items.str_impl(),
lang_items.slice_impl(),
lang_items.slice_u8_impl(),
+ lang_items.str_alloc_impl(),
+ lang_items.slice_alloc_impl(),
+ lang_items.slice_u8_alloc_impl(),
lang_items.const_ptr_impl(),
lang_items.mut_ptr_impl(),
];
actually_rustdoc: true,
debugging_opts: config::DebuggingOptions {
force_unstable_if_unmarked,
- edition,
..config::basic_debugging_options()
},
error_format,
+ edition,
..config::basic_options().clone()
};
/// discriminants. JavaScript then is used to decode them into the original value.
/// Consequently, every change to this type should be synchronized to
/// the `itemTypes` mapping table in `static/main.js`.
-#[derive(Copy, PartialEq, Clone)]
+#[derive(Copy, PartialEq, Clone, Debug)]
pub enum ItemType {
Module = 0,
ExternCrate = 1,
autocomplete=\"off\" \
placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
type=\"search\">\
+ <a id=\"settings-menu\" href=\"{root_path}settings.html\">\
+ <img src=\"{root_path}wheel{suffix}.svg\" width=\"18\" alt=\"Change settings\">\
+ </a>\
</div>\
</form>\
</nav>\
</script>\
<script src=\"{root_path}main{suffix}.js\"></script>\
<script defer src=\"{root_path}search-index.js\"></script>\
+ <script defer src=\"{root_path}aliases.js\"></script>\
</body>\
</html>",
css_extension = if css_file_extension {
themes = themes.iter()
.filter_map(|t| t.file_stem())
.filter_map(|t| t.to_str())
- .map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}">"#,
+ .map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}{}.css">"#,
page.root_path,
- t.replace(".css", &format!("{}.css", page.resource_suffix))))
+ t,
+ page.resource_suffix))
.collect::<String>(),
suffix=page.resource_suffix,
)
// yet when its implementation methods are being indexed. Caches such methods
// and their parent id here and indexes them at the end of crate parsing.
orphan_impl_items: Vec<(DefId, clean::Item)>,
+
+ /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
+ /// we need the alias element to have an array of items.
+ aliases: FxHashMap<String, Vec<IndexItem>>,
}
/// Temporary storage for data obtained during `RustdocVisitor::clean()`.
/// Struct representing one entry in the JS search index. These are all emitted
/// by hand to a large JS file at the end of cache-creation.
+#[derive(Debug)]
struct IndexItem {
ty: ItemType,
name: String,
}
/// A type used for the search index.
+#[derive(Debug)]
struct Type {
name: Option<String>,
generics: Option<Vec<String>>,
}
/// Full type of functions/methods in the search index.
+#[derive(Debug)]
struct IndexItemFunctionType {
inputs: Vec<Type>,
- output: Option<Type>
+ output: Option<Type>,
}
impl ToJson for IndexItemFunctionType {
owned_box_did,
masked_crates: mem::replace(&mut krate.masked_crates, FxHashSet()),
typarams: external_typarams,
+ aliases: FxHashMap(),
};
// Cache where all our extern crates are located
write(cx.dst.join(&format!("rustdoc{}.css", cx.shared.resource_suffix)),
include_bytes!("static/rustdoc.css"))?;
+ write(cx.dst.join(&format!("settings{}.css", cx.shared.resource_suffix)),
+ include_bytes!("static/settings.css"))?;
// To avoid "light.css" to be overwritten, we'll first run over the received themes and only
// then we'll run over the "official" styles.
write(cx.dst.join(&format!("brush{}.svg", cx.shared.resource_suffix)),
include_bytes!("static/brush.svg"))?;
+ write(cx.dst.join(&format!("wheel{}.svg", cx.shared.resource_suffix)),
+ include_bytes!("static/wheel.svg"))?;
write(cx.dst.join(&format!("light{}.css", cx.shared.resource_suffix)),
include_bytes!("static/themes/light.css"))?;
themes.insert("light".to_owned());
switchTheme(currentTheme, mainTheme, item);
}};
themes.appendChild(but);
-}});
-"#,
+}});"#,
themes.iter()
.map(|s| format!("\"{}\"", s))
.collect::<Vec<String>>()
write(cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)),
include_bytes!("static/main.js"))?;
+ write(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)),
+ include_bytes!("static/settings.js"))?;
{
let mut data = format!("var resourcesSuffix = \"{}\";\n",
write(cx.dst.join("COPYRIGHT.txt"),
include_bytes!("static/COPYRIGHT.txt"))?;
- fn collect(path: &Path, krate: &str,
- key: &str) -> io::Result<Vec<String>> {
+ fn collect(path: &Path, krate: &str, key: &str) -> io::Result<Vec<String>> {
let mut ret = Vec::new();
if path.exists() {
for line in BufReader::new(File::open(path)?).lines() {
Ok(ret)
}
+ fn show_item(item: &IndexItem, krate: &str) -> String {
+ format!("{{'crate':'{}','ty':{},'name':'{}','path':'{}'{}}}",
+ krate, item.ty as usize, item.name, item.path,
+ if let Some(p) = item.parent_idx {
+ format!(",'parent':{}", p)
+ } else {
+ String::new()
+ })
+ }
+
+ let dst = cx.dst.join("aliases.js");
+ {
+ let mut all_aliases = try_err!(collect(&dst, &krate.name, "ALIASES"), &dst);
+ let mut w = try_err!(File::create(&dst), &dst);
+ let mut output = String::with_capacity(100);
+ for (alias, items) in &cache.aliases {
+ if items.is_empty() {
+ continue
+ }
+ output.push_str(&format!("\"{}\":[{}],",
+ alias,
+ items.iter()
+ .map(|v| show_item(v, &krate.name))
+ .collect::<Vec<_>>()
+ .join(",")));
+ }
+ all_aliases.push(format!("ALIASES['{}'] = {{{}}};", krate.name, output));
+ all_aliases.sort();
+ try_err!(writeln!(&mut w, "var ALIASES = {{}};"), &dst);
+ for aliases in &all_aliases {
+ try_err!(writeln!(&mut w, "{}", aliases), &dst);
+ }
+ }
+
// Update the search index
let dst = cx.dst.join("search-index.js");
let mut all_indexes = try_err!(collect(&dst, &krate.name, "searchIndex"), &dst);
// `public_items` map, so we can skip inserting into the
// paths map if there was already an entry present and we're
// not a public item.
- if
- !self.paths.contains_key(&item.def_id) ||
- self.access_levels.is_public(item.def_id)
+ if !self.paths.contains_key(&item.def_id) ||
+ self.access_levels.is_public(item.def_id)
{
self.paths.insert(item.def_id,
(self.stack.clone(), item.type_()));
}
+ self.add_aliases(&item);
}
// Link variants to their parent enum because pages aren't emitted
// for each variant.
}
clean::PrimitiveItem(..) if item.visibility.is_some() => {
+ self.add_aliases(&item);
self.paths.insert(item.def_id, (self.stack.clone(),
item.type_()));
}
}
}
}
+
+ fn add_aliases(&mut self, item: &clean::Item) {
+ if item.def_id.index == CRATE_DEF_INDEX {
+ return
+ }
+ if let Some(ref item_name) = item.name {
+ let path = self.paths.get(&item.def_id)
+ .map(|p| p.0.join("::").to_string())
+ .unwrap_or("std".to_owned());
+ for alias in item.attrs.lists("doc")
+ .filter(|a| a.check_name("alias"))
+ .filter_map(|a| a.value_str()
+ .map(|s| s.to_string().replace("\"", "")))
+ .filter(|v| !v.is_empty())
+ .collect::<FxHashSet<_>>()
+ .into_iter() {
+ self.aliases.entry(alias)
+ .or_insert(Vec::with_capacity(1))
+ .push(IndexItem {
+ ty: item.type_(),
+ name: item_name.to_string(),
+ path: path.clone(),
+ desc: String::new(),
+ parent: None,
+ parent_idx: None,
+ search_type: get_index_search_type(&item),
+ });
+ }
+ }
+ }
}
#[derive(Debug, Eq, PartialEq, Hash)]
}
}
+#[derive(Debug)]
+struct Settings<'a> {
+ // (id, explanation, default value)
+ settings: Vec<(&'static str, &'static str, bool)>,
+ root_path: &'a str,
+ suffix: &'a str,
+}
+
+impl<'a> Settings<'a> {
+ pub fn new(root_path: &'a str, suffix: &'a str) -> Settings<'a> {
+ Settings {
+ settings: vec![
+ ("item-declarations", "Auto-hide item declarations.", true),
+ ("item-attributes", "Auto-hide item attributes.", true),
+ ],
+ root_path,
+ suffix,
+ }
+ }
+}
+
+impl<'a> fmt::Display for Settings<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f,
+"<h1 class='fqn'>\
+ <span class='in-band'>Rustdoc settings</span>\
+</h1>\
+<div class='settings'>{}</div>\
+<script src='{}settings{}.js'></script>",
+ self.settings.iter()
+ .map(|(id, text, enabled)| {
+ format!("<div class='setting-line'>\
+ <label class='toggle'>\
+ <input type='checkbox' id='{}' {}>\
+ <span class='slider'></span>\
+ </label>\
+ <div>{}</div>\
+ </div>", id, if *enabled { " checked" } else { "" }, text)
+ })
+ .collect::<String>(),
+ self.root_path,
+ self.suffix)
+ }
+}
+
impl Context {
/// String representation of how to get back to the root path of the 'doc/'
/// folder in terms of a relative URL.
};
let final_file = self.dst.join(&krate.name)
.join("all.html");
+ let settings_file = self.dst.join("settings.html");
+
let crate_name = krate.name.clone();
item.name = Some(krate.name);
if !root_path.ends_with('/') {
root_path.push('/');
}
- let page = layout::Page {
+ let mut page = layout::Page {
title: "List of all items in this crate",
css_class: "mod",
root_path: "../",
self.shared.css_file_extension.is_some(),
&self.shared.themes),
&final_file);
+
+ // Generating settings page.
+ let settings = Settings::new("./", &self.shared.resource_suffix);
+ page.title = "Rustdoc settings";
+ page.description = "Settings of Rustdoc";
+ page.root_path = "./";
+
+ let mut w = BufWriter::new(try_err!(File::create(&settings_file), &settings_file));
+ let mut themes = self.shared.themes.clone();
+ let sidebar = "<p class='location'>Settings</p><div class='sidebar-elems'></div>";
+ themes.push(PathBuf::from("settings.css"));
+ let mut layout = self.shared.layout.clone();
+ layout.krate = String::new();
+ layout.logo = String::new();
+ layout.favicon = String::new();
+ try_err!(layout::render(&mut w, &layout,
+ &page, &sidebar, &settings,
+ self.shared.css_file_extension.is_some(),
+ &themes),
+ &settings_file);
+
Ok(())
}
return false;
}
var end = start + className.length;
- if (end < elemClass.length && elemClass[end] !== ' ') {
- return false;
- }
- return true;
+ return !(end < elemClass.length && elemClass[end] !== ' ');
}
if (start > 0 && elemClass[start - 1] !== ' ') {
return false;
}
var end = start + className.length;
- if (end < elemClass.length && elemClass[end] !== ' ') {
- return false;
- }
- return true;
+ return !(end < elemClass.length && elemClass[end] !== ' ');
}
return false;
}
} else if (ev.target.tagName === 'SPAN' && hasClass(ev.target.parentNode, 'line-numbers')) {
var prev_id = 0;
- var set_fragment = function (name) {
+ var set_fragment = function(name) {
if (browserSupportsHistoryApi()) {
history.replaceState(null, null, '#' + name);
window.hashchange();
query.search = val;
// searching by type
} else if (val.search("->") > -1) {
- var trimmer = function (s) { return s.trim(); };
+ var trimmer = function(s) { return s.trim(); };
var parts = val.split("->").map(trimmer);
var input = parts[0];
// sort inputs so that order does not matter
}
}
- return {
+ var ret = {
'in_args': sortResults(results_in_args, true),
'returned': sortResults(results_returned, true),
'others': sortResults(results),
};
+ if (ALIASES[window.currentCrate][query.raw]) {
+ var aliases = ALIASES[window.currentCrate][query.raw];
+ for (var i = 0; i < aliases.length; ++i) {
+ ret['others'].unshift(aliases[i]);
+ if (ret['others'].length > MAX_RESULTS) {
+ ret['others'].pop();
+ }
+ }
+ }
+ return ret;
}
/**
array.forEach(function(item) {
var name, type, href, displayPath;
- if (shown.indexOf(item) !== -1) {
+ var id_ty = item.ty + item.path + item.name;
+ if (shown.indexOf(id_ty) !== -1) {
return;
}
- shown.push(item);
+ console.log(item);
+ shown.push(id_ty);
name = item.name;
type = itemTypes[item.ty];
function search(e) {
var params = getQueryStringParams();
- var query = getQuery(document.getElementsByClassName('search-input')[0].value);
+ var search_input = document.getElementsByClassName('search-input')[0];
+ var query = getQuery(search_input.value.trim());
if (e) {
e.preventDefault();
}
if (!query.query || query.id === currentResults) {
+ if (query.query.length > 0) {
+ putBackSearch(search_input);
+ }
return;
}
startSearch();
// Draw a convenient sidebar of known crates if we have a listing
- if (rootPath === '../') {
+ if (rootPath === '../' || rootPath === "./") {
var sidebar = document.getElementsByClassName('sidebar-elems')[0];
if (sidebar) {
var div = document.createElement('div');
crates.sort();
for (var i = 0; i < crates.length; ++i) {
var klass = 'crate';
- if (crates[i] === window.currentCrate) {
+ if (rootPath !== "./" && crates[i] === window.currentCrate) {
klass += ' current';
}
var link = document.createElement('a');
- link.href = '../' + crates[i] + '/index.html';
+ link.href = rootPath + crates[i] + '/index.html';
link.title = rawSearchIndex[crates[i]].doc;
link.className = klass;
link.textContent = crates[i];
otherMessage = ' Show type declaration';
}
e.parentNode.insertBefore(createToggle(otherMessage), e);
- if (otherMessage) {
+ if (otherMessage && getCurrentValue('rustdoc-item-declarations') !== "false") {
collapseDocs(e.previousSibling.childNodes[0], "toggle");
}
}
onEach(document.getElementById('main').getElementsByTagName('pre'), function(e) {
onEach(e.getElementsByClassName('attributes'), function(i_e) {
i_e.parentNode.insertBefore(createToggleWrapper(), i_e);
- collapseDocs(i_e.previousSibling.childNodes[0], "toggle");
+ if (getCurrentValue("rustdoc-item-attributes") !== "false") {
+ collapseDocs(i_e.previousSibling.childNodes[0], "toggle");
+ }
});
});
};
});
+ function putBackSearch(search_input) {
+ if (search_input.value !== "") {
+ addClass(document.getElementById("main"), "hidden");
+ removeClass(document.getElementById("search"), "hidden");
+ if (browserSupportsHistoryApi()) {
+ history.replaceState(search_input.value,
+ "",
+ "?search=" + encodeURIComponent(search_input.value));
+ }
+ }
+ }
+
var search_input = document.getElementsByClassName("search-input")[0];
if (search_input) {
search_input.onfocus = function() {
- if (search_input.value !== "") {
- addClass(document.getElementById("main"), "hidden");
- removeClass(document.getElementById("search"), "hidden");
- if (browserSupportsHistoryApi()) {
- history.replaceState(search_input.value,
- "",
- "?search=" + encodeURIComponent(search_input.value));
- }
- }
+ putBackSearch(this);
};
}
.block a.current.crate { font-weight: 500; }
+.search-container {
+ position: relative;
+}
+.search-container > .top-button {
+ position: absolute;
+ right: 0;
+ top: 10px;
+}
.search-input {
- width: 100%;
+ width: calc(100% - 34px);
/* Override Normalize.css: we have margins and do
not want to overflow - the `moz` attribute is necessary
until Firefox 29, too early to drop at this point */
outline: none;
}
-#theme-picker {
+#settings-menu {
+ position: absolute;
+ right: 0;
+ top: 10px;
+ outline: none;
+}
+
+#theme-picker, #settings-menu {
padding: 4px;
width: 27px;
height: 29px;
--- /dev/null
+/**
+ * Copyright 2018 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.
+ */
+
+.setting-line {
+ padding: 5px;
+}
+
+.setting-line > div {
+ max-width: calc(100% - 74px);
+ display: inline-block;
+ vertical-align: top;
+ font-size: 17px;
+ padding-top: 2px;
+}
+
+.toggle {
+ position: relative;
+ display: inline-block;
+ width: 45px;
+ height: 27px;
+ margin-right: 20px;
+}
+
+.toggle input {
+ display: none;
+}
+
+.slider {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #ccc;
+ -webkit-transition: .3s;
+ transition: .3s;
+}
+
+.slider:before {
+ position: absolute;
+ content: "";
+ height: 19px;
+ width: 19px;
+ left: 4px;
+ bottom: 4px;
+ background-color: white;
+ -webkit-transition: .3s;
+ transition: .3s;
+}
+
+input:checked + .slider {
+ background-color: #2196F3;
+}
+
+input:focus + .slider {
+ box-shadow: 0 0 1px #2196F3;
+}
+
+input:checked + .slider:before {
+ -webkit-transform: translateX(19px);
+ -ms-transform: translateX(19px);
+ transform: translateX(19px);
+}
\ No newline at end of file
--- /dev/null
+/*!
+ * Copyright 2018 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.
+ */
+
+(function () {
+ function changeSetting(settingName, isEnabled) {
+ updateLocalStorage('rustdoc-' + settingName, isEnabled);
+ }
+
+ function getSettingValue(settingName) {
+ return getCurrentValue('rustdoc-' + settingName);
+ }
+
+ function setEvents() {
+ var elems = document.getElementsByClassName("slider");
+ if (!elems || elems.length === 0) {
+ return;
+ }
+ for (var i = 0; i < elems.length; ++i) {
+ var toggle = elems[i].previousElementSibling;
+ var settingId = toggle.id;
+ var settingValue = getSettingValue(settingId);
+ if (settingValue !== null) {
+ toggle.checked = settingValue === "true";
+ }
+ toggle.onchange = function() {
+ changeSetting(this.id, this.checked);
+ };
+ }
+ }
+
+ setEvents();
+})();
box-shadow-color: #c6cbd1;
}
-#theme-picker {
+#theme-picker, #settings-menu {
border-color: #e0e0e0;
background: #f0f0f0;
}
-#theme-picker:hover, #theme-picker:focus {
+#theme-picker:hover, #theme-picker:focus,
+#settings-menu:hover, #settings-menu:focus {
border-color: #ffb900;
}
box-shadow-color: #c6cbd1;
}
-#theme-picker {
+#theme-picker, #settings-menu {
border-color: #e0e0e0;
background-color: #fff;
}
-#theme-picker:hover, #theme-picker:focus {
+#theme-picker:hover, #theme-picker:focus,
+#settings-menu:hover, #settings-menu:focus {
border-color: #717171;
}
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 27.434 29.5" height="29.5px" id="Capa_1" version="1.1" viewBox="0 0 27.434 29.5" width="27.434px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g><path d="M27.315,18.389c-0.165-0.604-0.509-1.113-0.981-1.459c-0.042-0.144-0.083-0.429-0.015-0.761l0.037-0.177v-0.182V14.8 c0-1.247-0.006-1.277-0.048-1.472c-0.076-0.354-0.035-0.653,0.007-0.803c0.477-0.346,0.828-0.861,0.996-1.476 c0.261-0.956,0.076-2.091-0.508-3.114l-0.591-1.032c-0.746-1.307-1.965-2.119-3.182-2.119c-0.378,0-0.75,0.081-1.085,0.235 c-0.198-0.025-0.554-0.15-0.855-0.389l-0.103-0.082l-0.114-0.065l-1.857-1.067L18.92,3.36l-0.105-0.044 c-0.376-0.154-0.658-0.41-0.768-0.556C17.918,1.172,16.349,0,14.296,0H13.14c-2.043,0-3.608,1.154-3.749,2.721 C9.277,2.862,8.999,3.104,8.633,3.25l-0.1,0.039L8.439,3.341L6.495,4.406L6.363,4.479L6.245,4.573 C5.936,4.82,5.596,4.944,5.416,4.977c-0.314-0.139-0.66-0.21-1.011-0.21c-1.198,0-2.411,0.819-3.165,2.139L0.65,7.938 c-0.412,0.72-0.642,1.521-0.644,2.258c-0.003,0.952,0.362,1.756,1.013,2.256c0.034,0.155,0.061,0.448-0.016,0.786 c-0.038,0.168-0.062,0.28-0.062,1.563c0,1.148,0,1.148,0.015,1.262l0.009,0.073l0.017,0.073c0.073,0.346,0.045,0.643,0.011,0.802 C0.348,17.512-0.01,18.314,0,19.268c0.008,0.729,0.238,1.523,0.648,2.242l0.589,1.031c0.761,1.331,1.967,2.159,3.15,2.159 c0.324,0,0.645-0.064,0.938-0.187c0.167,0.038,0.492,0.156,0.813,0.416l0.11,0.088l0.124,0.07l2.045,1.156l0.102,0.057l0.107,0.043 c0.364,0.147,0.646,0.381,0.766,0.521c0.164,1.52,1.719,2.634,3.745,2.634h1.155c2.037,0,3.598-1.134,3.747-2.675 c0.117-0.145,0.401-0.393,0.774-0.549l0.111-0.047l0.105-0.062l1.96-1.159l0.105-0.062l0.097-0.075 c0.309-0.246,0.651-0.371,0.832-0.402c0.313,0.138,0.662,0.212,1.016,0.212c1.199,0,2.412-0.82,3.166-2.139l0.59-1.032 C27.387,20.48,27.575,19.342,27.315,18.389z M25.274,20.635l-0.59,1.032c-0.438,0.765-1.104,1.251-1.639,1.251 c-0.133,0-0.258-0.029-0.369-0.094c-0.15-0.086-0.346-0.127-0.566-0.127c-0.596,0-1.383,0.295-2.01,0.796l-1.96,1.157 c-1.016,0.425-1.846,1.291-1.846,1.929s-0.898,1.159-1.998,1.159H13.14c-1.1,0-1.998-0.514-1.998-1.141s-0.834-1.477-1.854-1.888 l-2.046-1.157c-0.636-0.511-1.425-0.814-2.006-0.814c-0.202,0-0.379,0.037-0.516,0.115c-0.101,0.057-0.214,0.084-0.333,0.084 c-0.518,0-1.179-0.498-1.62-1.271l-0.591-1.032c-0.545-0.954-0.556-1.983-0.024-2.286c0.532-0.305,0.78-1.432,0.551-2.506 c0,0,0-0.003,0-1.042c0-1.088,0.021-1.18,0.021-1.18c0.238-1.072-0.01-2.203-0.552-2.513C1.631,10.8,1.634,9.765,2.18,8.812 L2.769,7.78c0.438-0.766,1.103-1.251,1.636-1.251c0.131,0,0.255,0.029,0.365,0.092C4.92,6.707,5.114,6.747,5.334,6.747 c0.596,0,1.38-0.296,2.007-0.795l1.944-1.065c1.021-0.407,1.856-1.277,1.856-1.933c0-0.656,0.898-1.192,1.998-1.192h1.156V1.761 c1.1,0,1.998,0.545,1.998,1.211c0,0.667,0.832,1.554,1.849,1.973L20,6.013c0.618,0.489,1.401,0.775,2.012,0.775 c0.24,0,0.454-0.045,0.62-0.139c0.122-0.069,0.259-0.102,0.403-0.102c0.551,0,1.221,0.476,1.653,1.231l0.59,1.032 c0.544,0.953,0.518,2.004-0.062,2.334c-0.577,0.331-0.859,1.48-0.627,2.554c0,0,0.01,0.042,0.01,1.103c0,1.012,0,1.012,0,1.012 c-0.218,1.049,0.068,2.174,0.636,2.498C25.802,18.635,25.819,19.68,25.274,20.635z"/><path d="M13.61,7.611c-3.913,0-7.084,3.173-7.084,7.085c0,3.914,3.171,7.085,7.084,7.085s7.085-3.172,7.085-7.085 C20.695,10.784,17.523,7.611,13.61,7.611z M13.61,20.02c-2.936,0-5.323-2.388-5.323-5.323c0-2.935,2.388-5.323,5.323-5.323 s5.324,2.388,5.324,5.323C18.934,17.632,16.546,20.02,13.61,20.02z"/><path d="M13.682,9.908c-2.602,0-4.718,2.116-4.718,4.718c0,2.601,2.116,4.716,4.718,4.716c2.601,0,4.717-2.115,4.717-4.716 C18.399,12.024,16.283,9.908,13.682,9.908z M13.682,17.581c-1.633,0-2.956-1.323-2.956-2.955s1.323-2.956,2.956-2.956 c1.632,0,2.956,1.324,2.956,2.956S15.314,17.581,13.682,17.581z"/></g></svg>
\ No newline at end of file
lint_cap: Some(::rustc::lint::Level::Allow),
actually_rustdoc: true,
debugging_opts: config::DebuggingOptions {
- edition,
..config::basic_debugging_options()
},
+ edition,
..config::basic_options().clone()
};
test: as_test_harness,
unstable_features: UnstableFeatures::from_environment(),
debugging_opts: config::DebuggingOptions {
- edition,
..config::basic_debugging_options()
},
+ edition,
..config::basic_options().clone()
};
#![unstable(issue = "32838", feature = "allocator_api")]
#[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap;
-#[doc(inline)] pub use alloc_crate::alloc::Global;
+#[doc(inline)] pub use alloc_crate::alloc::{Global, oom};
#[doc(inline)] pub use alloc_system::System;
#[doc(inline)] pub use core::alloc::*;
+#[cfg(not(stage0))]
+#[cfg(not(test))]
+#[doc(hidden)]
+#[lang = "oom"]
+pub extern fn rust_oom() -> ! {
+ rtabort!("memory allocation failed");
+}
+
#[cfg(not(test))]
#[doc(hidden)]
#[allow(unused_attributes)]
System.alloc(layout) as *mut u8
}
+ #[cfg(stage0)]
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_oom() -> ! {
- System.oom()
+ super::oom()
}
#[no_mangle]
use self::Entry::*;
use self::VacantEntryState::*;
-use alloc::{Global, Alloc, CollectionAllocErr};
+use alloc::{CollectionAllocErr, oom};
use cell::Cell;
use borrow::Borrow;
use cmp::max;
pub fn reserve(&mut self, additional: usize) {
match self.try_reserve(additional) {
Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"),
- Err(CollectionAllocErr::AllocErr) => Global.oom(),
+ Err(CollectionAllocErr::AllocErr) => oom(),
Ok(()) => { /* yay */ }
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use alloc::{Global, Alloc, Layout, CollectionAllocErr};
+use alloc::{Global, Alloc, Layout, CollectionAllocErr, oom};
use cmp;
use hash::{BuildHasher, Hash, Hasher};
use marker;
unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> {
match Self::try_new_uninitialized(capacity) {
Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"),
- Err(CollectionAllocErr::AllocErr) => Global.oom(),
+ Err(CollectionAllocErr::AllocErr) => oom(),
Ok(table) => { table }
}
}
pub fn new(capacity: usize) -> RawTable<K, V> {
match Self::try_new(capacity) {
Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"),
- Err(CollectionAllocErr::AllocErr) => Global.oom(),
+ Err(CollectionAllocErr::AllocErr) => oom(),
Ok(table) => { table }
}
}
}
}
-#[stable(feature = "never_type", since = "1.26.0")]
+#[unstable(feature = "never_type", issue = "35121")]
impl Error for ! {
fn description(&self) -> &str { *self }
}
}
}
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl Error for num::TryFromIntError {
fn description(&self) -> &str {
self.__description()
}
}
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl Error for array::TryFromSliceError {
fn description(&self) -> &str {
self.__description()
}
}
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl Error for char::CharTryFromError {
fn description(&self) -> &str {
"converted integer out of range for `char`"
#![allow(missing_docs)]
#[cfg(not(test))]
-use core::num;
+#[cfg(stage0)]
+use core::num::Float;
#[cfg(not(test))]
use intrinsics;
#[cfg(not(test))]
+#[cfg(stage0)]
use num::FpCategory;
#[cfg(not(test))]
use sys::cmath;
pub use core::f32::consts;
#[cfg(not(test))]
-#[lang = "f32"]
+#[cfg_attr(stage0, lang = "f32")]
+#[cfg_attr(not(stage0), lang = "f32_runtime")]
impl f32 {
- /// Returns `true` if this value is `NaN` and false otherwise.
- ///
- /// ```
- /// use std::f32;
- ///
- /// let nan = f32::NAN;
- /// let f = 7.0_f32;
- ///
- /// assert!(nan.is_nan());
- /// assert!(!f.is_nan());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_nan(self) -> bool { num::Float::is_nan(self) }
-
- /// Returns `true` if this value is positive infinity or negative infinity and
- /// false otherwise.
- ///
- /// ```
- /// use std::f32;
- ///
- /// let f = 7.0f32;
- /// let inf = f32::INFINITY;
- /// let neg_inf = f32::NEG_INFINITY;
- /// let nan = f32::NAN;
- ///
- /// assert!(!f.is_infinite());
- /// assert!(!nan.is_infinite());
- ///
- /// assert!(inf.is_infinite());
- /// assert!(neg_inf.is_infinite());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_infinite(self) -> bool { num::Float::is_infinite(self) }
-
- /// Returns `true` if this number is neither infinite nor `NaN`.
- ///
- /// ```
- /// use std::f32;
- ///
- /// let f = 7.0f32;
- /// let inf = f32::INFINITY;
- /// let neg_inf = f32::NEG_INFINITY;
- /// let nan = f32::NAN;
- ///
- /// assert!(f.is_finite());
- ///
- /// assert!(!nan.is_finite());
- /// assert!(!inf.is_finite());
- /// assert!(!neg_inf.is_finite());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_finite(self) -> bool { num::Float::is_finite(self) }
-
- /// Returns `true` if the number is neither zero, infinite,
- /// [subnormal][subnormal], or `NaN`.
- ///
- /// ```
- /// use std::f32;
- ///
- /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32
- /// let max = f32::MAX;
- /// let lower_than_min = 1.0e-40_f32;
- /// let zero = 0.0_f32;
- ///
- /// assert!(min.is_normal());
- /// assert!(max.is_normal());
- ///
- /// assert!(!zero.is_normal());
- /// assert!(!f32::NAN.is_normal());
- /// assert!(!f32::INFINITY.is_normal());
- /// // Values between `0` and `min` are Subnormal.
- /// assert!(!lower_than_min.is_normal());
- /// ```
- /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_normal(self) -> bool { num::Float::is_normal(self) }
-
- /// Returns the floating point category of the number. If only one property
- /// is going to be tested, it is generally faster to use the specific
- /// predicate instead.
- ///
- /// ```
- /// use std::num::FpCategory;
- /// use std::f32;
- ///
- /// let num = 12.4_f32;
- /// let inf = f32::INFINITY;
- ///
- /// assert_eq!(num.classify(), FpCategory::Normal);
- /// assert_eq!(inf.classify(), FpCategory::Infinite);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn classify(self) -> FpCategory { num::Float::classify(self) }
+ #[cfg(stage0)]
+ f32_core_methods!();
/// Returns the largest integer less than or equal to a number.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn abs(self) -> f32 { num::Float::abs(self) }
+ pub fn abs(self) -> f32 {
+ unsafe { intrinsics::fabsf32(self) }
+ }
/// Returns a number that represents the sign of `self`.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn signum(self) -> f32 { num::Float::signum(self) }
-
- /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
- /// positive sign bit and positive infinity.
- ///
- /// ```
- /// let f = 7.0_f32;
- /// let g = -7.0_f32;
- ///
- /// assert!(f.is_sign_positive());
- /// assert!(!g.is_sign_positive());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) }
-
- /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
- /// negative sign bit and negative infinity.
- ///
- /// ```
- /// let f = 7.0f32;
- /// let g = -7.0f32;
- ///
- /// assert!(!f.is_sign_negative());
- /// assert!(g.is_sign_negative());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_sign_negative(self) -> bool { num::Float::is_sign_negative(self) }
+ pub fn signum(self) -> f32 {
+ if self.is_nan() {
+ NAN
+ } else {
+ unsafe { intrinsics::copysignf32(1.0, self) }
+ }
+ }
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding
/// error. This produces a more accurate result with better performance than
}
- /// Takes the reciprocal (inverse) of a number, `1/x`.
- ///
- /// ```
- /// use std::f32;
- ///
- /// let x = 2.0_f32;
- /// let abs_difference = (x.recip() - (1.0/x)).abs();
- ///
- /// assert!(abs_difference <= f32::EPSILON);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn recip(self) -> f32 { num::Float::recip(self) }
-
/// Raises a number to an integer power.
///
/// Using this function is generally faster than using `powf`
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn powi(self, n: i32) -> f32 { num::Float::powi(self, n) }
+ pub fn powi(self, n: i32) -> f32 {
+ unsafe { intrinsics::powif32(self, n) }
+ }
/// Raises a number to a floating point power.
///
return unsafe { intrinsics::log10f32(self) };
}
- /// Converts radians to degrees.
- ///
- /// ```
- /// use std::f32::{self, consts};
- ///
- /// let angle = consts::PI;
- ///
- /// let abs_difference = (angle.to_degrees() - 180.0).abs();
- ///
- /// assert!(abs_difference <= f32::EPSILON);
- /// ```
- #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")]
- #[inline]
- pub fn to_degrees(self) -> f32 { num::Float::to_degrees(self) }
-
- /// Converts degrees to radians.
- ///
- /// ```
- /// use std::f32::{self, consts};
- ///
- /// let angle = 180.0f32;
- ///
- /// let abs_difference = (angle.to_radians() - consts::PI).abs();
- ///
- /// assert!(abs_difference <= f32::EPSILON);
- /// ```
- #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")]
- #[inline]
- pub fn to_radians(self) -> f32 { num::Float::to_radians(self) }
-
- /// Returns the maximum of the two numbers.
- ///
- /// ```
- /// let x = 1.0f32;
- /// let y = 2.0f32;
- ///
- /// assert_eq!(x.max(y), y);
- /// ```
- ///
- /// If one of the arguments is NaN, then the other argument is returned.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn max(self, other: f32) -> f32 {
- num::Float::max(self, other)
- }
-
- /// Returns the minimum of the two numbers.
- ///
- /// ```
- /// let x = 1.0f32;
- /// let y = 2.0f32;
- ///
- /// assert_eq!(x.min(y), x);
- /// ```
- ///
- /// If one of the arguments is NaN, then the other argument is returned.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn min(self, other: f32) -> f32 {
- num::Float::min(self, other)
- }
-
/// The positive difference of two numbers.
///
/// * If `self <= other`: `0:0`
pub fn atanh(self) -> f32 {
0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
}
-
- /// Raw transmutation to `u32`.
- ///
- /// This is currently identical to `transmute::<f32, u32>(self)` on all platforms.
- ///
- /// See `from_bits` for some discussion of the portability of this operation
- /// (there are almost no issues).
- ///
- /// Note that this function is distinct from `as` casting, which attempts to
- /// preserve the *numeric* value, and not the bitwise value.
- ///
- /// # Examples
- ///
- /// ```
- /// assert_ne!((1f32).to_bits(), 1f32 as u32); // to_bits() is not casting!
- /// assert_eq!((12.5f32).to_bits(), 0x41480000);
- ///
- /// ```
- #[stable(feature = "float_bits_conv", since = "1.20.0")]
- #[inline]
- pub fn to_bits(self) -> u32 {
- num::Float::to_bits(self)
- }
-
- /// Raw transmutation from `u32`.
- ///
- /// This is currently identical to `transmute::<u32, f32>(v)` on all platforms.
- /// It turns out this is incredibly portable, for two reasons:
- ///
- /// * Floats and Ints have the same endianness on all supported platforms.
- /// * IEEE-754 very precisely specifies the bit layout of floats.
- ///
- /// However there is one caveat: prior to the 2008 version of IEEE-754, how
- /// to interpret the NaN signaling bit wasn't actually specified. Most platforms
- /// (notably x86 and ARM) picked the interpretation that was ultimately
- /// standardized in 2008, but some didn't (notably MIPS). As a result, all
- /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
- ///
- /// Rather than trying to preserve signaling-ness cross-platform, this
- /// implementation favours preserving the exact bits. This means that
- /// any payloads encoded in NaNs will be preserved even if the result of
- /// this method is sent over the network from an x86 machine to a MIPS one.
- ///
- /// If the results of this method are only manipulated by the same
- /// architecture that produced them, then there is no portability concern.
- ///
- /// If the input isn't NaN, then there is no portability concern.
- ///
- /// If you don't care about signalingness (very likely), then there is no
- /// portability concern.
- ///
- /// Note that this function is distinct from `as` casting, which attempts to
- /// preserve the *numeric* value, and not the bitwise value.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::f32;
- /// let v = f32::from_bits(0x41480000);
- /// let difference = (v - 12.5).abs();
- /// assert!(difference <= 1e-5);
- /// ```
- #[stable(feature = "float_bits_conv", since = "1.20.0")]
- #[inline]
- pub fn from_bits(v: u32) -> Self {
- num::Float::from_bits(v)
- }
}
#[cfg(test)]
#![allow(missing_docs)]
#[cfg(not(test))]
-use core::num;
+#[cfg(stage0)]
+use core::num::Float;
#[cfg(not(test))]
use intrinsics;
#[cfg(not(test))]
+#[cfg(stage0)]
use num::FpCategory;
#[cfg(not(test))]
use sys::cmath;
pub use core::f64::consts;
#[cfg(not(test))]
-#[lang = "f64"]
+#[cfg_attr(stage0, lang = "f64")]
+#[cfg_attr(not(stage0), lang = "f64_runtime")]
impl f64 {
- /// Returns `true` if this value is `NaN` and false otherwise.
- ///
- /// ```
- /// use std::f64;
- ///
- /// let nan = f64::NAN;
- /// let f = 7.0_f64;
- ///
- /// assert!(nan.is_nan());
- /// assert!(!f.is_nan());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_nan(self) -> bool { num::Float::is_nan(self) }
-
- /// Returns `true` if this value is positive infinity or negative infinity and
- /// false otherwise.
- ///
- /// ```
- /// use std::f64;
- ///
- /// let f = 7.0f64;
- /// let inf = f64::INFINITY;
- /// let neg_inf = f64::NEG_INFINITY;
- /// let nan = f64::NAN;
- ///
- /// assert!(!f.is_infinite());
- /// assert!(!nan.is_infinite());
- ///
- /// assert!(inf.is_infinite());
- /// assert!(neg_inf.is_infinite());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_infinite(self) -> bool { num::Float::is_infinite(self) }
-
- /// Returns `true` if this number is neither infinite nor `NaN`.
- ///
- /// ```
- /// use std::f64;
- ///
- /// let f = 7.0f64;
- /// let inf: f64 = f64::INFINITY;
- /// let neg_inf: f64 = f64::NEG_INFINITY;
- /// let nan: f64 = f64::NAN;
- ///
- /// assert!(f.is_finite());
- ///
- /// assert!(!nan.is_finite());
- /// assert!(!inf.is_finite());
- /// assert!(!neg_inf.is_finite());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_finite(self) -> bool { num::Float::is_finite(self) }
-
- /// Returns `true` if the number is neither zero, infinite,
- /// [subnormal][subnormal], or `NaN`.
- ///
- /// ```
- /// use std::f64;
- ///
- /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64
- /// let max = f64::MAX;
- /// let lower_than_min = 1.0e-308_f64;
- /// let zero = 0.0f64;
- ///
- /// assert!(min.is_normal());
- /// assert!(max.is_normal());
- ///
- /// assert!(!zero.is_normal());
- /// assert!(!f64::NAN.is_normal());
- /// assert!(!f64::INFINITY.is_normal());
- /// // Values between `0` and `min` are Subnormal.
- /// assert!(!lower_than_min.is_normal());
- /// ```
- /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_normal(self) -> bool { num::Float::is_normal(self) }
-
- /// Returns the floating point category of the number. If only one property
- /// is going to be tested, it is generally faster to use the specific
- /// predicate instead.
- ///
- /// ```
- /// use std::num::FpCategory;
- /// use std::f64;
- ///
- /// let num = 12.4_f64;
- /// let inf = f64::INFINITY;
- ///
- /// assert_eq!(num.classify(), FpCategory::Normal);
- /// assert_eq!(inf.classify(), FpCategory::Infinite);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn classify(self) -> FpCategory { num::Float::classify(self) }
+ #[cfg(stage0)]
+ f64_core_methods!();
/// Returns the largest integer less than or equal to a number.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn abs(self) -> f64 { num::Float::abs(self) }
+ pub fn abs(self) -> f64 {
+ unsafe { intrinsics::fabsf64(self) }
+ }
/// Returns a number that represents the sign of `self`.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn signum(self) -> f64 { num::Float::signum(self) }
-
- /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
- /// positive sign bit and positive infinity.
- ///
- /// ```
- /// let f = 7.0_f64;
- /// let g = -7.0_f64;
- ///
- /// assert!(f.is_sign_positive());
- /// assert!(!g.is_sign_positive());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")]
- #[inline]
- pub fn is_positive(self) -> bool { num::Float::is_sign_positive(self) }
-
- /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
- /// negative sign bit and negative infinity.
- ///
- /// ```
- /// let f = 7.0_f64;
- /// let g = -7.0_f64;
- ///
- /// assert!(!f.is_sign_negative());
- /// assert!(g.is_sign_negative());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_sign_negative(self) -> bool { num::Float::is_sign_negative(self) }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")]
- #[inline]
- pub fn is_negative(self) -> bool { num::Float::is_sign_negative(self) }
+ pub fn signum(self) -> f64 {
+ if self.is_nan() {
+ NAN
+ } else {
+ unsafe { intrinsics::copysignf64(1.0, self) }
+ }
+ }
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding
/// error. This produces a more accurate result with better performance than
}
}
- /// Takes the reciprocal (inverse) of a number, `1/x`.
- ///
- /// ```
- /// let x = 2.0_f64;
- /// let abs_difference = (x.recip() - (1.0/x)).abs();
- ///
- /// assert!(abs_difference < 1e-10);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn recip(self) -> f64 { num::Float::recip(self) }
-
/// Raises a number to an integer power.
///
/// Using this function is generally faster than using `powf`
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn powi(self, n: i32) -> f64 { num::Float::powi(self, n) }
+ pub fn powi(self, n: i32) -> f64 {
+ unsafe { intrinsics::powif64(self, n) }
+ }
/// Raises a number to a floating point power.
///
self.log_wrapper(|n| { unsafe { intrinsics::log10f64(n) } })
}
- /// Converts radians to degrees.
- ///
- /// ```
- /// use std::f64::consts;
- ///
- /// let angle = consts::PI;
- ///
- /// let abs_difference = (angle.to_degrees() - 180.0).abs();
- ///
- /// assert!(abs_difference < 1e-10);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn to_degrees(self) -> f64 { num::Float::to_degrees(self) }
-
- /// Converts degrees to radians.
- ///
- /// ```
- /// use std::f64::consts;
- ///
- /// let angle = 180.0_f64;
- ///
- /// let abs_difference = (angle.to_radians() - consts::PI).abs();
- ///
- /// assert!(abs_difference < 1e-10);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn to_radians(self) -> f64 { num::Float::to_radians(self) }
-
- /// Returns the maximum of the two numbers.
- ///
- /// ```
- /// let x = 1.0_f64;
- /// let y = 2.0_f64;
- ///
- /// assert_eq!(x.max(y), y);
- /// ```
- ///
- /// If one of the arguments is NaN, then the other argument is returned.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn max(self, other: f64) -> f64 {
- num::Float::max(self, other)
- }
-
- /// Returns the minimum of the two numbers.
- ///
- /// ```
- /// let x = 1.0_f64;
- /// let y = 2.0_f64;
- ///
- /// assert_eq!(x.min(y), x);
- /// ```
- ///
- /// If one of the arguments is NaN, then the other argument is returned.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn min(self, other: f64) -> f64 {
- num::Float::min(self, other)
- }
-
/// The positive difference of two numbers.
///
/// * If `self <= other`: `0:0`
}
}
}
-
- /// Raw transmutation to `u64`.
- ///
- /// This is currently identical to `transmute::<f64, u64>(self)` on all platforms.
- ///
- /// See `from_bits` for some discussion of the portability of this operation
- /// (there are almost no issues).
- ///
- /// Note that this function is distinct from `as` casting, which attempts to
- /// preserve the *numeric* value, and not the bitwise value.
- ///
- /// # Examples
- ///
- /// ```
- /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting!
- /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
- ///
- /// ```
- #[stable(feature = "float_bits_conv", since = "1.20.0")]
- #[inline]
- pub fn to_bits(self) -> u64 {
- num::Float::to_bits(self)
- }
-
- /// Raw transmutation from `u64`.
- ///
- /// This is currently identical to `transmute::<u64, f64>(v)` on all platforms.
- /// It turns out this is incredibly portable, for two reasons:
- ///
- /// * Floats and Ints have the same endianness on all supported platforms.
- /// * IEEE-754 very precisely specifies the bit layout of floats.
- ///
- /// However there is one caveat: prior to the 2008 version of IEEE-754, how
- /// to interpret the NaN signaling bit wasn't actually specified. Most platforms
- /// (notably x86 and ARM) picked the interpretation that was ultimately
- /// standardized in 2008, but some didn't (notably MIPS). As a result, all
- /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
- ///
- /// Rather than trying to preserve signaling-ness cross-platform, this
- /// implementation favours preserving the exact bits. This means that
- /// any payloads encoded in NaNs will be preserved even if the result of
- /// this method is sent over the network from an x86 machine to a MIPS one.
- ///
- /// If the results of this method are only manipulated by the same
- /// architecture that produced them, then there is no portability concern.
- ///
- /// If the input isn't NaN, then there is no portability concern.
- ///
- /// If you don't care about signalingness (very likely), then there is no
- /// portability concern.
- ///
- /// Note that this function is distinct from `as` casting, which attempts to
- /// preserve the *numeric* value, and not the bitwise value.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::f64;
- /// let v = f64::from_bits(0x4029000000000000);
- /// let difference = (v - 12.5).abs();
- /// assert!(difference <= 1e-5);
- /// ```
- #[stable(feature = "float_bits_conv", since = "1.20.0")]
- #[inline]
- pub fn from_bits(v: u64) -> Self {
- num::Float::from_bits(v)
- }
}
#[cfg(test)]
}
#[test]
+ #[allow(deprecated)]
fn read_char_buffered() {
let buf = [195, 159];
let reader = BufReader::with_capacity(1, &buf[..]);
}
#[test]
+ #[allow(deprecated)]
fn test_chars() {
let buf = [195, 159, b'a'];
let reader = BufReader::with_capacity(1, &buf[..]);
}
#[test]
+ #[allow(deprecated)]
fn test_read_char() {
let b = &b"Vi\xE1\xBB\x87t"[..];
let mut c = Cursor::new(b).chars();
}
#[test]
+ #[allow(deprecated)]
fn test_read_bad_char() {
let b = &b"\x80"[..];
let mut c = Cursor::new(b).chars();
of where errors happen is currently \
unclear and may change",
issue = "27802")]
+ #[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
+ https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
+ #[allow(deprecated)]
fn chars(self) -> Chars<Self> where Self: Sized {
Chars { inner: self }
}
/// [chars]: trait.Read.html#method.chars
#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
issue = "27802")]
+#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
+ https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
#[derive(Debug)]
+#[allow(deprecated)]
pub struct Chars<R> {
inner: R,
}
/// An enumeration of possible errors that can be generated from the `Chars`
/// adapter.
-#[derive(Debug)]
#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
issue = "27802")]
+#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
+ https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
+#[derive(Debug)]
+#[allow(deprecated)]
pub enum CharsError {
/// Variant representing that the underlying stream was read successfully
/// but it did not contain valid utf8 data.
#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
issue = "27802")]
+#[allow(deprecated)]
impl<R: Read> Iterator for Chars<R> {
type Item = result::Result<char, CharsError>;
#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
issue = "27802")]
+#[allow(deprecated)]
impl std_error::Error for CharsError {
fn description(&self) -> &str {
match *self {
#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
issue = "27802")]
+#[allow(deprecated)]
impl fmt::Display for CharsError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
#![feature(collections_range)]
#![feature(compiler_builtins_lib)]
#![feature(const_fn)]
-#![feature(core_float)]
+#![cfg_attr(stage0, feature(core_float))]
#![feature(core_intrinsics)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
#![feature(fs_read_write)]
#![feature(fixed_size_array)]
#![feature(float_from_str_radix)]
+#![cfg_attr(stage0, feature(float_internals))]
#![feature(fn_traits)]
#![feature(fnbox)]
#![cfg_attr(stage0, feature(generic_param_attrs))]
#![feature(macro_reexport)]
#![feature(macro_vis_matcher)]
#![feature(needs_panic_runtime)]
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![feature(nonzero)]
#![feature(num_bits_bytes)]
#![feature(test, rustc_private)]
#![feature(thread_local)]
#![feature(toowned_clone_into)]
+#![feature(try_from)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(untagged_unions)]
#![feature(doc_spotlight)]
#![cfg_attr(test, feature(update_panic_count))]
#![cfg_attr(windows, feature(used))]
+#![feature(doc_alias)]
#![default_lib_allocator]
pub use core::char;
#[stable(feature = "i128", since = "1.26.0")]
pub use core::u128;
+#[stable(feature = "core_hint", since = "1.27.0")]
+pub use core::hint;
pub mod f32;
pub mod f64;
pub mod process;
pub mod sync;
pub mod time;
-pub mod alloc;
#[unstable(feature = "allocator_api", issue = "32838")]
#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")]
mod sys_common;
mod sys;
+pub mod alloc;
+
// Private support modules
mod panicking;
mod memchr;
#[allow(deprecated)]
use os::android::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::bitrig::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::dragonfly::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::emscripten::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::freebsd::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
use fs::Metadata;
use sys_common::AsInner;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
#[stable(feature = "metadata_ext2", since = "1.8.0")]
#[allow(deprecated)]
use os::haiku::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::ios::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::linux::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::macos::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::netbsd::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::openbsd::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::solaris::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
// Iterate through `iter` while it matches `prefix`; return `None` if `prefix`
// is not a prefix of `iter`, otherwise return `Some(iter_after_prefix)` giving
// `iter` after having exhausted `prefix`.
-fn iter_after<A, I, J>(mut iter: I, mut prefix: J) -> Option<I>
- where I: Iterator<Item = A> + Clone,
- J: Iterator<Item = A>,
- A: PartialEq
+fn iter_after<'a, 'b, I, J>(mut iter: I, mut prefix: J) -> Option<I>
+ where I: Iterator<Item = Component<'a>> + Clone,
+ J: Iterator<Item = Component<'b>>,
{
loop {
let mut iter_next = iter.clone();
/// # Examples
///
/// ```
- /// use std::path::Path;
+ /// use std::path::{Path, PathBuf};
///
/// let path = Path::new("/test/haha/foo.txt");
///
/// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new("")));
/// assert_eq!(path.strip_prefix("test").is_ok(), false);
/// assert_eq!(path.strip_prefix("/haha").is_ok(), false);
+ ///
+ /// let prefix = PathBuf::from("/test/");
+ /// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt")));
/// ```
#[stable(since = "1.7.0", feature = "path_strip_prefix")]
- pub fn strip_prefix<'a, P: ?Sized>(&'a self, base: &'a P)
- -> Result<&'a Path, StripPrefixError>
+ pub fn strip_prefix<P>(&self, base: P)
+ -> Result<&Path, StripPrefixError>
where P: AsRef<Path>
{
self._strip_prefix(base.as_ref())
}
- fn _strip_prefix<'a>(&'a self, base: &'a Path)
- -> Result<&'a Path, StripPrefixError> {
+ fn _strip_prefix(&self, base: &Path)
+ -> Result<&Path, StripPrefixError> {
iter_after(self.components(), base.components())
.map(|c| c.as_path())
.ok_or(StripPrefixError(()))
// except according to those terms.
#[doc(primitive = "bool")]
+#[doc(alias = "true")]
+#[doc(alias = "false")]
//
/// The boolean type.
///
mod prim_bool { }
#[doc(primitive = "never")]
+#[doc(alias = "!")]
//
/// The `!` type, also called "never".
///
/// write:
///
/// ```
+/// #![feature(never_type)]
/// # fn foo() -> u32 {
/// let x: ! = {
/// return 123
/// for example:
///
/// ```
+/// #![feature(never_type)]
/// # use std::fmt;
/// # trait Debug {
/// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result;
mod prim_array { }
#[doc(primitive = "slice")]
+#[doc(alias = "[")]
+#[doc(alias = "]")]
+#[doc(alias = "[]")]
//
/// A dynamically-sized view into a contiguous sequence, `[T]`.
///
mod prim_str { }
#[doc(primitive = "tuple")]
+#[doc(alias = "(")]
+#[doc(alias = ")")]
+#[doc(alias = "()")]
//
/// A finite heterogeneous sequence, `(T, U, ..)`.
///
mod prim_usize { }
#[doc(primitive = "reference")]
+#[doc(alias = "&")]
//
/// References, both shared and mutable.
///
}
impl Child {
- /// Forces the child to exit. This is equivalent to sending a
- /// SIGKILL on unix platforms.
+ /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`]
+ /// error is returned.
+ ///
+ /// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function,
+ /// especially the [`Other`] kind might change to more specific kinds in the future.
+ ///
+ /// This is equivalent to sending a SIGKILL on Unix platforms.
///
/// # Examples
///
/// println!("yes command didn't start");
/// }
/// ```
+ ///
+ /// [`ErrorKind`]: ../io/enum.ErrorKind.html
+ /// [`InvalidInput`]: ../io/enum.ErrorKind.html#variant.InvalidInput
+ /// [`Other`]: ../io/enum.ErrorKind.html#variant.Other
#[stable(feature = "process", since = "1.0.0")]
pub fn kill(&mut self) -> io::Result<()> {
self.handle.kill()
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Unix-specific extension to the primitives in the `std::ffi` module
+//! Redox-specific extension to the primitives in the `std::ffi` module.
#![stable(feature = "rust1", since = "1.0.0")]
use sys::os_str::Buf;
use sys_common::{FromInner, IntoInner, AsInner};
-/// Unix-specific extensions to `OsString`.
+/// Redox-specific extensions to [`OsString`].
+///
+/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStringExt {
/// Creates an `OsString` from a byte vector.
}
}
-/// Unix-specific extensions to `OsStr`.
+/// Redox-specific extensions to [`OsStr`].
+///
+/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStrExt {
#[stable(feature = "rust1", since = "1.0.0")]
use sys;
use sys_common::{FromInner, AsInner, AsInnerMut};
-/// Redox-specific extensions to `Permissions`
+/// Redox-specific extensions to [`fs::Permissions`].
+///
+/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait PermissionsExt {
/// Returns the underlying raw `mode_t` bits that are the standard Redox
}
}
-/// Redox-specific extensions to `OpenOptions`
+/// Redox-specific extensions to [`fs::OpenOptions`].
+///
+/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait OpenOptionsExt {
/// Sets the mode bits that a new file will be created with.
}
}
-// Hm, why are there casts here to the returned type, shouldn't the types always
-// be the same? Right you are! Turns out, however, on android at least the types
-// in the raw `stat` structure are not the same as the types being returned. Who
-// knew!
-//
-// As a result to make sure this compiles for all platforms we do the manual
-// casts and rely on manual lowering to `stat` if the raw type is desired.
+/// Redox-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn blocks(&self) -> u64;
}
+// Hm, why are there casts here to the returned type, shouldn't the types always
+// be the same? Right you are! Turns out, however, on android at least the types
+// in the raw `stat` structure are not the same as the types being returned. Who
+// knew!
+//
+// As a result to make sure this compiles for all platforms we do the manual
+// casts and rely on manual lowering to `stat` if the raw type is desired.
#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for fs::Metadata {
fn dev(&self) -> u64 {
}
}
-/// Add special Redox types (block/char device, fifo and socket)
+/// Redox-specific extensions for [`FileType`].
+///
+/// Adds support for special Unix file types such as block/character devices,
+/// pipes, and sockets.
+///
+/// [`FileType`]: ../../../../std/fs/struct.FileType.html
#[stable(feature = "file_type_ext", since = "1.5.0")]
pub trait FileTypeExt {
/// Returns whether this file type is a block device.
sys::fs::symlink(src.as_ref(), dst.as_ref())
}
+/// Redox-specific extensions to [`fs::DirBuilder`].
+///
+/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
#[stable(feature = "dir_builder", since = "1.6.0")]
-/// An extension trait for `fs::DirBuilder` for Redox-specific options.
pub trait DirBuilderExt {
/// Sets the mode to create new directories with. This option defaults to
/// 0o777.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Unix-specific extensions to primitives in the `std::process` module.
+//! Redox-specific extensions to primitives in the `std::process` module.
#![stable(feature = "rust1", since = "1.0.0")]
use sys;
use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
-/// Unix-specific extensions to the `std::process::Command` builder
+/// Redox-specific extensions to the [`process::Command`] builder,
+///
+/// [`process::Command`]: ../../../../std/process/struct.Command.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait CommandExt {
/// Sets the child process's user id. This translates to a
}
}
-/// Unix-specific extensions to `std::process::ExitStatus`
+/// Redox-specific extensions to [`process::ExitStatus`].
+///
+/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ExitStatusExt {
/// Creates a new `ExitStatus` from the raw underlying `i32` return value of
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Unix-specific extensions to primitives in the `std::thread` module.
+//! Redox-specific extensions to primitives in the `std::thread` module.
#![stable(feature = "thread_extensions", since = "1.9.0")]
#[allow(deprecated)]
pub type RawPthread = usize;
-/// Unix-specific extensions to `std::thread::JoinHandle`
+/// Redox-specific extensions to [`thread::JoinHandle`].
+///
+/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html
#[stable(feature = "thread_extensions", since = "1.9.0")]
pub trait JoinHandleExt {
/// Extracts the raw pthread_t without taking ownership
use sys::os_str::Buf;
use sys_common::{FromInner, IntoInner, AsInner};
-/// Unix-specific extensions to `OsString`.
+/// Unix-specific extensions to [`OsString`].
+///
+/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStringExt {
/// Creates an [`OsString`] from a byte vector.
}
}
-/// Unix-specific extensions to `OsStr`.
+/// Unix-specific extensions to [`OsStr`].
+///
+/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStrExt {
#[stable(feature = "rust1", since = "1.0.0")]
}
}
-/// Unix-specific extensions to `Permissions`
+/// Unix-specific extensions to [`fs::Permissions`].
+///
+/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait PermissionsExt {
/// Returns the underlying raw `st_mode` bits that contain the standard
}
}
-/// Unix-specific extensions to `OpenOptions`
+/// Unix-specific extensions to [`fs::OpenOptions`].
+///
+/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait OpenOptionsExt {
/// Sets the mode bits that a new file will be created with.
}
}
-// Hm, why are there casts here to the returned type, shouldn't the types always
-// be the same? Right you are! Turns out, however, on android at least the types
-// in the raw `stat` structure are not the same as the types being returned. Who
-// knew!
-//
-// As a result to make sure this compiles for all platforms we do the manual
-// casts and rely on manual lowering to `stat` if the raw type is desired.
+/// Unix-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Returns the ID of the device containing the file.
fn blocks(&self) -> u64 { self.st_blocks() }
}
-/// Add support for special unix types (block/char device, fifo and socket).
+/// Unix-specific extensions for [`FileType`].
+///
+/// Adds support for special Unix file types such as block/character devices,
+/// pipes, and sockets.
+///
+/// [`FileType`]: ../../../../std/fs/struct.FileType.html
#[stable(feature = "file_type_ext", since = "1.5.0")]
pub trait FileTypeExt {
/// Returns whether this file type is a block device.
sys::fs::symlink(src.as_ref(), dst.as_ref())
}
-#[stable(feature = "dir_builder", since = "1.6.0")]
-/// An extension trait for [`fs::DirBuilder`] for unix-specific options.
+/// Unix-specific extensions to [`fs::DirBuilder`].
///
/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
+#[stable(feature = "dir_builder", since = "1.6.0")]
pub trait DirBuilderExt {
/// Sets the mode to create new directories with. This option defaults to
/// 0o777.
let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
// macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
- if len == 0 || (cfg!(not(target_os = "linux")) && self.addr.sun_path[0] == 0) {
+ if len == 0
+ || (cfg!(not(any(target_os = "linux", target_os = "android")))
+ && self.addr.sun_path[0] == 0)
+ {
AddressKind::Unnamed
} else if self.addr.sun_path[0] == 0 {
AddressKind::Abstract(&path[1..len])
use sys;
use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
-/// Unix-specific extensions to the `std::process::Command` builder
+/// Unix-specific extensions to the [`process::Command`] builder.
+///
+/// [`process::Command`]: ../../../../std/process/struct.Command.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait CommandExt {
/// Sets the child process's user id. This translates to a
}
}
-/// Unix-specific extensions to `std::process::ExitStatus`
+/// Unix-specific extensions to [`process::ExitStatus`].
+///
+/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ExitStatusExt {
/// Creates a new `ExitStatus` from the raw underlying `i32` return value of
#[allow(deprecated)]
pub type RawPthread = pthread_t;
-/// Unix-specific extensions to `std::thread::JoinHandle`
+/// Unix-specific extensions to [`thread::JoinHandle`].
+///
+/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html
#[stable(feature = "thread_extensions", since = "1.9.0")]
pub trait JoinHandleExt {
/// Extracts the raw pthread_t without taking ownership
#[stable(feature = "rust1", since = "1.0.0")]
pub use sys_common::wtf8::EncodeWide;
-/// Windows-specific extensions to `OsString`.
+/// Windows-specific extensions to [`OsString`].
+///
+/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStringExt {
/// Creates an `OsString` from a potentially ill-formed UTF-16 slice of
}
}
-/// Windows-specific extensions to `OsStr`.
+/// Windows-specific extensions to [`OsStr`].
+///
+/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStrExt {
/// Re-encodes an `OsStr` as a wide character sequence, i.e. potentially
}
}
-/// Windows-specific extensions to [`OpenOptions`].
+/// Windows-specific extensions to [`fs::OpenOptions`].
///
-/// [`OpenOptions`]: ../../../fs/struct.OpenOptions.html
+/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
#[stable(feature = "open_options_ext", since = "1.10.0")]
pub trait OpenOptionsExt {
/// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`]
}
}
-/// Extension methods for [`fs::Metadata`] to access the raw fields contained
-/// within.
+/// Windows-specific extensions to [`fs::Metadata`].
///
/// The data members that this trait exposes correspond to the members
/// of the [`BY_HANDLE_FILE_INFORMATION`] structure.
///
-/// [`fs::Metadata`]: ../../../fs/struct.Metadata.html
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
/// [`BY_HANDLE_FILE_INFORMATION`]:
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363788.aspx
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn file_size(&self) -> u64 { self.as_inner().size() }
}
-/// Add support for the Windows specific fact that a symbolic link knows whether it is a file
-/// or directory.
+/// Windows-specific extensions to [`FileType`].
+///
+/// On Windows, a symbolic link knows whether it is a file or directory.
+///
+/// [`FileType`]: ../../../../std/fs/struct.FileType.html
#[unstable(feature = "windows_file_type_ext", issue = "0")]
pub trait FileTypeExt {
/// Returns whether this file type is a symbolic link that is also a directory.
}
}
-/// Windows-specific extensions to `std::process::ExitStatus`
+/// Windows-specific extensions to [`process::ExitStatus`].
+///
+/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
#[stable(feature = "exit_status_from", since = "1.12.0")]
pub trait ExitStatusExt {
/// Creates a new `ExitStatus` from the raw underlying `u32` return value of
}
}
-/// Windows-specific extensions to the `std::process::Command` builder
+/// Windows-specific extensions to the [`process::Command`] builder.
+///
+/// [`process::Command`]: ../../../../std/process/struct.Command.html
#[stable(feature = "windows_process_extensions", since = "1.16.0")]
pub trait CommandExt {
/// Sets the [process creation flags][1] to be passed to `CreateProcess`.
}
impl Wtf8 {
- pub fn is_ascii(&self) -> bool {
- self.bytes.is_ascii()
- }
- pub fn to_ascii_uppercase(&self) -> Wtf8Buf {
- Wtf8Buf { bytes: self.bytes.to_ascii_uppercase() }
- }
- pub fn to_ascii_lowercase(&self) -> Wtf8Buf {
- Wtf8Buf { bytes: self.bytes.to_ascii_lowercase() }
- }
- pub fn eq_ignore_ascii_case(&self, other: &Wtf8) -> bool {
- self.bytes.eq_ignore_ascii_case(&other.bytes)
- }
-
pub fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() }
- pub fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() }
}
#[cfg(test)]
// when adding new editions, be sure to update:
//
- // - the list in the `parse_edition` static in librustc::session::config
+ // - Update the `ALL_EDITIONS` const
+ // - Update the EDITION_NAME_LIST const
// - add a `rust_####()` function to the session
// - update the enum in Cargo's sources as well
- //
- // When -Zedition becomes --edition, there will
- // also be a check for the edition being nightly-only
- // somewhere. That will need to be updated
- // whenever we're stabilizing/introducing a new edition
- // as well as changing the default Cargo template.
}
// must be in order from oldest to newest
pub const ALL_EDITIONS: &[Edition] = &[Edition::Edition2015, Edition::Edition2018];
+pub const EDITION_NAME_LIST: &'static str = "2015|2018";
+
+pub const DEFAULT_EDITION: Edition = Edition::Edition2015;
+
impl fmt::Display for Edition {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = match *self {
Edition::Edition2018 => "rust_2018_preview",
}
}
+
+ pub fn is_stable(&self) -> bool {
+ match *self {
+ Edition::Edition2015 => true,
+ Edition::Edition2018 => false,
+ }
+ }
}
impl FromStr for Edition {
Some(kind.expect_from_annotatables(items))
}
AttrProcMacro(ref mac) => {
+ self.gate_proc_macro_attr_item(attr.span, &item);
let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item {
Annotatable::Item(item) => token::NtItem(item),
Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()),
Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()),
Annotatable::Expr(expr) => token::NtExpr(expr),
})).into();
- let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_tok);
+ let input = self.extract_proc_macro_attr_input(attr.tokens, attr.span);
+ let tok_result = mac.expand(self.cx, attr.span, input, item_tok);
self.parse_expansion(tok_result, kind, &attr.path, attr.span)
}
ProcMacroDerive(..) | BuiltinDerive(..) => {
}
}
+ fn extract_proc_macro_attr_input(&self, tokens: TokenStream, span: Span) -> TokenStream {
+ let mut trees = tokens.trees();
+ match trees.next() {
+ Some(TokenTree::Delimited(_, delim)) => {
+ if trees.next().is_none() {
+ return delim.tts.into()
+ }
+ }
+ Some(TokenTree::Token(..)) => {}
+ None => return TokenStream::empty(),
+ }
+ self.cx.span_err(span, "custom attribute invocations must be \
+ of the form #[foo] or #[foo(..)], the macro name must only be \
+ followed by a delimiter token");
+ TokenStream::empty()
+ }
+
+ fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
+ let (kind, gate) = match *item {
+ Annotatable::Item(ref item) => {
+ match item.node {
+ ItemKind::Mod(_) if self.cx.ecfg.proc_macro_mod() => return,
+ ItemKind::Mod(_) => ("modules", "proc_macro_mod"),
+ _ => return,
+ }
+ }
+ Annotatable::TraitItem(_) => return,
+ Annotatable::ImplItem(_) => return,
+ Annotatable::ForeignItem(_) => return,
+ Annotatable::Stmt(_) |
+ Annotatable::Expr(_) if self.cx.ecfg.proc_macro_expr() => return,
+ Annotatable::Stmt(_) => ("statements", "proc_macro_expr"),
+ Annotatable::Expr(_) => ("expressions", "proc_macro_expr"),
+ };
+ emit_feature_err(
+ self.cx.parse_sess,
+ gate,
+ span,
+ GateIssue::Language,
+ &format!("custom attributes cannot be applied to {}", kind),
+ );
+ }
+
/// Expand a macro invocation. Returns the result of expansion.
fn expand_bang_invoc(&mut self,
invoc: Invocation,
self.cx.trace_macros_diag();
kind.dummy(span)
} else {
+ self.gate_proc_macro_expansion_kind(span, kind);
invoc.expansion_data.mark.set_expn_info(ExpnInfo {
call_site: span,
callee: NameAndSpan {
}
}
+ fn gate_proc_macro_expansion_kind(&self, span: Span, kind: ExpansionKind) {
+ let kind = match kind {
+ ExpansionKind::Expr => "expressions",
+ ExpansionKind::OptExpr => "expressions",
+ ExpansionKind::Pat => "patterns",
+ ExpansionKind::Ty => "types",
+ ExpansionKind::Stmts => "statements",
+ ExpansionKind::Items => return,
+ ExpansionKind::TraitItems => return,
+ ExpansionKind::ImplItems => return,
+ ExpansionKind::ForeignItems => return,
+ };
+ if self.cx.ecfg.proc_macro_non_items() {
+ return
+ }
+ emit_feature_err(
+ self.cx.parse_sess,
+ "proc_macro_non_items",
+ span,
+ GateIssue::Language,
+ &format!("procedural macros cannot be expanded to {}", kind),
+ );
+ }
+
/// Expand a derive invocation. Returns the result of expansion.
fn expand_derive_invoc(&mut self,
invoc: Invocation,
fn enable_custom_derive = custom_derive,
fn proc_macro_enabled = proc_macro,
fn macros_in_extern_enabled = macros_in_extern,
+ fn proc_macro_mod = proc_macro_mod,
+ fn proc_macro_expr = proc_macro_expr,
+ fn proc_macro_non_items = proc_macro_non_items,
}
}
// Allows cfg(target_has_atomic = "...").
(active, cfg_target_has_atomic, "1.9.0", Some(32976), None),
+ // The `!` type. Does not imply exhaustive_patterns (below) any more.
+ (active, never_type, "1.13.0", Some(35121), None),
+
// Allows exhaustive pattern matching on types that contain uninhabited types.
(active, exhaustive_patterns, "1.13.0", None, None),
(active, mmx_target_feature, "1.27.0", None, None),
(active, sse4a_target_feature, "1.27.0", None, None),
(active, tbm_target_feature, "1.27.0", None, None),
+
+ // Allows macro invocations of the form `#[foo::bar]`
+ (active, proc_macro_path_invoc, "1.27.0", None, None),
+
+ // Allows macro invocations on modules expressions and statements and
+ // procedural macros to expand to non-items.
+ (active, proc_macro_mod, "1.27.0", None, None),
+ (active, proc_macro_expr, "1.27.0", None, None),
+ (active, proc_macro_non_items, "1.27.0", None, None),
+
+ // #[doc(alias = "...")]
+ (active, doc_alias, "1.27.0", Some(50146), None),
);
declare_features! (
"the `#[naked]` attribute \
is an experimental feature",
cfg_fn!(naked_functions))),
- ("target_feature", Normal, Ungated),
+ ("target_feature", Whitelisted, Ungated),
("export_name", Whitelisted, Ungated),
("inline", Whitelisted, Ungated),
("link", Whitelisted, Ungated),
GateIssue::Library(lib) => lib,
};
- let explanation = if let Some(n) = issue {
- format!("{} (see issue #{})", explain, n)
- } else {
- explain.to_owned()
+ let explanation = match issue {
+ None | Some(0) => explain.to_owned(),
+ Some(n) => format!("{} (see issue #{})", explain, n)
};
let mut err = match level {
gate_feature_post!(&self, doc_spotlight, attr.span,
"#[doc(spotlight)] is experimental"
);
+ } else if content.iter().any(|c| c.check_name("alias")) {
+ gate_feature_post!(&self, doc_alias, attr.span,
+ "#[doc(alias = \"...\")] is experimental"
+ );
}
}
}
ast::TyKind::BareFn(ref bare_fn_ty) => {
self.check_abi(bare_fn_ty.abi, ty.span);
}
+ ast::TyKind::Never => {
+ gate_feature_post!(&self, never_type, ty.span,
+ "The `!` type is experimental");
+ }
ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => {
gate_feature_post!(&self, dyn_trait, ty.span,
"`dyn Trait` syntax is unstable");
}
}
ast::TraitItemKind::Type(_, ref default) => {
- // We use two if statements instead of something like match guards so that both
- // of these errors can be emitted if both cases apply.
+ // We use three if statements instead of something like match guards so that all
+ // of these errors can be emitted if all cases apply.
if default.is_some() {
gate_feature_post!(&self, associated_type_defaults, ti.span,
"associated type defaults are unstable");
gate_feature_post!(&self, generic_associated_types, ti.span,
"generic associated types are unstable");
}
+ if !ti.generics.where_clause.predicates.is_empty() {
+ gate_feature_post!(&self, generic_associated_types, ti.span,
+ "where clauses on associated types are unstable");
+ }
}
_ => {}
}
self.token_cursor.next()
};
if next.sp == syntax_pos::DUMMY_SP {
- next.sp = self.prev_span;
+ // Tweak the location for better diagnostics, but keep syntactic context intact.
+ next.sp = self.prev_span.with_ctxt(next.sp.ctxt());
}
next
}
vis: Visibility,
attrs: Vec<Attribute> )
-> PResult<'a, StructField> {
+ let mut seen_comma: bool = false;
let a_var = self.parse_name_and_ty(lo, vis, attrs)?;
+ if self.token == token::Comma {
+ seen_comma = true;
+ }
match self.token {
token::Comma => {
self.bump();
}
token::CloseDelim(token::Brace) => {}
token::DocComment(_) => {
+ let previous_span = self.prev_span;
let mut err = self.span_fatal_err(self.span, Error::UselessDocComment);
self.bump(); // consume the doc comment
- if self.eat(&token::Comma) || self.token == token::CloseDelim(token::Brace) {
+ let comma_after_doc_seen = self.eat(&token::Comma);
+ // `seen_comma` is always false, because we are inside doc block
+ // condition is here to make code more readable
+ if seen_comma == false && comma_after_doc_seen == true {
+ seen_comma = true;
+ }
+ if comma_after_doc_seen || self.token == token::CloseDelim(token::Brace) {
err.emit();
} else {
+ if seen_comma == false {
+ let sp = self.sess.codemap().next_point(previous_span);
+ err.span_suggestion(sp, "missing comma here", ",".into());
+ }
return Err(err);
}
}
#[derive(PartialEq)]
enum HasTestSignature {
Yes,
- No,
+ No(BadTestSignature),
+}
+
+#[derive(PartialEq)]
+enum BadTestSignature {
NotEvenAFunction,
+ WrongTypeSignature,
+ NoArgumentsAllowed,
+ ShouldPanicOnlyWithNoArgs,
}
fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
let has_test_attr = attr::contains_name(&i.attrs, "test");
fn has_test_signature(cx: &TestCtxt, i: &ast::Item) -> HasTestSignature {
+ let has_should_panic_attr = attr::contains_name(&i.attrs, "should_panic");
match i.node {
ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
// If the termination trait is active, the compiler will check that the output
// type implements the `Termination` trait as `libtest` enforces that.
- let output_matches = if cx.features.termination_trait_test {
- true
- } else {
- let no_output = match decl.output {
- ast::FunctionRetTy::Default(..) => true,
- ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true,
- _ => false
- };
-
- no_output && !generics.is_parameterized()
+ let has_output = match decl.output {
+ ast::FunctionRetTy::Default(..) => false,
+ ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => false,
+ _ => true
};
- if decl.inputs.is_empty() && output_matches {
- Yes
- } else {
- No
+ if !decl.inputs.is_empty() {
+ return No(BadTestSignature::NoArgumentsAllowed);
+ }
+
+ match (has_output, cx.features.termination_trait_test, has_should_panic_attr) {
+ (true, true, true) => No(BadTestSignature::ShouldPanicOnlyWithNoArgs),
+ (true, true, false) => if generics.is_parameterized() {
+ No(BadTestSignature::WrongTypeSignature)
+ } else {
+ Yes
+ },
+ (true, false, _) => No(BadTestSignature::WrongTypeSignature),
+ (false, _, _) => Yes
}
}
- _ => NotEvenAFunction,
+ _ => No(BadTestSignature::NotEvenAFunction),
}
}
let diag = cx.span_diagnostic;
match has_test_signature(cx, i) {
Yes => true,
- No => {
- if cx.features.termination_trait_test {
- diag.span_err(i.span, "functions used as tests can not have any arguments");
- } else {
- diag.span_err(i.span, "functions used as tests must have signature fn() -> ()");
+ No(cause) => {
+ match cause {
+ BadTestSignature::NotEvenAFunction =>
+ diag.span_err(i.span, "only functions may be used as tests"),
+ BadTestSignature::WrongTypeSignature =>
+ diag.span_err(i.span,
+ "functions used as tests must have signature fn() -> ()"),
+ BadTestSignature::NoArgumentsAllowed =>
+ diag.span_err(i.span, "functions used as tests can not have any arguments"),
+ BadTestSignature::ShouldPanicOnlyWithNoArgs =>
+ diag.span_err(i.span, "functions using `#[should_panic]` must return `()`"),
}
false
- },
- NotEvenAFunction => {
- diag.span_err(i.span, "only functions may be used as tests");
- false
- },
+ }
}
} else {
false
// well before resolve, can't get too deep.
input_cnt == 1 && output_matches
}
- _ => false
+ _ => false
}
}
name: "cmp",
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
- args: vec![borrowed_self()],
+ args: vec![(borrowed_self(), "other")],
ret_ty: Literal(path_std!(cx, cmp::Ordering)),
attributes: attrs,
is_unsafe: false,
}
pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
- let test_id = cx.ident_of("__cmp");
+ let test_id = cx.ident_of("cmp").gensym();
let equals_path = cx.path_global(span, cx.std_path(&["cmp", "Ordering", "Equal"]));
let cmp_path = cx.std_path(&["cmp", "Ord", "cmp"]);
// ::std::cmp::Ordering::Equal => {
// ...
// }
- // __cmp => __cmp
+ // cmp => cmp
// },
- // __cmp => __cmp
+ // cmp => cmp
// }
//
cs_fold(// foldr nests the if-elses correctly, leaving the first field
|cx, span, old, self_f, other_fs| {
// match new {
// ::std::cmp::Ordering::Equal => old,
- // __cmp => __cmp
+ // cmp => cmp
// }
let new = {
name: $name,
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
- args: vec![borrowed_self()],
+ args: vec![(borrowed_self(), "other")],
ret_ty: Literal(path_local!(bool)),
attributes: attrs,
is_unsafe: false,
name: $name,
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
- args: vec![borrowed_self()],
+ args: vec![(borrowed_self(), "other")],
ret_ty: Literal(path_local!(bool)),
attributes: attrs,
is_unsafe: false,
name: "partial_cmp",
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
- args: vec![borrowed_self()],
+ args: vec![(borrowed_self(), "other")],
ret_ty,
attributes: attrs,
is_unsafe: false,
}
pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
- let test_id = cx.ident_of("__cmp");
+ let test_id = cx.ident_of("cmp").gensym();
let ordering = cx.path_global(span, cx.std_path(&["cmp", "Ordering", "Equal"]));
let ordering_expr = cx.expr_path(ordering.clone());
let equals_expr = cx.expr_some(span, ordering_expr);
// ::std::option::Option::Some(::std::cmp::Ordering::Equal) => {
// ...
// }
- // __cmp => __cmp
+ // cmp => cmp
// },
- // __cmp => __cmp
+ // cmp => cmp
// }
//
cs_fold(// foldr nests the if-elses correctly, leaving the first field
|cx, span, old, self_f, other_fs| {
// match new {
// Some(::std::cmp::Ordering::Equal) => old,
- // __cmp => __cmp
+ // cmp => cmp
// }
let new = {
name: "fmt",
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
- args: vec![fmtr],
+ args: vec![(fmtr, "f")],
ret_ty: Literal(path_std!(cx, fmt::Result)),
attributes: Vec::new(),
is_unsafe: false,
// We want to make sure we have the ctxt set so that we can use unstable methods
let span = span.with_ctxt(cx.backtrace());
let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
- let builder = Ident::from_str("__debug_trait_builder");
+ let builder = Ident::from_str("debug_trait_builder").gensym();
let builder_expr = cx.expr_ident(span, builder.clone());
let fmt = substr.nonself_args[0].clone();
PathKind::Global)])],
},
explicit_self: None,
- args: vec![Ptr(Box::new(Literal(Path::new_local(typaram))),
- Borrowed(None, Mutability::Mutable))],
+ args: vec![(Ptr(Box::new(Literal(Path::new_local(typaram))),
+ Borrowed(None, Mutability::Mutable)), "d")],
ret_ty:
Literal(Path::new_(pathvec_std!(cx, result::Result),
None,
],
},
explicit_self: borrowed_explicit_self(),
- args: vec![Ptr(Box::new(Literal(Path::new_local(typaram))),
- Borrowed(None, Mutability::Mutable))],
+ args: vec![(Ptr(Box::new(Literal(Path::new_local(typaram))),
+ Borrowed(None, Mutability::Mutable)), "s")],
ret_ty: Literal(Path::new_(
pathvec_std!(cx, result::Result),
None,
pub explicit_self: Option<Option<PtrTy<'a>>>,
/// Arguments other than the self argument
- pub args: Vec<Ty<'a>>,
+ pub args: Vec<(Ty<'a>, &'a str)>,
/// Return type
pub ret_ty: Ty<'a>,
explicit_self
});
- for (i, ty) in self.args.iter().enumerate() {
+ for (ty, name) in self.args.iter() {
let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
- let ident = cx.ident_of(&format!("__arg_{}", i));
+ let ident = cx.ident_of(name).gensym();
arg_tys.push((ident, ast_ty));
let arg_expr = cx.expr_ident(trait_.span, ident);
///
/// // equivalent to:
/// impl PartialEq for A {
- /// fn eq(&self, __arg_1: &A) -> bool {
+ /// fn eq(&self, other: &A) -> bool {
/// match *self {
/// A {x: ref __self_0_0, y: ref __self_0_1} => {
- /// match *__arg_1 {
+ /// match *other {
/// A {x: ref __self_1_0, y: ref __self_1_1} => {
/// __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1)
/// }
/// // or if A is repr(packed) - note fields are matched by-value
/// // instead of by-reference.
/// impl PartialEq for A {
- /// fn eq(&self, __arg_1: &A) -> bool {
+ /// fn eq(&self, other: &A) -> bool {
/// match *self {
/// A {x: __self_0_0, y: __self_0_1} => {
- /// match __arg_1 {
+ /// match other {
/// A {x: __self_1_0, y: __self_1_1} => {
/// __self_0_0.eq(&__self_1_0) && __self_0_1.eq(&__self_1_1)
/// }
/// // is equivalent to
///
/// impl PartialEq for A {
- /// fn eq(&self, __arg_1: &A) -> ::bool {
- /// match (&*self, &*__arg_1) {
+ /// fn eq(&self, other: &A) -> ::bool {
+ /// match (&*self, &*other) {
/// (&A1, &A1) => true,
/// (&A2(ref self_0),
/// &A2(ref __arg_1_0)) => (*self_0).eq(&(*__arg_1_0)),
/// _ => {
/// let __self_vi = match *self { A1(..) => 0, A2(..) => 1 };
- /// let __arg_1_vi = match *__arg_1 { A1(..) => 0, A2(..) => 1 };
+ /// let __arg_1_vi = match *other { A1(..) => 0, A2(..) => 1 };
/// false
/// }
/// }
let vi_idents: Vec<ast::Ident> = self_arg_names.iter()
.map(|name| {
let vi_suffix = format!("{}_vi", &name[..]);
- cx.ident_of(&vi_suffix[..])
+ cx.ident_of(&vi_suffix[..]).gensym()
})
.collect::<Vec<ast::Ident>>();
let mut ident_exprs = Vec::new();
for (i, struct_field) in struct_def.fields().iter().enumerate() {
let sp = struct_field.span.with_ctxt(self.span.ctxt());
- let ident = cx.ident_of(&format!("{}_{}", prefix, i));
+ let ident = cx.ident_of(&format!("{}_{}", prefix, i)).gensym();
paths.push(ident.with_span_pos(sp));
let val = cx.expr_path(cx.path_ident(sp, ident));
let val = if use_temporaries {
bounds: vec![(typaram, vec![path_std!(cx, hash::Hasher)])],
},
explicit_self: borrowed_explicit_self(),
- args: vec![Ptr(Box::new(Literal(arg)),
- Borrowed(None, Mutability::Mutable))],
+ args: vec![(Ptr(Box::new(Literal(arg)),
+ Borrowed(None, Mutability::Mutable)), "state")],
ret_ty: nil_ty(),
attributes: vec![],
is_unsafe: false,
let mut pats = Vec::new();
let mut heads = Vec::new();
+ let names_pos: Vec<_> = (0..self.args.len()).map(|i| {
+ self.ecx.ident_of(&format!("arg{}", i)).gensym()
+ }).collect();
+
// First, build up the static array which will become our precompiled
// format "string"
let pieces = self.ecx.expr_vec_slice(self.fmtsp, self.str_pieces);
// of each variable because we don't want to move out of the arguments
// passed to this function.
for (i, e) in self.args.into_iter().enumerate() {
- let name = self.ecx.ident_of(&format!("__arg{}", i));
+ let name = names_pos[i];
let span =
DUMMY_SP.with_ctxt(e.span.ctxt().apply_mark(self.ecx.current_expansion.mark));
pats.push(self.ecx.pat_ident(span, name));
heads.push(self.ecx.expr_addr_of(e.span, e));
}
for pos in self.count_args {
- let name = self.ecx.ident_of(&match pos {
- Exact(i) => format!("__arg{}", i),
- _ => panic!("should never happen"),
- });
- let span = match pos {
- Exact(i) => spans_pos[i],
+ let index = match pos {
+ Exact(i) => i,
_ => panic!("should never happen"),
};
+ let name = names_pos[index];
+ let span = spans_pos[index];
counts.push(Context::format_arg(self.ecx, self.macsp, span, &Count, name));
}
use hygiene::SyntaxContext;
use {Span, DUMMY_SP, GLOBALS};
+use rustc_data_structures::fx::FxHashMap;
use serialize::{Decodable, Decoder, Encodable, Encoder};
-use std::collections::HashMap;
use std::fmt;
use std::hash::{Hash, Hasher};
pub fn modern(self) -> Ident {
Ident::new(self.name, self.span.modern())
}
+
+ pub fn gensym(self) -> Ident {
+ Ident::new(self.name.gensymed(), self.span)
+ }
}
impl PartialEq for Ident {
#[derive(Default)]
pub struct Interner {
- names: HashMap<Box<str>, Symbol>,
+ names: FxHashMap<Box<str>, Symbol>,
strings: Vec<Box<str>>,
gensyms: Vec<Symbol>,
}
// aux-build:nounwind.rs
// compile-flags: -C no-prepopulate-passes -C panic=abort -C metadata=a
// ignore-windows
+// ignore-android
#![crate_type = "lib"]
//! Attributes producing expressions in invalid locations
-#![feature(proc_macro, stmt_expr_attributes)]
+#![feature(proc_macro, stmt_expr_attributes, proc_macro_expr)]
extern crate attr_stmt_expr;
use attr_stmt_expr::{duplicate, no_output};
// aux-build:attr-stmt-expr.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_expr)]
extern crate attr_stmt_expr;
use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr};
// aux-build:attributes-included.rs
// ignore-stage1
-#![feature(proc_macro, rustc_attrs)]
+#![feature(proc_macro, rustc_attrs, proc_macro_path_invoc)]
#![warn(unused)]
extern crate attributes_included;
--- /dev/null
+// Copyright 2018 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.
+
+// no-prefer-dynamic
+// force-host
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro)]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro]
+pub fn m(a: TokenStream) -> TokenStream {
+ a
+}
+
+#[proc_macro_attribute]
+pub fn a(_a: TokenStream, b: TokenStream) -> TokenStream {
+ b
+}
// aux-build:bang_proc_macro2.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
#![allow(unused_macros)]
extern crate bang_proc_macro2;
// aux-build:bang_proc_macro.rs
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
#[macro_use]
extern crate bang_proc_macro;
--- /dev/null
+// Copyright 2018 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.
+
+// aux-build:proc-macro-gates.rs
+// gate-test-proc_macro_non_items
+// gate-test-proc_macro_path_invoc
+// gate-test-proc_macro_mod line
+// gate-test-proc_macro_expr
+// gate-test-proc_macro_mod
+
+#![feature(proc_macro, stmt_expr_attributes)]
+
+extern crate proc_macro_gates as foo;
+
+use foo::*;
+
+#[foo::a] //~ ERROR: paths of length greater than one
+fn _test() {}
+
+#[a] //~ ERROR: custom attributes cannot be applied to modules
+mod _test2 {}
+
+#[a = y] //~ ERROR: must only be followed by a delimiter token
+fn _test3() {}
+
+#[a = ] //~ ERROR: must only be followed by a delimiter token
+fn _test4() {}
+
+#[a () = ] //~ ERROR: must only be followed by a delimiter token
+fn _test5() {}
+
+fn main() {
+ #[a] //~ ERROR: custom attributes cannot be applied to statements
+ let _x = 2;
+ let _x = #[a] 2;
+ //~^ ERROR: custom attributes cannot be applied to expressions
+
+ let _x: m!(u32) = 3;
+ //~^ ERROR: procedural macros cannot be expanded to types
+ if let m!(Some(_x)) = Some(3) {
+ //~^ ERROR: procedural macros cannot be expanded to patterns
+ }
+ let _x = m!(3);
+ //~^ ERROR: procedural macros cannot be expanded to expressions
+ m!(let _x = 3;);
+ //~^ ERROR: procedural macros cannot be expanded to statements
+}
--- /dev/null
+// Copyright 2018 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.
+
+// aux-build:proc-macro-gates.rs
+
+#![feature(proc_macro, stmt_expr_attributes)]
+
+extern crate proc_macro_gates as foo;
+
+use foo::*;
+
+// NB. these errors aren't the best errors right now, but they're definitely
+// intended to be errors. Somehow using a custom attribute in these positions
+// should either require a feature gate or not be allowed on stable.
+
+fn _test6<#[a] T>() {}
+//~^ ERROR: unknown to the compiler
+
+fn _test7() {
+ match 1 {
+ #[a] //~ ERROR: unknown to the compiler
+ 0 => {}
+ _ => {}
+ }
+}
+
+fn main() {
+}
//~| the trait bound `usize:
//~| the trait bound `usize:
//~| the trait bound `usize:
-//~| the trait bound `usize:
fn main() {}
const B: i32 = (&A)[1];
//~^ ERROR constant evaluation error
//~| index out of bounds: the len is 0 but the index is 1
+//~| WARN this constant cannot be used
fn main() {
let _ = B;
const B: i32 = A[1];
//~^ ERROR constant evaluation error
//~| index out of bounds: the len is 0 but the index is 1
+//~| WARN this constant cannot be used
fn main() {
let _ = B;
// Test that we can't pass other types for !
+#![feature(never_type)]
+
fn foo(x: !) -> ! {
x
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
+
fn foo(x: usize, y: !, z: usize) { }
fn cast_a() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
+
fn foo(x: usize, y: !, z: usize) { }
fn call_foo_a() {
#![deny(const_err)]
-pub const A: i8 = -std::i8::MIN; //~ ERROR E0080
-//~^ ERROR attempt to negate with overflow
+pub const A: i8 = -std::i8::MIN; //~ ERROR const_err
+//~^ ERROR this constant cannot be used
//~| ERROR constant evaluation error
-pub const B: u8 = 200u8 + 200u8; //~ ERROR E0080
-//~^ ERROR attempt to add with overflow
-pub const C: u8 = 200u8 * 4; //~ ERROR E0080
-//~^ ERROR attempt to multiply with overflow
-pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR E0080
-//~^ ERROR attempt to subtract with overflow
+pub const B: u8 = 200u8 + 200u8; //~ ERROR const_err
+//~^ ERROR this constant cannot be used
+pub const C: u8 = 200u8 * 4; //~ ERROR const_err
+//~^ ERROR this constant cannot be used
+pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR const_err
+//~^ ERROR this constant cannot be used
pub const E: u8 = [5u8][1];
-//~^ ERROR E0080
+//~^ ERROR const_err
fn main() {
let _a = A;
//~^ ERROR E0080
//~| ERROR attempt to negate with overflow
//~| ERROR constant evaluation error
+//~| ERROR this constant cannot be used
pub const B: i8 = A;
-//~^ ERROR E0080
+//~^ ERROR const_err
pub const C: u8 = A as u8;
-//~^ ERROR E0080
+//~^ ERROR const_err
pub const D: i8 = 50 - A;
-//~^ ERROR E0080
+//~^ ERROR const_err
fn main() {
let _ = (A, B, C, D);
use std::{u8, u16, u32, u64, usize};
const VALS_I8: (i8,) =
+ //~^ ERROR this constant cannot be used
(
i8::MIN - 1,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to subtract with overflow
+ //~^ ERROR attempt to subtract with overflow
);
const VALS_I16: (i16,) =
+ //~^ ERROR this constant cannot be used
(
i16::MIN - 1,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to subtract with overflow
+ //~^ ERROR attempt to subtract with overflow
);
const VALS_I32: (i32,) =
+ //~^ ERROR this constant cannot be used
(
i32::MIN - 1,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to subtract with overflow
+ //~^ ERROR attempt to subtract with overflow
);
const VALS_I64: (i64,) =
+ //~^ ERROR this constant cannot be used
(
i64::MIN - 1,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to subtract with overflow
+ //~^ ERROR attempt to subtract with overflow
);
const VALS_U8: (u8,) =
+ //~^ ERROR this constant cannot be used
(
u8::MIN - 1,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to subtract with overflow
+ //~^ ERROR attempt to subtract with overflow
);
const VALS_U16: (u16,) = (
+ //~^ ERROR this constant cannot be used
u16::MIN - 1,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to subtract with overflow
+ //~^ ERROR attempt to subtract with overflow
);
const VALS_U32: (u32,) = (
+ //~^ ERROR this constant cannot be used
u32::MIN - 1,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to subtract with overflow
+ //~^ ERROR attempt to subtract with overflow
);
const VALS_U64: (u64,) =
+ //~^ ERROR this constant cannot be used
(
u64::MIN - 1,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to subtract with overflow
+ //~^ ERROR attempt to subtract with overflow
);
fn main() {
use std::{u8, u16, u32, u64, usize};
const VALS_I8: (i8,) =
+ //~^ ERROR this constant cannot be used
(
i8::MAX + 1,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to add with overflow
+ //~^ ERROR attempt to add with overflow
);
const VALS_I16: (i16,) =
+ //~^ ERROR this constant cannot be used
(
i16::MAX + 1,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to add with overflow
+ //~^ ERROR attempt to add with overflow
);
const VALS_I32: (i32,) =
+ //~^ ERROR this constant cannot be used
(
i32::MAX + 1,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to add with overflow
+ //~^ ERROR attempt to add with overflow
);
const VALS_I64: (i64,) =
+ //~^ ERROR this constant cannot be used
(
i64::MAX + 1,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to add with overflow
+ //~^ ERROR attempt to add with overflow
);
const VALS_U8: (u8,) =
+ //~^ ERROR this constant cannot be used
(
u8::MAX + 1,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to add with overflow
+ //~^ ERROR attempt to add with overflow
);
const VALS_U16: (u16,) = (
+ //~^ ERROR this constant cannot be used
u16::MAX + 1,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to add with overflow
+ //~^ ERROR attempt to add with overflow
);
const VALS_U32: (u32,) = (
+ //~^ ERROR this constant cannot be used
u32::MAX + 1,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to add with overflow
+ //~^ ERROR attempt to add with overflow
);
const VALS_U64: (u64,) =
+ //~^ ERROR this constant cannot be used
(
u64::MAX + 1,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to add with overflow
+ //~^ ERROR attempt to add with overflow
);
fn main() {
use std::{u8, u16, u32, u64, usize};
const VALS_I8: (i8,) =
+ //~^ ERROR this constant cannot be used
(
i8::MIN * 2,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to multiply with overflow
+ //~^ ERROR attempt to multiply with overflow
);
const VALS_I16: (i16,) =
+ //~^ ERROR this constant cannot be used
(
i16::MIN * 2,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to multiply with overflow
+ //~^ ERROR attempt to multiply with overflow
);
const VALS_I32: (i32,) =
+ //~^ ERROR this constant cannot be used
(
i32::MIN * 2,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to multiply with overflow
+ //~^ ERROR attempt to multiply with overflow
);
const VALS_I64: (i64,) =
+ //~^ ERROR this constant cannot be used
(
i64::MIN * 2,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to multiply with overflow
+ //~^ ERROR attempt to multiply with overflow
);
const VALS_U8: (u8,) =
+ //~^ ERROR this constant cannot be used
(
u8::MAX * 2,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to multiply with overflow
+ //~^ ERROR attempt to multiply with overflow
);
const VALS_U16: (u16,) = (
+ //~^ ERROR this constant cannot be used
u16::MAX * 2,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to multiply with overflow
+ //~^ ERROR attempt to multiply with overflow
);
const VALS_U32: (u32,) = (
+ //~^ ERROR this constant cannot be used
u32::MAX * 2,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to multiply with overflow
+ //~^ ERROR attempt to multiply with overflow
);
const VALS_U64: (u64,) =
+ //~^ ERROR this constant cannot be used
(
u64::MAX * 2,
- //~^ ERROR constant evaluation error
- //~| ERROR attempt to multiply with overflow
+ //~^ ERROR attempt to multiply with overflow
);
fn main() {
const BAR: u32 = FOO[5];
//~^ ERROR constant evaluation error [E0080]
//~| index out of bounds: the len is 3 but the index is 5
+//~| WARN this constant cannot be used
fn main() {
let _ = BAR;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// We need to opt inot the `!` feature in order to trigger the
+// requirement that this is testing.
+#![feature(never_type)]
+
#![allow(unused)]
trait Deserialize: Sized {
// except according to those terms.
// ignore-tidy-linelength
-// compile-flags: -Zedition=2015 -Zunstable-options
+// compile-flags: --edition=2015 -Zunstable-options
// tests that editions work with the tyvar warning-turned-error
// except according to those terms.
// ignore-tidy-linelength
-// compile-flags: -Zedition=2018 -Zunstable-options
+// compile-flags: --edition=2018 -Zunstable-options
// tests that editions work with the tyvar warning-turned-error
// #41719
-#![feature(use_extern_macros)]
+#![feature(use_extern_macros, proc_macro_path_invoc)]
fn main() {
enum Foo {}
// error-pattern:reached recursion limit
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
struct Foo<'a, T: 'a> {
+++ /dev/null
-// Copyright 2017 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.
-
-trait Foo {
- const AMT: usize;
-}
-
-enum Bar<A, B> {
- First(A),
- Second(B),
-}
-
-impl<A: Foo, B: Foo> Foo for Bar<A, B> {
- const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize];
-}
-
-impl Foo for u8 {
- const AMT: usize = 1;
-}
-
-impl Foo for u16 {
- const AMT: usize = 2;
-}
-
-fn main() {
- println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ E0080
-}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
+
fn main() {
let val: ! = loop { break break; };
//~^ ERROR mismatched types
// gate-test-use_extern_macros
+#![feature(proc_macro_path_invoc)]
+
fn main() {
globnar::brotz!(); //~ ERROR non-ident macro paths are experimental
#[derive(foo::Bar)] struct T; //~ ERROR non-ident macro paths are experimental
#![feature(asm)]
#![feature(trace_macros, concat_idents)]
+#![feature(proc_macro_path_invoc)]
#[derive(Default)] //~ ERROR
enum OrDeriveThis {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
mod private {
// Test that an assignment of type ! makes the rest of the block dead code.
+#![feature(never_type)]
#![feature(rustc_attrs)]
#![warn(unused)]
// Test that we can't use another type in place of !
+#![feature(never_type)]
#![deny(warnings)]
fn main() {
#![feature(decl_macro, associated_type_defaults)]
#![allow(unused, private_in_public)]
+#![feature(proc_macro_path_invoc)]
mod priv_nominal {
pub struct Pub;
// ignore-tidy-linelength
+#![feature(proc_macro_path_invoc)]
#![feature(decl_macro, associated_type_defaults)]
#![allow(unused, private_in_public)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(proc_macro_path_invoc)]
#![feature(decl_macro, associated_type_defaults)]
#![allow(unused, private_in_public)]
// error-pattern:type `fn(u8) -> ext::PubTupleStruct {ext::PubTupleStruct::{{constructor}}}` is priv
// error-pattern:type `for<'r> fn(&'r ext::Pub<u8>) {<ext::Pub<u8>>::priv_method}` is private
+#![feature(proc_macro_path_invoc)]
#![feature(decl_macro)]
extern crate private_inferred_type as ext;
#![feature(associated_consts)]
#![feature(decl_macro)]
#![allow(private_in_public)]
+#![feature(proc_macro_path_invoc)]
mod m {
fn priv_fn() {}
#![no_std]
// OK
-#[lang = "str"]
+#[lang = "str_alloc"]
impl str {}
impl str {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
mod foo {
#![feature(box_patterns)]
#![feature(box_syntax)]
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![feature(slice_patterns)]
#![deny(unreachable_patterns)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![deny(unreachable_patterns)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
#![feature(exhaustive_patterns, rustc_attrs)]
#![warn(unreachable_code)]
#![warn(unreachable_patterns)]
// Test that a variable of type ! can coerce to another type.
// error-pattern:explicit
+
+#![feature(never_type)]
+
fn main() {
let x: ! = panic!();
let y: u32 = x;
// error-pattern:wowzers!
+#![feature(never_type)]
#![allow(unreachable_code)]
fn foo(x: !) -> ! {
// Test that we can explicitly cast ! to another type
// error-pattern:explicit
+
+#![feature(never_type)]
+
fn main() {
let x: ! = panic!();
let y: u32 = x as u32;
// error-pattern:kapow!
+#![feature(never_type)]
+
trait Foo {
type Wow;
// error-pattern:oh no!
+#![feature(never_type)]
+
struct Wub;
impl PartialEq<!> for Wub {
// no-prefer-dynamic
#![crate_type = "proc-macro"]
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate proc_macro;
name: "eq",
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
- args: vec![borrowed_self()],
+ args: vec![(borrowed_self(), "other")],
ret_ty: Literal(deriving::generic::ty::Path::new_local("bool")),
attributes: attrs,
is_unsafe: false,
// no-prefer-dynamic
#![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib)]
+#![feature(proc_macro, proc_macro_lib, proc_macro_non_items)]
extern crate proc_macro;
// no-prefer-dynamic
#![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib)]
+#![feature(proc_macro, proc_macro_lib, proc_macro_non_items)]
extern crate proc_macro;
--- /dev/null
+// Copyright 2018 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.
+
+#![feature(rustc_private)]
+extern crate serialize;
+
+pub const other: u8 = 1;
+pub const f: u8 = 1;
+pub const d: u8 = 1;
+pub const s: u8 = 1;
+pub const state: u8 = 1;
+pub const cmp: u8 = 1;
+
+#[derive(Ord,Eq,PartialOrd,PartialEq,Debug,Decodable,Encodable,Hash)]
+struct Foo {}
+
+fn main() {
+}
// aux-build:cond_plugin.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate cond_plugin;
// aux-build:hello_macro.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_path_invoc, proc_macro_non_items)]
extern crate hello_macro;
// ignore-stage1
#![allow(warnings)]
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_path_invoc)]
extern crate attr_args;
use attr_args::attr_with_args;
#[attr_with_args(text = "Hello, world!")]
fn foo() {}
-#[::attr_args::identity
- fn main() { assert_eq!(foo(), "Hello, world!"); }]
+#[::attr_args::identity(
+ fn main() { assert_eq!(foo(), "Hello, world!"); })]
struct Dummy;
// aux-build:attr-on-trait.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_path_invoc)]
extern crate attr_on_trait;
// aux-build:attr-stmt-expr.rs
// ignore-stage1
-#![feature(proc_macro, stmt_expr_attributes)]
+#![feature(proc_macro, stmt_expr_attributes, proc_macro_stmt, proc_macro_expr)]
extern crate attr_stmt_expr;
use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr,
pub fn attr_with_args(args: TokenStream, input: TokenStream) -> TokenStream {
let args = args.to_string();
- assert_eq!(args, r#"( text = "Hello, world!" )"#);
+ assert_eq!(args, r#"text = "Hello, world!""#);
let input = input.to_string();
// no-prefer-dynamic
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
#![crate_type = "proc-macro"]
extern crate proc_macro;
// no-prefer-dynamic
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
#![crate_type = "proc-macro"]
extern crate proc_macro as proc_macro_renamed; // This does not break `quote!`
--- /dev/null
+// Copyright 2018 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.
+
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro)]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn check(_a: TokenStream, b: TokenStream) -> TokenStream {
+ b.into_iter().collect()
+}
// aux-build:bang-macro.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate bang_macro;
use bang_macro::rewrite;
// aux-build:count_compound_ops.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate count_compound_ops;
use count_compound_ops::count_compound_ops;
// aux-build:derive-b.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_path_invoc)]
extern crate derive_b;
// aux-build:hygiene_example.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate hygiene_example;
use hygiene_example::hello;
// aux-build:issue-42708.rs
// ignore-stage1
-#![feature(decl_macro, proc_macro)]
+#![feature(decl_macro, proc_macro, proc_macro_path_invoc)]
#![allow(unused)]
extern crate issue_42708;
--- /dev/null
+// Copyright 2018 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.
+
+// aux-build:issue-50061.rs
+// ignore-stage1
+
+#![feature(proc_macro, proc_macro_path_invoc, decl_macro)]
+
+extern crate issue_50061;
+
+macro inner(any_token $v: tt) {
+ $v
+}
+
+macro outer($v: tt) {
+ inner!(any_token $v)
+}
+
+#[issue_50061::check]
+fn main() {
+ //! this doc comment forces roundtrip through a string
+ let checkit = 0;
+ outer!(checkit);
+}
// aux-build:negative-token.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate negative_token;
// ignore-stage1
// ignore-cross-compile
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate proc_macro_def;
#![feature(allocator_api, nonnull)]
-use std::alloc::{Alloc, Global};
+use std::alloc::{Alloc, Global, oom};
fn main() {
unsafe {
- let ptr = Global.alloc_one::<i32>().unwrap_or_else(|_| {
- Global.oom()
- });
+ let ptr = Global.alloc_one::<i32>().unwrap_or_else(|_| oom());
*ptr.as_ptr() = 4;
assert_eq!(*ptr.as_ptr(), 4);
Global.dealloc_one(ptr);
--- /dev/null
+// Copyright 2018 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.
+
+#![feature(mmx_target_feature)]
+
+#[inline]
+#[target_feature(enable = "mmx")]
+pub unsafe fn foo() {}
// These represent current behavior, but are pretty dubious. I would
// like to revisit these and potentially change them. --nmatsakis
+#![feature(never_type)]
+
trait BadDefault {
fn default() -> Self;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![feature(slice_patterns)]
#![allow(unreachable_patterns)]
--- /dev/null
+// Copyright 2018 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.
+
+pub const arg0: u8 = 1;
+
+pub fn main() {
+ format!("{}", 1);
+}
// ignore-pretty pretty-printing is unhygienic
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
#![allow(unused)]
macro m($S:ident, $x:ident) {
// ignore-pretty pretty-printing is unhygienic
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
#![allow(unused)]
mod foo {
// aux-build:legacy_interaction.rs
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
#[allow(unused)]
extern crate legacy_interaction;
// ignore-pretty pretty-printing is unhygienic
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod bar {
mod baz {
// aux-build:my_crate.rs
// aux-build:unhygienic_example.rs
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
extern crate unhygienic_example;
extern crate my_crate; // (b)
// aux-build:xcrate.rs
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
extern crate xcrate;
// Test that we can call static methods on ! both directly and when it appears in a generic
+#![feature(never_type)]
+
trait StringifyType {
fn stringify_type() -> &'static str;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
// Regression test for inhabitedness check. The old
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
+
#[allow(unused)]
fn never_returns() {
loop {
// ignore-wasm32-bare compiled with panic=abort by default
#![feature(fn_traits)]
+#![feature(never_type)]
use std::panic;
// Test that we can extract a ! through pattern matching then use it as several different types.
+#![feature(never_type)]
+
fn main() {
let x: Result<u32, !> = Ok(123);
match x {
// aux-build:two_macros.rs
-#![feature(use_extern_macros)]
+#![feature(use_extern_macros, proc_macro_path_invoc)]
extern crate two_macros;
#![feature(heap_api, allocator_api)]
-use std::alloc::{Global, Alloc, Layout};
+use std::alloc::{Global, Alloc, Layout, oom};
use std::ptr::{self, NonNull};
fn main() {
println!("allocate({:?})", layout);
}
- let ret = Global.alloc(layout.clone()).unwrap_or_else(|_| Global.oom());
+ let ret = Global.alloc(layout.clone()).unwrap_or_else(|_| oom());
if PRINT {
println!("allocate({:?}) = {:?}", layout, ret);
}
let ret = Global.realloc(NonNull::new_unchecked(ptr).as_opaque(), old.clone(), new.size())
- .unwrap_or_else(|_| Global.oom());
+ .unwrap_or_else(|_| oom());
if PRINT {
println!("reallocate({:?}, old={:?}, new={:?}) = {:?}",
#![feature(allocator_api)]
-use std::alloc::{Alloc, Global, Layout};
+use std::alloc::{Alloc, Global, Layout, oom};
use std::ptr::NonNull;
struct arena(());
fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> {
unsafe {
let ptr = Global.alloc(Layout::new::<Bcx>())
- .unwrap_or_else(|_| Global.oom());
+ .unwrap_or_else(|_| oom());
&*(ptr.as_ptr() as *const _)
}
}
+++ /dev/null
-// Copyright 2017 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.
-
-// compile-flags: --test
-
-#![feature(termination_trait_test)]
-#![feature(test)]
-
-extern crate test;
-use std::num::ParseIntError;
-use test::Bencher;
-
-#[test]
-fn is_a_num() -> Result<(), ParseIntError> {
- let _: u32 = "22".parse()?;
- Ok(())
-}
-
-#[test]
-#[should_panic]
-fn not_a_num() -> Result<(), ParseIntError> {
- let _: u32 = "abc".parse()?;
- Ok(())
-}
-
-#[bench]
-fn test_a_positive_bench(_: &mut Bencher) -> Result<(), ParseIntError> {
- Ok(())
-}
-
-#[bench]
-#[should_panic]
-fn test_a_neg_bench(_: &mut Bencher) -> Result<(), ParseIntError> {
- let _: u32 = "abc".parse()?;
- Ok(())
-}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
use std::mem::size_of;
--- /dev/null
+// Copyright 2018 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.
+
+// only-x86_64
+// aux-build:using-target-feature-unstable.rs
+
+extern crate using_target_feature_unstable;
+
+fn main() {
+ unsafe {
+ using_target_feature_unstable::foo();
+ }
+}
--- /dev/null
+// Copyright 2018 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.
+
+const QUERY = '&';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'reference' },
+ ],
+};
--- /dev/null
+// Copyright 2018 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.
+
+const QUERY = '+';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std::ops::AddAssign', 'name': 'AddAssign' },
+ { 'path': 'std::ops::Add', 'name': 'Add' },
+ ],
+};
--- /dev/null
+// Copyright 2018 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.
+
+const QUERY = '!';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'never' },
+ ],
+};
--- /dev/null
+// Copyright 2018 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.
+
+const QUERY = '[';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'slice' },
+ { 'path': 'std::ops::IndexMut', 'name': 'IndexMut' },
+ { 'path': 'std::ops::Index', 'name': 'Index' },
+ ],
+};
--- /dev/null
+// Copyright 2018 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.
+
+const QUERY = '!';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'never' },
+ ],
+};
pub mod str {
#![doc(primitive = "str")]
- #[lang = "str"]
+ #[lang = "str_alloc"]
impl str {
// @has search-index.js foo
pub fn foo(&self) {}
// aux-build:parent-source-spans.rs
// ignore-stage1
-#![feature(proc_macro, decl_macro)]
+#![feature(proc_macro, decl_macro, proc_macro_non_items)]
extern crate parent_source_spans;
// aux-build:three-equals.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate three_equals;
fn ice<A>(a: A) {
let r = loop {};
r = r + a;
- //~^ ERROR the trait bound `!: Add<A>` is not satisfied
+ //~^ ERROR the trait bound `(): Add<A>` is not satisfied
}
-error[E0277]: the trait bound `!: Add<A>` is not satisfied
+error[E0277]: the trait bound `(): Add<A>` is not satisfied
--> $DIR/associated-types-ICE-when-projecting-out-of-err.rs:33:11
|
LL | r = r + a;
- | ^ the trait `Add<A>` is not implemented for `!`
+ | ^ the trait `Add<A>` is not implemented for `()`
error: aborting due to previous error
--- /dev/null
+// Copyright 2018 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.
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+trait Foo { }
+
+#[rustc_dump_program_clauses] //~ ERROR program clause dump
+trait Bar where Self: Foo { }
+
+#[rustc_dump_env_program_clauses] //~ ERROR program clause dump
+fn bar<T: Bar>() {
+}
+
+fn main() {
+}
--- /dev/null
+error: program clause dump
+ --> $DIR/lower_env1.rs:16:1
+ |
+LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: FromEnv(Self: Bar) :- FromEnv(Self: Bar).
+ = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
+ = note: Implemented(Self: Bar) :- FromEnv(Self: Bar).
+
+error: program clause dump
+ --> $DIR/lower_env1.rs:19:1
+ |
+LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: FromEnv(Self: Bar) :- FromEnv(Self: Bar).
+ = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
+ = note: Implemented(Self: Bar) :- FromEnv(Self: Bar).
+ = note: Implemented(Self: Foo) :- FromEnv(Self: Foo).
+ = note: Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized).
+
+error: aborting due to 2 previous errors
+
trait Foo { }
-#[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :-
+#[rustc_dump_program_clauses] //~ ERROR program clause dump
impl<T: 'static> Foo for T where T: Iterator<Item = i32> { }
trait Bar {
}
impl<T> Bar for T where T: Iterator<Item = i32> {
- #[rustc_dump_program_clauses] //~ ERROR Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :-
+ #[rustc_dump_program_clauses] //~ ERROR program clause dump
type Assoc = Vec<T>;
}
-error: Implemented(T: Foo) :- ProjectionEq(<T as std::iter::Iterator>::Item == i32), TypeOutlives(T : 'static), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized).
+error: program clause dump
--> $DIR/lower_impl.rs:15:1
|
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :-
+LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: Implemented(T: Foo) :- ProjectionEq(<T as std::iter::Iterator>::Item == i32), TypeOutlives(T : 'static), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized).
-error: Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :- Implemented(T: Bar).
+error: program clause dump
--> $DIR/lower_impl.rs:23:5
|
-LL | #[rustc_dump_program_clauses] //~ ERROR Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :-
+LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :- Implemented(T: Bar).
error: aborting due to 2 previous errors
#![feature(rustc_attrs)]
-#[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
- //~| ERROR FromEnv
- //~| ERROR FromEnv
- //~| ERROR FromEnv
+#[rustc_dump_program_clauses] //~ ERROR program clause dump
trait Foo<S, T, U> {
fn s(S) -> S;
fn t(T) -> T;
-error: Implemented(Self: Foo<S, T, U>) :- FromEnv(Self: Foo<S, T, U>).
+error: program clause dump
--> $DIR/lower_trait.rs:13:1
|
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
+LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
- --> $DIR/lower_trait.rs:13:1
- |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
- --> $DIR/lower_trait.rs:13:1
|
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(U: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
- --> $DIR/lower_trait.rs:13:1
- |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :-
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
+ = note: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
+ = note: FromEnv(U: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
+ = note: Implemented(Self: Foo<S, T, U>) :- FromEnv(Self: Foo<S, T, U>).
-error: aborting due to 4 previous errors
+error: aborting due to previous error
#![feature(rustc_attrs)]
-#[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :-
- //~| ERROR FromEnv
- //~| ERROR FromEnv
- //~| ERROR FromEnv
+#[rustc_dump_program_clauses] //~ ERROR program clause dump
trait Foo<F> where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8
{
fn s(F) -> F;
-error: Implemented(Self: Foo<F>) :- FromEnv(Self: Foo<F>).
+error: program clause dump
--> $DIR/lower_trait_higher_rank.rs:13:1
|
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :-
+LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(F: std::marker::Sized) :- FromEnv(Self: Foo<F>).
- --> $DIR/lower_trait_higher_rank.rs:13:1
- |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :-
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(F: std::ops::Fn<(&'a (u8, u16),)>) :- FromEnv(Self: Foo<F>).
- --> $DIR/lower_trait_higher_rank.rs:13:1
|
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :-
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(<F as std::ops::FnOnce<(&'a (u8, u16),)>>::Output == &'a u8) :- FromEnv(Self: Foo<F>).
- --> $DIR/lower_trait_higher_rank.rs:13:1
- |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :-
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: FromEnv(<F as std::ops::FnOnce<(&'a (u8, u16),)>>::Output == &'a u8) :- FromEnv(Self: Foo<F>).
+ = note: FromEnv(F: std::marker::Sized) :- FromEnv(Self: Foo<F>).
+ = note: FromEnv(F: std::ops::Fn<(&'a (u8, u16),)>) :- FromEnv(Self: Foo<F>).
+ = note: Implemented(Self: Foo<F>) :- FromEnv(Self: Foo<F>).
-error: aborting due to 4 previous errors
+error: aborting due to previous error
use std::fmt::{Debug, Display};
use std::borrow::Borrow;
-#[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
- //~| ERROR FromEnv
- //~| ERROR FromEnv
- //~| ERROR FromEnv
- //~| ERROR FromEnv
- //~| ERROR RegionOutlives
- //~| ERROR TypeOutlives
+#[rustc_dump_program_clauses] //~ ERROR program clause dump
trait Foo<'a, 'b, S, T, U> where S: Debug, T: Borrow<U>, U: ?Sized, 'a: 'b, U: 'b {
fn s(S) -> S;
fn t(T) -> T;
-error: Implemented(Self: Foo<'a, 'b, S, T, U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+error: program clause dump
--> $DIR/lower_trait_where_clause.rs:16:1
|
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
+LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
- --> $DIR/lower_trait_where_clause.rs:16:1
- |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
- --> $DIR/lower_trait_where_clause.rs:16:1
- |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(S: std::fmt::Debug) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
- --> $DIR/lower_trait_where_clause.rs:16:1
- |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: FromEnv(T: std::borrow::Borrow<U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
- --> $DIR/lower_trait_where_clause.rs:16:1
- |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: RegionOutlives('a : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
- --> $DIR/lower_trait_where_clause.rs:16:1
|
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: TypeOutlives(U : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
- --> $DIR/lower_trait_where_clause.rs:16:1
- |
-LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :-
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 7 previous errors
+ = note: FromEnv(S: std::fmt::Debug) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+ = note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+ = note: FromEnv(T: std::borrow::Borrow<U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+ = note: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+ = note: Implemented(Self: Foo<'a, 'b, S, T, U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+ = note: RegionOutlives('a : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+ = note: TypeOutlives(U : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+
+error: aborting due to previous error
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// compile-pass
+
const X: u32 = 5;
const Y: u32 = 6;
const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
//~^ WARN attempt to subtract with overflow
+//~| WARN this constant cannot be used
fn main() {
- println!("{}", FOO); //~ E0080
+ println!("{}", FOO);
+ //~^ WARN constant evaluation error
}
warning: attempt to subtract with overflow
- --> $DIR/conditional_array_execution.rs:13:19
+ --> $DIR/conditional_array_execution.rs:15:19
|
LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
| ^^^^^
|
= note: #[warn(const_err)] on by default
-error[E0080]: constant evaluation error
- --> $DIR/conditional_array_execution.rs:17:20
+warning: this constant cannot be used
+ --> $DIR/conditional_array_execution.rs:15:1
|
-LL | println!("{}", FOO); //~ E0080
- | ^^^ referenced constant has errors
+LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
-error: aborting due to previous error
+warning: constant evaluation error
+ --> $DIR/conditional_array_execution.rs:20:20
+ |
+LL | println!("{}", FOO);
+ | ^^^ referenced constant has errors
-For more information about this error, try `rustc --explain E0080`.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// compile-pass
+
#![feature(const_fn)]
const fn foo(x: u32) -> u32 {
fn main() {
const X: u32 = 0-1;
//~^ WARN attempt to subtract with overflow
+ //~| WARN this constant cannot be used
const Y: u32 = foo(0-1);
//~^ WARN attempt to subtract with overflow
+ //~| WARN this constant cannot be used
println!("{} {}", X, Y);
- //~^ ERROR constant evaluation error
- //~| ERROR constant evaluation error
+ //~^ WARN constant evaluation error
+ //~| WARN constant evaluation error
}
warning: attempt to subtract with overflow
- --> $DIR/issue-43197.rs:18:20
+ --> $DIR/issue-43197.rs:20:20
|
LL | const X: u32 = 0-1;
| ^^^
|
= note: #[warn(const_err)] on by default
-error[E0080]: constant evaluation error
- --> $DIR/issue-43197.rs:22:23
+warning: this constant cannot be used
+ --> $DIR/issue-43197.rs:20:5
|
-LL | println!("{} {}", X, Y);
- | ^ referenced constant has errors
+LL | const X: u32 = 0-1;
+ | ^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
warning: attempt to subtract with overflow
- --> $DIR/issue-43197.rs:20:24
+ --> $DIR/issue-43197.rs:23:24
|
LL | const Y: u32 = foo(0-1);
| ^^^
-error[E0080]: constant evaluation error
- --> $DIR/issue-43197.rs:22:26
+warning: this constant cannot be used
+ --> $DIR/issue-43197.rs:23:5
+ |
+LL | const Y: u32 = foo(0-1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+
+warning: constant evaluation error
+ --> $DIR/issue-43197.rs:26:23
|
LL | println!("{} {}", X, Y);
- | ^ referenced constant has errors
+ | ^ referenced constant has errors
-error: aborting due to 2 previous errors
+warning: constant evaluation error
+ --> $DIR/issue-43197.rs:26:26
+ |
+LL | println!("{} {}", X, Y);
+ | ^ referenced constant has errors
-For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+// Copyright 2017 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.
+
+// compile-pass
+
+trait Foo {
+ const AMT: usize;
+}
+
+enum Bar<A, B> {
+ First(A),
+ Second(B),
+}
+
+impl<A: Foo, B: Foo> Foo for Bar<A, B> {
+ const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize];
+}
+
+impl Foo for u8 {
+ const AMT: usize = 1;
+}
+
+impl Foo for u16 {
+ const AMT: usize = 2;
+}
+
+fn main() {
+ println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ WARN const_err
+ //~^ WARN const_err
+}
--- /dev/null
+warning: constant evaluation error
+ --> $DIR/issue-44578.rs:35:20
+ |
+LL | println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ WARN const_err
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+ |
+ = note: #[warn(const_err)] on by default
+
+warning: constant evaluation error
+ --> $DIR/issue-44578.rs:35:20
+ |
+LL | println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ WARN const_err
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+
--- /dev/null
+// Copyright 2018 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.
+
+// compile-pass
+// compile-flags: -O
+fn main() {
+ println!("{}", 0u32 - 1);
+ //~^ WARN const_err
+ //~| WARN const_err
+ let _x = 0u32 - 1;
+ //~^ WARN const_err
+ println!("{}", 1/(1-1));
+ //~^ WARN const_err
+ //~| WARN const_err
+ let _x = 1/(1-1);
+ //~^ WARN const_err
+ //~| WARN const_err
+ println!("{}", 1/(false as u32));
+ //~^ WARN const_err
+ let _x = 1/(false as u32);
+}
--- /dev/null
+warning: constant evaluation error
+ --> $DIR/promoted_errors.rs:14:20
+ |
+LL | println!("{}", 0u32 - 1);
+ | ^^^^^^^^ attempted to do overflowing math
+ |
+ = note: #[warn(const_err)] on by default
+
+warning: constant evaluation error
+ --> $DIR/promoted_errors.rs:14:20
+ |
+LL | println!("{}", 0u32 - 1);
+ | ^^^^^^^^ attempted to do overflowing math
+
+warning: constant evaluation error
+ --> $DIR/promoted_errors.rs:17:14
+ |
+LL | let _x = 0u32 - 1;
+ | ^^^^^^^^ attempted to do overflowing math
+
+warning: attempt to divide by zero
+ --> $DIR/promoted_errors.rs:19:20
+ |
+LL | println!("{}", 1/(1-1));
+ | ^^^^^^^
+
+warning: constant evaluation error
+ --> $DIR/promoted_errors.rs:19:20
+ |
+LL | println!("{}", 1/(1-1));
+ | ^^^^^^^ attempted to do overflowing math
+
+warning: attempt to divide by zero
+ --> $DIR/promoted_errors.rs:22:14
+ |
+LL | let _x = 1/(1-1);
+ | ^^^^^^^
+
+warning: constant evaluation error
+ --> $DIR/promoted_errors.rs:22:14
+ |
+LL | let _x = 1/(1-1);
+ | ^^^^^^^ attempted to do overflowing math
+
+warning: constant evaluation error
+ --> $DIR/promoted_errors.rs:25:20
+ |
+LL | println!("{}", 1/(false as u32));
+ | ^^^^^^^^^^^^^^^^ attempted to do overflowing math
+
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![deny(const_err)]
+// compile-pass
#![crate_type = "lib"]
pub const Z: u32 = 0 - 1;
-//~^ ERROR attempt to subtract with overflow
+//~^ WARN attempt to subtract with overflow
+//~| WARN this constant cannot be used
+
+pub type Foo = [i32; 0 - 1];
+//~^ WARN attempt to subtract with overflow
+//~| WARN this array length cannot be used
-error: attempt to subtract with overflow
+warning: attempt to subtract with overflow
--> $DIR/pub_const_err.rs:15:20
|
LL | pub const Z: u32 = 0 - 1;
| ^^^^^
|
-note: lint level defined here
- --> $DIR/pub_const_err.rs:11:9
+ = note: #[warn(const_err)] on by default
+
+warning: this constant cannot be used
+ --> $DIR/pub_const_err.rs:15:1
|
-LL | #![deny(const_err)]
- | ^^^^^^^^^
+LL | pub const Z: u32 = 0 - 1;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
-error: aborting due to previous error
+warning: attempt to subtract with overflow
+ --> $DIR/pub_const_err.rs:19:22
+ |
+LL | pub type Foo = [i32; 0 - 1];
+ | ^^^^^
+
+warning: this array length cannot be used
+ --> $DIR/pub_const_err.rs:19:22
+ |
+LL | pub type Foo = [i32; 0 - 1];
+ | ^^^^^ attempt to subtract with overflow
--- /dev/null
+// Copyright 2017 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.
+
+// compile-pass
+
+pub const Z: u32 = 0 - 1;
+//~^ WARN attempt to subtract with overflow
+//~| WARN this constant cannot be used
+
+pub type Foo = [i32; 0 - 1];
+//~^ WARN attempt to subtract with overflow
+//~| WARN this array length cannot be used
+
+fn main() {}
--- /dev/null
+warning: attempt to subtract with overflow
+ --> $DIR/pub_const_err_bin.rs:13:20
+ |
+LL | pub const Z: u32 = 0 - 1;
+ | ^^^^^
+ |
+ = note: #[warn(const_err)] on by default
+
+warning: this constant cannot be used
+ --> $DIR/pub_const_err_bin.rs:13:1
+ |
+LL | pub const Z: u32 = 0 - 1;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+
+warning: attempt to subtract with overflow
+ --> $DIR/pub_const_err_bin.rs:17:22
+ |
+LL | pub type Foo = [i32; 0 - 1];
+ | ^^^^^
+
+warning: this array length cannot be used
+ --> $DIR/pub_const_err_bin.rs:17:22
+ |
+LL | pub type Foo = [i32; 0 - 1];
+ | ^^^^^ attempt to subtract with overflow
+
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(try_from)]
+
use std::marker::PhantomData;
use std::convert::{TryFrom, AsRef};
error[E0119]: conflicting implementations of trait `std::convert::AsRef<Q>` for type `std::boxed::Box<Q>`:
- --> $DIR/conflict-with-std.rs:15:1
+ --> $DIR/conflict-with-std.rs:17:1
|
LL | impl AsRef<Q> for Box<Q> { //~ ERROR conflicting implementations
| ^^^^^^^^^^^^^^^^^^^^^^^^
where T: ?Sized;
error[E0119]: conflicting implementations of trait `std::convert::From<S>` for type `S`:
- --> $DIR/conflict-with-std.rs:22:1
+ --> $DIR/conflict-with-std.rs:24:1
|
LL | impl From<S> for S { //~ ERROR conflicting implementations
| ^^^^^^^^^^^^^^^^^^
- impl<T> std::convert::From<T> for T;
error[E0119]: conflicting implementations of trait `std::convert::TryFrom<X>` for type `X`:
- --> $DIR/conflict-with-std.rs:29:1
+ --> $DIR/conflict-with-std.rs:31:1
|
LL | impl TryFrom<X> for X { //~ ERROR conflicting implementations
| ^^^^^^^^^^^^^^^^^^^^^
--- /dev/null
+// Copyright 2018 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.
+
+#![feature(crate_in_paths)]
+#![deny(absolute_path_starting_with_module)]
+#![allow(unused)]
+
+pub mod foo {
+ use ::bar::Bar;
+ //~^ ERROR Absolute
+ //~| WARN this was previously accepted
+ use super::bar::Bar2;
+ use crate::bar::Bar3;
+}
+
+
+use bar::Bar;
+//~^ ERROR Absolute
+//~| WARN this was previously accepted
+
+pub mod bar {
+ pub struct Bar;
+ pub type Bar2 = Bar;
+ pub type Bar3 = Bar;
+}
+
+fn main() {
+ let x = ::bar::Bar;
+ //~^ ERROR Absolute
+ //~| WARN this was previously accepted
+ let x = bar::Bar;
+ let x = ::crate::bar::Bar;
+ let x = self::bar::Bar;
+}
--- /dev/null
+error: Absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+ --> $DIR/edition-lint-paths.rs:16:9
+ |
+LL | use ::bar::Bar;
+ | ^^^^^^^^^^ help: use `crate`: `crate::bar::Bar`
+ |
+note: lint level defined here
+ --> $DIR/edition-lint-paths.rs:12:9
+ |
+LL | #![deny(absolute_path_starting_with_module)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue TBD
+
+error: Absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+ --> $DIR/edition-lint-paths.rs:24:5
+ |
+LL | use bar::Bar;
+ | ^^^^^^^^ help: use `crate`: `crate::bar::Bar`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue TBD
+
+error: Absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+ --> $DIR/edition-lint-paths.rs:35:13
+ |
+LL | let x = ::bar::Bar;
+ | ^^^^^^^^^^ help: use `crate`: `crate::bar::Bar`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue TBD
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// Copyright 2018 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.
+
+#[doc(alias = "foo")] //~ ERROR: #[doc(alias = "...")] is experimental
+pub struct Foo;
+
+fn main() {}
--- /dev/null
+error[E0658]: #[doc(alias = "...")] is experimental (see issue #50146)
+ --> $DIR/feature-gate-doc_alias.rs:11:1
+ |
+LL | #[doc(alias = "foo")] //~ ERROR: #[doc(alias = "...")] is experimental
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(doc_alias)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
// <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.
-
+#![feature(never_type)]
fn foo() -> Result<u32, !> {
Ok(123)
}
//~^ ERROR generic associated types are unstable
type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
//~^ ERROR generic associated types are unstable
+ //~| ERROR where clauses on associated types are unstable
}
struct Foo;
//~^ ERROR generic associated types are unstable
}
+trait Bar {
+ type Assoc where Self: Sized;
+ //~^ ERROR where clauses on associated types are unstable
+}
+
+
fn main() {}
|
= help: add #![feature(generic_associated_types)] to the crate attributes to enable
+error[E0658]: where clauses on associated types are unstable (see issue #44265)
+ --> $DIR/feature-gate-generic_associated_types.rs:16:5
+ |
+LL | type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(generic_associated_types)] to the crate attributes to enable
+
error[E0658]: generic associated types are unstable (see issue #44265)
- --> $DIR/feature-gate-generic_associated_types.rs:22:5
+ --> $DIR/feature-gate-generic_associated_types.rs:23:5
|
LL | type Pointer<usize> = Box<usize>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: add #![feature(generic_associated_types)] to the crate attributes to enable
error[E0658]: generic associated types are unstable (see issue #44265)
- --> $DIR/feature-gate-generic_associated_types.rs:24:5
+ --> $DIR/feature-gate-generic_associated_types.rs:25:5
|
LL | type Pointer2<u32> = Box<u32>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(generic_associated_types)] to the crate attributes to enable
-error: aborting due to 4 previous errors
+error[E0658]: where clauses on associated types are unstable (see issue #44265)
+ --> $DIR/feature-gate-generic_associated_types.rs:30:5
+ |
+LL | type Assoc where Self: Sized;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(generic_associated_types)] to the crate attributes to enable
+
+error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Copyright 2012 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.
+
+// Test that ! errors when used in illegal positions with feature(never_type) disabled
+
+trait Foo {
+ type Wub;
+}
+
+type Ma = (u32, !, i32); //~ ERROR type is experimental
+type Meeshka = Vec<!>; //~ ERROR type is experimental
+type Mow = &fn(!) -> !; //~ ERROR type is experimental
+type Skwoz = &mut !; //~ ERROR type is experimental
+
+impl Foo for Meeshka {
+ type Wub = !; //~ ERROR type is experimental
+}
+
+fn main() {
+}
--- /dev/null
+error[E0658]: The `!` type is experimental (see issue #35121)
+ --> $DIR/feature-gate-never_type.rs:17:17
+ |
+LL | type Ma = (u32, !, i32); //~ ERROR type is experimental
+ | ^
+ |
+ = help: add #![feature(never_type)] to the crate attributes to enable
+
+error[E0658]: The `!` type is experimental (see issue #35121)
+ --> $DIR/feature-gate-never_type.rs:18:20
+ |
+LL | type Meeshka = Vec<!>; //~ ERROR type is experimental
+ | ^
+ |
+ = help: add #![feature(never_type)] to the crate attributes to enable
+
+error[E0658]: The `!` type is experimental (see issue #35121)
+ --> $DIR/feature-gate-never_type.rs:19:16
+ |
+LL | type Mow = &fn(!) -> !; //~ ERROR type is experimental
+ | ^
+ |
+ = help: add #![feature(never_type)] to the crate attributes to enable
+
+error[E0658]: The `!` type is experimental (see issue #35121)
+ --> $DIR/feature-gate-never_type.rs:20:19
+ |
+LL | type Skwoz = &mut !; //~ ERROR type is experimental
+ | ^
+ |
+ = help: add #![feature(never_type)] to the crate attributes to enable
+
+error[E0658]: The `!` type is experimental (see issue #35121)
+ --> $DIR/feature-gate-never_type.rs:23:16
+ |
+LL | type Wub = !; //~ ERROR type is experimental
+ | ^
+ |
+ = help: add #![feature(never_type)] to the crate attributes to enable
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Copyright 2018 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.
+
+extern crate core;
+
+// error should not say "(see issue #0)"
+#[allow(unused_imports)] use core::ptr::Unique; //~ ERROR use of unstable library feature
+
+fn main() {}
--- /dev/null
+error[E0658]: use of unstable library feature 'ptr_internals': use NonNull instead and consider PhantomData<T> (if you also use #[may_dangle]), Send, and/or Sync
+ --> $DIR/issue-49983-see-issue-0.rs:14:30
+ |
+LL | #[allow(unused_imports)] use core::ptr::Unique; //~ ERROR use of unstable library feature
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(ptr_internals)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
// ignore-pretty pretty-printing is unhygienic
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
struct S { x: u32 }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
pub fn f() {}
// ignore-pretty pretty-printing is unhygienic
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
struct S;
// error-pattern:type `fn() -> u32 {intercrate::foo::bar::f}` is private
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
extern crate intercrate;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
pub macro m() { Vec::new(); ().clone() }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
fn f() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
pub trait T {
| ^^^^^^^^
|
= help: items from traits can only be used if the trait is implemented and in scope
- = note: the following traits define an item `is_empty`, perhaps you need to implement one of them:
+ = note: the following trait defines an item `is_empty`, perhaps you need to implement it:
candidate #1: `std::iter::ExactSizeIterator`
- candidate #2: `core::slice::SliceExt`
- candidate #3: `core::str::StrExt`
error: aborting due to previous error
// aux-build:two_macros.rs
-#![feature(use_extern_macros)]
+#![feature(use_extern_macros, proc_macro_path_invoc)]
extern crate two_macros;
// aux-build:two_macros.rs
-#![feature(use_extern_macros)]
+#![feature(use_extern_macros, proc_macro_path_invoc)]
mod foo {
extern crate two_macros;
--- /dev/null
+// Copyright 2018 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.
+
+struct S {
+ x: u8
+ /// The id of the parent core
+ y: u8,
+}
+//~^^^ ERROR found a documentation comment that doesn't document anything
+fn main() {}
--- /dev/null
+error[E0585]: found a documentation comment that doesn't document anything
+ --> $DIR/issue-48636.rs:13:5
+ |
+LL | x: u8
+ | - help: missing comma here: `,`
+LL | /// The id of the parent core
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: doc comments must come before what they document, maybe a comment was intended with `//`?
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0585`.
macro_rules! real_method_stmt {
() => {
- 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
+ 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}`
}
}
macro_rules! real_method_expr {
() => {
- 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
+ 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}`
}
}
LL | fake_anon_field_stmt!();
| ------------------------ in this macro invocation
-error[E0689]: can't call method `powi` on ambiguous numeric type `{float}`
+error[E0689]: can't call method `recip` on ambiguous numeric type `{float}`
--> $DIR/macro-backtrace-invalid-internals.rs:51:15
|
-LL | 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
- | ^^^^
+LL | 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}`
+ | ^^^^^
...
LL | real_method_stmt!();
| -------------------- in this macro invocation
help: you must specify a concrete type for this numeric value, like `f32`
|
-LL | 2.0_f32.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
+LL | 2.0_f32.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}`
| ^^^^^^^
error[E0599]: no method named `fake` found for type `{integer}` in the current scope
LL | let _ = fake_anon_field_expr!();
| ----------------------- in this macro invocation
-error[E0689]: can't call method `powi` on ambiguous numeric type `{float}`
+error[E0689]: can't call method `recip` on ambiguous numeric type `{float}`
--> $DIR/macro-backtrace-invalid-internals.rs:57:15
|
-LL | 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
- | ^^^^
+LL | 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}`
+ | ^^^^^
...
LL | let _ = real_method_expr!();
| ------------------- in this macro invocation
help: you must specify a concrete type for this numeric value, like `f32`
|
-LL | 2.0_f32.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
+LL | 2.0_f32.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}`
| ^^^^^^^
error: aborting due to 8 previous errors
// compile-flags: -Z print-type-sizes
// compile-pass
+#![feature(never_type)]
#![feature(start)]
#[start]
// <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.
-
+#![feature(never_type)]
#![allow(unused_variables)]
#![deny(unreachable_code)]
// <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.
-
+#![feature(never_type)]
#![allow(unused_variables)]
#![allow(unused_assignments)]
#![allow(dead_code)]
// <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.
-
+#![feature(never_type)]
#![allow(unused_variables)]
#![allow(unused_assignments)]
#![allow(dead_code)]
#![allow(unused_assignments)]
#![allow(dead_code)]
#![deny(unreachable_code)]
-#![feature(type_ascription)]
+#![feature(never_type, type_ascription)]
fn a() {
// the cast is unreachable:
// <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.
-
+#![feature(never_type)]
#![allow(unused_variables)]
#![allow(unused_assignments)]
#![allow(dead_code)]
#![allow(unused_assignments)]
#![allow(dead_code)]
#![deny(unreachable_code)]
-#![feature(type_ascription)]
+#![feature(never_type, type_ascription)]
fn a() {
// the cast is unreachable:
// <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.
-
+#![feature(never_type)]
#![allow(unused_variables)]
#![allow(unused_assignments)]
#![allow(dead_code)]
--- /dev/null
+// Copyright 2017 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.
+
+// compile-flags: --test
+
+#![feature(termination_trait_test)]
+#![feature(test)]
+
+extern crate test;
+use std::num::ParseIntError;
+use test::Bencher;
+
+#[test]
+#[should_panic]
+fn not_a_num() -> Result<(), ParseIntError> {
+ //~^ ERROR functions using `#[should_panic]` must return `()`
+ let _: u32 = "abc".parse()?;
+ Ok(())
+}
--- /dev/null
+error: functions using `#[should_panic]` must return `()`
+ --> $DIR/termination-trait-in-test-should-panic.rs:22:1
+ |
+LL | / fn not_a_num() -> Result<(), ParseIntError> {
+LL | | //~^ ERROR functions using `#[should_panic]` must return `()`
+LL | | let _: u32 = "abc".parse()?;
+LL | | Ok(())
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2017 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.
+
+// compile-flags: --test
+// run-pass
+
+#![feature(termination_trait_test)]
+#![feature(test)]
+
+extern crate test;
+use std::num::ParseIntError;
+use test::Bencher;
+
+#[test]
+fn is_a_num() -> Result<(), ParseIntError> {
+ let _: u32 = "22".parse()?;
+ Ok(())
+}
+
+#[bench]
+fn test_a_positive_bench(_: &mut Bencher) -> Result<(), ParseIntError> {
+ Ok(())
+}
+
+#[bench]
+#[should_panic]
+fn test_a_neg_bench(_: &mut Bencher) -> Result<(), ParseIntError> {
+ let _: u32 = "abc".parse()?;
+ Ok(())
+}
// except according to those terms.
fn main() {
- let x = 2.0.powi(2);
- //~^ ERROR can't call method `powi` on ambiguous numeric type `{float}`
+ let x = 2.0.recip();
+ //~^ ERROR can't call method `recip` on ambiguous numeric type `{float}`
let y = 2.0;
- let x = y.powi(2);
- //~^ ERROR can't call method `powi` on ambiguous numeric type `{float}`
+ let x = y.recip();
+ //~^ ERROR can't call method `recip` on ambiguous numeric type `{float}`
println!("{:?}", x);
}
-error[E0689]: can't call method `powi` on ambiguous numeric type `{float}`
+error[E0689]: can't call method `recip` on ambiguous numeric type `{float}`
--> $DIR/method-on-ambiguous-numeric-type.rs:12:17
|
-LL | let x = 2.0.powi(2);
- | ^^^^
+LL | let x = 2.0.recip();
+ | ^^^^^
help: you must specify a concrete type for this numeric value, like `f32`
|
-LL | let x = 2.0_f32.powi(2);
+LL | let x = 2.0_f32.recip();
| ^^^^^^^
-error[E0689]: can't call method `powi` on ambiguous numeric type `{float}`
+error[E0689]: can't call method `recip` on ambiguous numeric type `{float}`
--> $DIR/method-on-ambiguous-numeric-type.rs:15:15
|
-LL | let x = y.powi(2);
- | ^^^^
+LL | let x = y.recip();
+ | ^^^^^
help: you must specify a type for this binding, like `f32`
|
LL | let y: f32 = 2.0;
BUILD_DIR="$1"
shift
+shopt -s nullglob
+
while [[ "$1" != "" ]]; do
- STDERR_NAME="${1/%.rs/.stderr}"
- STDERR_NLL_NAME="${1/%.rs/.nll.stderr}"
- STDOUT_NAME="${1/%.rs/.stdout}"
+ for EXT in "stderr" "stdout"; do
+ for OUT_NAME in $BUILD_DIR/${1%.rs}.*$EXT; do
+ OUT_BASE=`basename "$OUT_NAME"`
+ if ! (diff $OUT_NAME $MYDIR/$OUT_BASE >& /dev/null); then
+ echo updating $MYDIR/$OUT_BASE
+ cp $OUT_NAME $MYDIR
+ fi
+ done
+ done
shift
- if [ -f $BUILD_DIR/$STDOUT_NAME ] && \
- ! (diff $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME >& /dev/null); then
- echo updating $MYDIR/$STDOUT_NAME
- cp $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME
- fi
- if [ -f $BUILD_DIR/$STDERR_NAME ] && \
- ! (diff $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME >& /dev/null); then
- echo updating $MYDIR/$STDERR_NAME
- cp $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME
- fi
- if [ -f $BUILD_DIR/$STDERR_NLL_NAME ] && \
- ! (diff $BUILD_DIR/$STDERR_NLL_NAME $MYDIR/$STDERR_NLL_NAME >& /dev/null); then
- echo updating $MYDIR/$STDERR_NLL_NAME
- cp $BUILD_DIR/$STDERR_NLL_NAME $MYDIR/$STDERR_NLL_NAME
- fi
done
-Subproject commit 5ac4ab14f53fe8210befca9c9178a93f7df70a41
+Subproject commit 0a1add2d8689ad12a86f6c32d0a5cd0393dc5d80
use std::collections::HashMap;
use std::collections::HashSet;
use std::env;
-use std::ffi::OsString;
+use std::ffi::{OsStr, OsString};
use std::fs::{self, create_dir_all, File};
use std::fmt;
use std::io::prelude::*;
}
}
+trait PathBufExt {
+ /// Append an extension to the path, even if it already has one.
+ fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf;
+}
+
+impl PathBufExt for PathBuf {
+ fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
+ if extension.as_ref().len() == 0 {
+ self.clone()
+ } else {
+ let mut fname = self.file_name().unwrap().to_os_string();
+ if !extension.as_ref().to_str().unwrap().starts_with(".") {
+ fname.push(".");
+ }
+ fname.push(extension);
+ self.with_file_name(fname)
+ }
+ }
+}
+
// Produces a diff between the expected output and actual output.
pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Mismatch> {
let mut line_number = 1;
}
fn make_exe_name(&self) -> PathBuf {
- let mut f = self.output_base_name();
+ let mut f = self.output_base_name_stage();
// FIXME: This is using the host architecture exe suffix, not target!
if self.config.target.contains("emscripten") {
- let mut fname = f.file_name().unwrap().to_os_string();
- fname.push(".js");
- f.set_file_name(&fname);
+ f = f.with_extra_extension("js");
} else if self.config.target.contains("wasm32") {
- let mut fname = f.file_name().unwrap().to_os_string();
- fname.push(".wasm");
- f.set_file_name(&fname);
+ f = f.with_extra_extension("wasm");
} else if !env::consts::EXE_SUFFIX.is_empty() {
- let mut fname = f.file_name().unwrap().to_os_string();
- fname.push(env::consts::EXE_SUFFIX);
- f.set_file_name(&fname);
+ f = f.with_extra_extension(env::consts::EXE_SUFFIX);
}
f
}
}
fn aux_output_dir_name(&self) -> PathBuf {
- let f = self.output_base_name();
- let mut fname = f.file_name().unwrap().to_os_string();
- fname.push(&format!("{}.aux", self.config.mode.disambiguator()));
- f.with_file_name(&fname)
+ self.output_base_name_stage()
+ .with_extra_extension(self.config.mode.disambiguator())
+ .with_extra_extension(".aux")
}
fn output_testname(&self, filepath: &Path) -> PathBuf {
PathBuf::from(filepath.file_stem().unwrap())
}
- /// Given a test path like `compile-fail/foo/bar.rs` Returns a name like
- ///
- /// <output>/foo/bar-stage1
+ /// Given a test path like `compile-fail/foo/bar.rs` returns a name like
+ /// `/path/to/build/<triple>/test/compile-fail/foo/bar`.
fn output_base_name(&self) -> PathBuf {
let dir = self.config.build_base.join(&self.testpaths.relative_dir);
// Note: The directory `dir` is created during `collect_tests_from_dir`
dir.join(&self.output_testname(&self.testpaths.file))
- .with_extension(&self.config.stage_id)
+ }
+
+ /// Same as `output_base_name`, but includes the stage ID as an extension,
+ /// such as: `.../compile-fail/foo/bar.stage1-<triple>`
+ fn output_base_name_stage(&self) -> PathBuf {
+ self.output_base_name().with_extension(&self.config.stage_id)
}
fn maybe_dump_to_stdout(&self, out: &str, err: &str) {
fn run_rustdoc_test(&self) {
assert!(self.revision.is_none(), "revisions not relevant here");
- let out_dir = self.output_base_name();
+ let out_dir = self.output_base_name_stage();
let _ = fs::remove_dir_all(&out_dir);
create_dir_all(&out_dir).unwrap();
.unwrap();
let src_root = cwd.join(&src_root);
- let tmpdir = cwd.join(self.output_base_name());
+ let tmpdir = cwd.join(self.output_base_name_stage());
if tmpdir.exists() {
self.aggressive_rm_rf(&tmpdir).unwrap();
}
self.revision,
&self.config.compare_mode,
kind);
-
if !path.exists() && self.config.compare_mode.is_some() {
// fallback!
path = expected_output_path(&self.testpaths, self.revision, &None, kind);
}
}
- let expected_output = self.expected_output_path(kind);
- // #50113: output is abspath; only want filename component.
- let expected_output = expected_output.file_name().expect("output path requires file name");
- let output_file = self.output_base_name().with_file_name(&expected_output);
+ let mode = self.config.compare_mode.as_ref().map_or("", |m| m.to_str());
+ let output_file = self.output_base_name()
+ .with_extra_extension(self.revision.unwrap_or(""))
+ .with_extra_extension(mode)
+ .with_extra_extension(kind);
+
match File::create(&output_file).and_then(|mut f| f.write_all(actual.as_bytes())) {
Ok(()) => {}
Err(e) => self.fatal(&format!(
-Subproject commit d4712ca37500f26bbcbf97edcb27820717f769f7
+Subproject commit f48fed70d4447445b586a35c4ae88683542ffc72
clap = "2.25.0"
[dependencies.mdbook]
-version = "0.1.5"
+version = "0.1.7"
default-features = false
features = ["search"]
var toolchain = argv[2];
var mainJs = readFile("build/" + toolchain + "/doc/main.js");
+ var ALIASES = readFile("build/" + toolchain + "/doc/aliases.js");
var searchIndex = readFile("build/" + toolchain + "/doc/search-index.js").split("\n");
if (searchIndex[searchIndex.length - 1].length === 0) {
searchIndex.pop();
"execSearch"];
finalJS += 'window = { "currentCrate": "std" };\n';
+ finalJS += ALIASES;
finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs);
finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs);
finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs);
use std::path::Path;
-// See rust-lang/rust#48879: In addition to the mapping from `foo.rs`
-// to `foo.stderr`/`foo.stdout`, we also can optionally have
-// `foo.$mode.stderr`, where $mode is one of the strings on this list,
-// as an alternative to use when running under that mode.
-static COMPARE_MODE_NAMES: [&'static str; 1] = ["nll"];
-
pub fn check(path: &Path, bad: &mut bool) {
super::walk_many(&[&path.join("test/ui"), &path.join("test/ui-fulldeps")],
&mut |_| false,
&mut |file_path| {
if let Some(ext) = file_path.extension() {
- if (ext == "stderr" || ext == "stdout") && !file_path.with_extension("rs").exists() {
-
- // rust-lang/rust#48879: this fn used to be beautful
- // because Path API special-cases replacing
- // extensions. That works great for ".stderr" but not
- // so well for ".nll.stderr". To support the latter,
- // we explicitly search backwards for mode's starting
- // point and build corresponding source name.
- let filename = file_path.file_name().expect("need filename")
- .to_str().expect("need UTF-8 filename");
- let found_matching_prefix = COMPARE_MODE_NAMES.iter().any(|mode| {
- if let Some(r_idx) = filename.rfind(&format!(".{}", mode)) {
- let source_name = format!("{}.rs", &filename[0..r_idx]);
- let source_path = file_path.with_file_name(source_name);
- source_path.exists()
- } else {
- false
- }
- });
-
- if !found_matching_prefix {
+ if ext == "stderr" || ext == "stdout" {
+ // Test output filenames have the format:
+ // $testname.stderr
+ // $testname.$mode.stderr
+ // $testname.$revision.stderr
+ // $testname.$revision.$mode.stderr
+ //
+ // For now, just make sure that there is a corresponding
+ // $testname.rs file.
+ let testname = file_path.file_name().unwrap()
+ .to_str().unwrap()
+ .splitn(2, '.').next().unwrap();
+ if !file_path.with_file_name(testname)
+ .with_extension("rs")
+ .exists() {
println!("Stray file with UI testing output: {:?}", file_path);
*bad = true;
}