diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 348eb6fb5ffa4..ddde9d06d8176 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1260,6 +1260,39 @@ impl String { self.len() == 0 } + /// Divide one string 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 strings returned go from the start of the string to `mid`, and from `mid` to the end + /// of the string. + /// + /// # 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. + /// + /// # Examples + /// + /// ``` + /// # #![feature(string_split_off)] + /// # fn main() { + /// let mut hello = String::from("Hello, World!"); + /// let world = hello.split_off(7); + /// assert_eq!(hello, "Hello, "); + /// assert_eq!(world, "World!"); + /// # } + /// ``` + #[inline] + #[unstable(feature = "string_split_off", issue = "38080")] + pub fn split_off(&mut self, mid: usize) -> String { + assert!(self.is_char_boundary(mid)); + assert!(mid <= self.len()); + let other = self.vec.split_off(mid); + unsafe { String::from_utf8_unchecked(other) } + } + /// Truncates this `String`, removing all contents. /// /// While this means the `String` will have a length of zero, it does not diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 1e08074b14db8..58ce78eab9a17 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -25,6 +25,7 @@ #![feature(step_by)] #![feature(str_escape)] #![feature(str_replacen)] +#![feature(string_split_off)] #![feature(test)] #![feature(unboxed_closures)] #![feature(unicode)] diff --git a/src/libcollectionstest/string.rs b/src/libcollectionstest/string.rs index 98de33bdaa8e1..cb4fcb58452da 100644 --- a/src/libcollectionstest/string.rs +++ b/src/libcollectionstest/string.rs @@ -231,6 +231,45 @@ fn test_pop() { assert_eq!(data, "ประเทศไทย中"); } +#[test] +fn test_split_off_empty() { + let orig = "Hello, world!"; + let mut split = String::from(orig); + let empty: String = split.split_off(orig.len()); + assert!(empty.is_empty()); +} + +#[test] +#[should_panic] +fn test_split_off_past_end() { + let orig = "Hello, world!"; + let mut split = String::from(orig); + split.split_off(orig.len() + 1); +} + +#[test] +#[should_panic] +fn test_split_off_mid_char() { + let mut orig = String::from("山"); + orig.split_off(1); +} + +#[test] +fn test_split_off_ascii() { + let mut ab = String::from("ABCD"); + let cd = ab.split_off(2); + assert_eq!(ab, "AB"); + assert_eq!(cd, "CD"); +} + +#[test] +fn test_split_off_unicode() { + let mut nihon = String::from("日本語"); + let go = nihon.split_off("日本".len()); + assert_eq!(nihon, "日本"); + assert_eq!(go, "語"); +} + #[test] fn test_str_truncate() { let mut s = String::from("12345");