Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce <&[_]>::split_off and <&str>::split_off #49173

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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: 2 additions & 0 deletions src/liballoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(rand, test))]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(ascii_ctype)]
#![feature(box_into_raw_non_null)]
#![feature(box_patterns)]
Expand Down Expand Up @@ -112,6 +113,7 @@
#![feature(slice_get_slice)]
#![feature(slice_patterns)]
#![feature(slice_rsplit)]
#![feature(slice_split_off)]
#![feature(specialization)]
#![feature(staged_api)]
#![feature(str_internals)]
Expand Down
51 changes: 51 additions & 0 deletions src/liballoc/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1722,6 +1722,57 @@ impl<T> [T] {
// NB see hack module in this file
hack::into_vec(self)
}

/// Splits the slice into two at the given index.
///
/// Returns a newly slice. `self` contains elements `[0, at)`,
/// and the returned `Self` contains elements `[at, len)`.
///
/// # Panics
///
/// Panics if `at > len`.
///
/// # Examples
///
/// ```
/// #![feature(slice_split_off)]
///
/// let mut parisien: &[_] = &["baguette", "jambon", "beurre"];
/// let ingredients = parisien.split_off(1);
/// assert_eq!(parisien, &["baguette"]);
/// assert_eq!(ingredients, &["jambon", "beurre"]);
/// ```
#[unstable(feature = "slice_split_off", issue = "0")]
#[inline]
pub fn split_off<'a>(self: &mut &'a Self, at: usize) -> &'a [T] {
core_slice::SliceExt::split_off(self, at)
}

/// Splits the mutable slice into two at the given index.
///
/// Returns a newly mutable slice. `self` contains elements `[0, at)`,
/// and the returned `Self` contains elements `[at, len)`.
///
/// # Panics
///
/// Panics if `at > len`.
///
/// # Examples
///
/// ```
/// #![feature(slice_split_off)]
///
/// let mut parisien: &mut [_] = &mut ["baguette", "jambon", "beurre"];
/// let ingredients = parisien.split_off_mut(1);
/// ingredients[1] = "fromage";
/// assert_eq!(parisien, &["baguette"]);
/// assert_eq!(ingredients, &["jambon", "fromage"]);
/// ```
#[unstable(feature = "slice_split_off", issue = "0")]
#[inline]
pub fn split_off_mut<'a>(self: &mut &'a mut Self, at: usize) -> &'a mut [T] {
core_slice::SliceExt::split_off_mut(self, at)
}
}

#[lang = "slice_u8"]
Expand Down
61 changes: 61 additions & 0 deletions src/liballoc/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2249,6 +2249,67 @@ impl str {
let me = unsafe { self.as_bytes_mut() };
me.make_ascii_lowercase()
}

/// Splits the string slice into two at the given index.
///
/// Returns a new string slice. `self` contains bytes `[at, len)`, and
/// the returned string slice contains bytes `[at, len)`. `at` must be on
/// the boundary of a UTF-8 code point.
///
/// # Panics
///
/// Panics if `at` is not on a `UTF-8` code point boundary, or if it is
/// beyond the last code point of the string.
///
/// # Examples
///
/// ```
/// #![feature(slice_split_off)]
///
/// let mut best_baguette = "baguette de tradition";
/// let why_best = best_baguette.split_off(9);
/// assert_eq!(best_baguette, "baguette ");
/// assert_eq!(why_best, "de tradition");
/// ```
#[unstable(feature = "slice_split_off", issue = "0")]
#[inline]
pub fn split_off<'a>(self: &mut &'a Self, at: usize) -> &'a str {
core_str::StrExt::split_off(self, at)
}

/// Splits the mutable string slice into two at the given index.
///
/// Returns a new mutable string slice. `self` contains bytes `[0, at)`, and
/// the returned string slice contains bytes `[at, len)`. `at` must be on
/// the boundary of a UTF-8 code point.
///
/// To split immutable string slices instead, see the [`split_off`] method.
///
/// [`split_off`]: #method.split_off
///
/// # Panics
///
/// Panics if `at` 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:
///
/// ```
/// #![feature(slice_split_off)]
///
/// let mut magritte_says = &mut *String::from("Ceci n'est pas une pipe.");
/// let it_is_not = magritte_says.split_off_mut(19);
/// it_is_not.make_ascii_uppercase();
/// assert_eq!(magritte_says, "Ceci n'est pas une ");
/// assert_eq!(it_is_not, "PIPE.");
/// ```
#[unstable(feature = "slice_split_off", issue = "0")]
#[inline]
pub fn split_off_mut<'a>(self: &mut &'a mut Self, at: usize) -> &'a mut str {
core_str::StrExt::split_off_mut(self, at)
}
}

/// Converts a boxed slice of bytes to a boxed string slice without checking
Expand Down
1 change: 1 addition & 0 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
#![deny(warnings)]

#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(asm)]
#![feature(associated_type_defaults)]
#![feature(attr_literals)]
Expand Down
20 changes: 20 additions & 0 deletions src/libcore/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,12 @@ pub trait SliceExt {
fn sort_unstable_by_key<B, F>(&mut self, f: F)
where F: FnMut(&Self::Item) -> B,
B: Ord;

#[unstable(feature = "slice_split_off", issue = "0")]
fn split_off<'a>(self: &mut &'a Self, at: usize) -> &'a Self;

#[unstable(feature = "slice_split_off", issue = "0")]
fn split_off_mut<'a>(self: &mut &'a mut Self, at: usize) -> &'a mut Self;
}

// Use macros to be generic over const/mut
Expand Down Expand Up @@ -753,6 +759,20 @@ impl<T> SliceExt for [T] {
{
sort::quicksort(self, |a, b| f(a).lt(&f(b)));
}

#[inline]
fn split_off<'a>(self: &mut &'a Self, at: usize) -> &'a [T] {
let (rest, split) = self.split_at(at);
*self = rest;
split
}

#[inline]
fn split_off_mut<'a>(self: &mut &'a mut Self, at: usize) -> &'a mut [T] {
let (rest, split) = mem::replace(self, &mut []).split_at_mut(at);
*self = rest;
split
}
}

#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
20 changes: 20 additions & 0 deletions src/libcore/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2181,6 +2181,10 @@ pub trait StrExt {
fn is_empty(&self) -> bool;
#[stable(feature = "core", since = "1.6.0")]
fn parse<T: FromStr>(&self) -> Result<T, T::Err>;
#[unstable(feature = "slice_split_off", issue = "0")]
fn split_off<'a>(self: &mut &'a Self, at: usize) -> &'a Self;
#[unstable(feature = "slice_split_off", issue = "0")]
fn split_off_mut<'a>(self: &mut &'a mut Self, at: usize) -> &'a mut Self;
}

// truncate `&str` to length at most equal to `max`
Expand Down Expand Up @@ -2501,6 +2505,22 @@ impl StrExt for str {

#[inline]
fn parse<T: FromStr>(&self) -> Result<T, T::Err> { FromStr::from_str(self) }

#[inline]
fn split_off<'a>(self: &mut &'a Self, at: usize) -> &'a str {
let (rest, split) = self.split_at(at);
*self = rest;
split
}

#[inline]
fn split_off_mut<'a>(self: &mut &'a mut Self, at: usize) -> &'a mut str {
// An empty slice of bytes is trivially valid UTF-8.
let empty = unsafe { from_utf8_unchecked_mut(&mut []) };
let (rest, split) = mem::replace(self, empty).split_at_mut(at);
*self = rest;
split
}
}

#[stable(feature = "rust1", since = "1.0.0")]
Expand Down