diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index a9725214c19..062f7992724 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -779,6 +779,33 @@ impl str { core_str::StrExt::slice_shift_char(&self[..]) } + /// Divide one string slice into two at an index. + /// + /// The index `mid` is a byte offset from the start of the string + /// that must be on a character boundary. + /// + /// Return slices `&self[..mid]` and `&self[mid..]`. + /// + /// # Panics + /// + /// Panics if `mid` is beyond the last character of the string, + /// or if it is not on a character boundary. + /// + /// # Examples + /// ``` + /// # #![feature(collections)] + /// let s = "Löwe 老虎 Léopard"; + /// let first_space = s.find(' ').unwrap_or(s.len()); + /// let (a, b) = s.split_at(first_space); + /// + /// assert_eq!(a, "Löwe"); + /// assert_eq!(b, " 老虎 Léopard"); + /// ``` + #[inline] + pub fn split_at(&self, mid: usize) -> (&str, &str) { + core_str::StrExt::split_at(self, mid) + } + /// An iterator over the codepoints of `self`. /// /// # Examples diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 1019e98153e..def79682801 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -688,6 +688,26 @@ fn test_char_at_reverse() { } } +#[test] +fn test_split_at() { + let s = "ศไทย中华Việt Nam"; + for (index, _) in s.char_indices() { + let (a, b) = s.split_at(index); + assert_eq!(&s[..a.len()], a); + assert_eq!(&s[a.len()..], b); + } + let (a, b) = s.split_at(s.len()); + assert_eq!(a, s); + assert_eq!(b, ""); +} + +#[test] +#[should_panic] +fn test_split_at_boundscheck() { + let s = "ศไทย中华Việt Nam"; + let (a, b) = s.split_at(1); +} + #[test] fn test_escape_unicode() { assert_eq!("abc".escape_unicode(), diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 11ca6e332b5..4db64a3097e 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1517,6 +1517,7 @@ pub trait StrExt { fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option where P::Searcher: ReverseSearcher<'a>; fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option; + fn split_at(&self, mid: usize) -> (&str, &str); fn slice_shift_char<'a>(&'a self) -> Option<(char, &'a str)>; fn subslice_offset(&self, inner: &str) -> usize; fn as_ptr(&self) -> *const u8; @@ -1809,6 +1810,18 @@ impl StrExt for str { self.find(pat) } + fn split_at(&self, mid: usize) -> (&str, &str) { + // is_char_boundary checks that the index is in [0, .len()] + if self.is_char_boundary(mid) { + unsafe { + (self.slice_unchecked(0, mid), + self.slice_unchecked(mid, self.len())) + } + } else { + slice_error_fail(self, 0, mid) + } + } + #[inline] fn slice_shift_char(&self) -> Option<(char, &str)> { if self.is_empty() {