Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cargo
Submodule cargo updated 1 files
+0 −2 src/ci/docker/run.sh
22 changes: 16 additions & 6 deletions src/bootstrap/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,11 @@ def build_triple(self):
# The goal here is to come up with the same triple as LLVM would,
# at least for the subset of platforms we're willing to target.
if ostype == 'Linux':
ostype = 'unknown-linux-gnu'
os = subprocess.check_output(['uname', '-o']).strip().decode(default_encoding)
if os == 'Android':
ostype = 'linux-android'
else:
ostype = 'unknown-linux-gnu'
elif ostype == 'FreeBSD':
ostype = 'unknown-freebsd'
elif ostype == 'DragonFly':
Expand Down Expand Up @@ -464,15 +468,21 @@ def build_triple(self):
cputype = 'i686'
elif cputype in {'xscale', 'arm'}:
cputype = 'arm'
if ostype == 'linux-android':
ostype = 'linux-androideabi'
elif cputype == 'armv6l':
cputype = 'arm'
ostype += 'eabihf'
if ostype == 'linux-android':
ostype = 'linux-androideabi'
else:
ostype += 'eabihf'
elif cputype in {'armv7l', 'armv8l'}:
cputype = 'armv7'
ostype += 'eabihf'
elif cputype == 'aarch64':
cputype = 'aarch64'
elif cputype == 'arm64':
if ostype == 'linux-android':
ostype = 'linux-androideabi'
else:
ostype += 'eabihf'
elif cputype in {'aarch64', 'arm64'}:
cputype = 'aarch64'
elif cputype == 'mips':
if sys.byteorder == 'big':
Expand Down
40 changes: 29 additions & 11 deletions src/bootstrap/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,6 @@ pub fn linkcheck(build: &Build, host: &str) {
pub fn cargotest(build: &Build, stage: u32, host: &str) {
let ref compiler = Compiler::new(stage, host);

// Configure PATH to find the right rustc. NB. we have to use PATH
// and not RUSTC because the Cargo test suite has tests that will
// fail if rustc is not spelled `rustc`.
let path = build.sysroot(compiler).join("bin");
let old_path = ::std::env::var("PATH").expect("");
let sep = if cfg!(windows) { ";" } else {":" };
let ref newpath = format!("{}{}{}", path.display(), sep, old_path);

// Note that this is a short, cryptic, and not scoped directory name. This
// is currently to minimize the length of path on Windows where we otherwise
// quickly run into path name limit constraints.
Expand All @@ -95,9 +87,35 @@ pub fn cargotest(build: &Build, stage: u32, host: &str) {
let _time = util::timeit();
let mut cmd = Command::new(build.tool(&Compiler::new(0, host), "cargotest"));
build.prepare_tool_cmd(compiler, &mut cmd);
build.run(cmd.env("PATH", newpath)
.arg(&build.cargo)
.arg(&out_dir));
build.run(cmd.arg(&build.cargo)
.arg(&out_dir)
.env("RUSTC", build.compiler_path(compiler))
.env("RUSTDOC", build.rustdoc(compiler)))
}

/// Runs `cargo test` for `cargo` packaged with Rust.
pub fn cargo(build: &Build, stage: u32, host: &str) {
let ref compiler = Compiler::new(stage, host);

// Configure PATH to find the right rustc. NB. we have to use PATH
// and not RUSTC because the Cargo test suite has tests that will
// fail if rustc is not spelled `rustc`.
let path = build.sysroot(compiler).join("bin");
let old_path = ::std::env::var("PATH").expect("");
let sep = if cfg!(windows) { ";" } else {":" };
let ref newpath = format!("{}{}{}", path.display(), sep, old_path);

let mut cargo = build.cargo(compiler, Mode::Tool, host, "test");
cargo.arg("--manifest-path").arg(build.src.join("cargo/Cargo.toml"));

// Don't build tests dynamically, just a pain to work with
cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");

// Don't run cross-compile tests, we may not have cross-compiled libstd libs
// available.
cargo.env("CFG_DISABLE_CROSS_TESTS", "1");

build.run(cargo.env("PATH", newpath));
}

/// Runs the `tidy` tool as compiled in `stage` by the `host` compiler.
Expand Down
13 changes: 13 additions & 0 deletions src/bootstrap/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,19 @@ impl Build {
cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string());
}

// When being built Cargo will at some point call `nmake.exe` on Windows
// MSVC. Unfortunately `nmake` will read these two environment variables
// below and try to intepret them. We're likely being run, however, from
// MSYS `make` which uses the same variables.
//
// As a result, to prevent confusion and errors, we remove these
// variables from our environment to prevent passing MSYS make flags to
// nmake, causing it to blow up.
if cfg!(target_env = "msvc") {
cargo.env_remove("MAKE");
cargo.env_remove("MAKEFLAGS");
}

// Environment variables *required* needed throughout the build
//
// FIXME: should update code to not require this env var
Expand Down
1 change: 1 addition & 0 deletions src/bootstrap/mk/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ check:
check-aux:
$(Q)$(BOOTSTRAP) test \
src/tools/cargotest \
cargo \
src/test/pretty \
src/test/run-pass/pretty \
src/test/run-fail/pretty \
Expand Down
4 changes: 4 additions & 0 deletions src/bootstrap/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,10 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
.dep(|s| s.name("librustc"))
.host(true)
.run(move |s| check::cargotest(build, s.stage, s.target));
rules.test("check-cargo", "cargo")
.dep(|s| s.name("tool-cargo"))
.host(true)
.run(move |s| check::cargo(build, s.stage, s.target));
rules.test("check-tidy", "src/tools/tidy")
.dep(|s| s.name("tool-tidy").stage(0))
.default(true)
Expand Down
1 change: 1 addition & 0 deletions src/doc/unstable-book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@
- [slice_rsplit](library-features/slice-rsplit.md)
- [sort_internals](library-features/sort-internals.md)
- [sort_unstable](library-features/sort-unstable.md)
- [splice](library-features/splice.md)
- [step_by](library-features/step-by.md)
- [step_trait](library-features/step-trait.md)
- [str_checked_slicing](library-features/str-checked-slicing.md)
Expand Down
24 changes: 24 additions & 0 deletions src/doc/unstable-book/src/library-features/splice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# `splice`

The tracking issue for this feature is: [#32310]

[#32310]: https://github.com/rust-lang/rust/issues/32310

------------------------

The `splice()` method on `Vec` and `String` allows you to replace a range
of values in a vector or string with another range of values, and returns
the replaced values.

A simple example:

```rust
#![feature(splice)]
let mut s = String::from("α is alpha, β is beta");
let beta_offset = s.find('β').unwrap_or(s.len());

// Replace the range up until the β from the string
let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect();
assert_eq!(t, "α is alpha, ");
assert_eq!(s, "Α is capital alpha; β is beta");
```
6 changes: 1 addition & 5 deletions src/libcollections/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1519,13 +1519,9 @@ impl<T: Clone> ToOwned for [T] {
self.to_vec()
}

// HACK(japaric): with cfg(test) the inherent `[T]::to_vec`, which is required for this method
// definition, is not available. Since we don't require this method for testing purposes, I'll
// just stub it
// NB see the slice::hack module in slice.rs for more information
#[cfg(test)]
fn to_owned(&self) -> Vec<T> {
panic!("not available with cfg(test)")
hack::to_vec(self)
}

fn clone_into(&self, target: &mut Vec<T>) {
Expand Down
125 changes: 124 additions & 1 deletion src/libcollections/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1316,7 +1316,7 @@ impl String {
self.vec.clear()
}

/// Create a draining iterator that removes the specified range in the string
/// Creates a draining iterator that removes the specified range in the string
/// and yields the removed chars.
///
/// Note: The element range is removed even if the iterator is not
Expand Down Expand Up @@ -1382,6 +1382,71 @@ impl String {
}
}

/// Creates a splicing iterator that removes the specified range in the string,
/// replaces with the given string, and yields the removed chars.
/// The given string doesn’t need to be the same length as the range.
///
/// Note: The element range is removed when the `Splice` is dropped,
/// even if the iterator is not consumed until the end.
///
/// # Panics
///
/// Panics if the starting point or end point do not lie on a [`char`]
/// boundary, or if they're out of bounds.
///
/// [`char`]: ../../std/primitive.char.html
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(splice)]
/// let mut s = String::from("α is alpha, β is beta");
/// let beta_offset = s.find('β').unwrap_or(s.len());
///
/// // Replace the range up until the β from the string
/// let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect();
/// assert_eq!(t, "α is alpha, ");
/// assert_eq!(s, "Α is capital alpha; β is beta");
/// ```
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
pub fn splice<'a, 'b, R>(&'a mut self, range: R, replace_with: &'b str) -> Splice<'a, 'b>
where R: RangeArgument<usize>
{
// Memory safety
//
// The String version of Splice does not have the memory safety issues
// of the vector version. The data is just plain bytes.
// Because the range removal happens in Drop, if the Splice iterator is leaked,
// the removal will not happen.
let len = self.len();
let start = match range.start() {
Included(&n) => n,
Excluded(&n) => n + 1,
Unbounded => 0,
};
let end = match range.end() {
Included(&n) => n + 1,
Excluded(&n) => n,
Unbounded => len,
};

// Take out two simultaneous borrows. The &mut String won't be accessed
// until iteration is over, in Drop.
let self_ptr = self as *mut _;
// slicing does the appropriate bounds checks
let chars_iter = self[start..end].chars();

Splice {
start: start,
end: end,
iter: chars_iter,
string: self_ptr,
replace_with: replace_with
}
}

/// Converts this `String` into a `Box<str>`.
///
/// This will drop any excess capacity.
Expand Down Expand Up @@ -2145,3 +2210,61 @@ impl<'a> DoubleEndedIterator for Drain<'a> {

#[unstable(feature = "fused", issue = "35602")]
impl<'a> FusedIterator for Drain<'a> {}

/// A splicing iterator for `String`.
///
/// This struct is created by the [`splice()`] method on [`String`]. See its
/// documentation for more.
///
/// [`splice()`]: struct.String.html#method.splice
/// [`String`]: struct.String.html
#[derive(Debug)]
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
pub struct Splice<'a, 'b> {
/// Will be used as &'a mut String in the destructor
string: *mut String,
/// Start of part to remove
start: usize,
/// End of part to remove
end: usize,
/// Current remaining range to remove
iter: Chars<'a>,
replace_with: &'b str,
}

#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
unsafe impl<'a, 'b> Sync for Splice<'a, 'b> {}
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
unsafe impl<'a, 'b> Send for Splice<'a, 'b> {}

#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
impl<'a, 'b> Drop for Splice<'a, 'b> {
fn drop(&mut self) {
unsafe {
let vec = (*self.string).as_mut_vec();
vec.splice(self.start..self.end, self.replace_with.bytes());
}
}
}

#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
impl<'a, 'b> Iterator for Splice<'a, 'b> {
type Item = char;

#[inline]
fn next(&mut self) -> Option<char> {
self.iter.next()
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}

#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
impl<'a, 'b> DoubleEndedIterator for Splice<'a, 'b> {
#[inline]
fn next_back(&mut self) -> Option<char> {
self.iter.next_back()
}
}
1 change: 1 addition & 0 deletions src/libcollections/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#![feature(pattern)]
#![feature(placement_in_syntax)]
#![feature(rand)]
#![feature(splice)]
#![feature(step_by)]
#![feature(str_escape)]
#![feature(test)]
Expand Down
Loading