@@ -641,8 +641,9 @@ impl str {
641641 ///
642642 /// # Panics
643643 ///
644- /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is
645- /// past the end of the last code point of the string slice.
644+ /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is past
645+ /// the end of the last code point of the string slice. For a non-panicking
646+ /// alternative see [`split_at_checked`](str::split_at_checked).
646647 ///
647648 /// # Examples
648649 ///
@@ -658,12 +659,9 @@ impl str {
658659 #[ must_use]
659660 #[ stable( feature = "str_split_at" , since = "1.4.0" ) ]
660661 pub fn split_at ( & self , mid : usize ) -> ( & str , & str ) {
661- // is_char_boundary checks that the index is in [0, .len()]
662- if self . is_char_boundary ( mid) {
663- // SAFETY: just checked that `mid` is on a char boundary.
664- unsafe { ( self . get_unchecked ( 0 ..mid) , self . get_unchecked ( mid..self . len ( ) ) ) }
665- } else {
666- slice_error_fail ( self , 0 , mid)
662+ match self . split_at_checked ( mid) {
663+ None => slice_error_fail ( self , 0 , mid) ,
664+ Some ( pair) => pair,
667665 }
668666 }
669667
@@ -681,8 +679,9 @@ impl str {
681679 ///
682680 /// # Panics
683681 ///
684- /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is
685- /// past the end of the last code point of the string slice.
682+ /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is past
683+ /// the end of the last code point of the string slice. For a non-panicking
684+ /// alternative see [`split_at_mut_checked`](str::split_at_mut_checked).
686685 ///
687686 /// # Examples
688687 ///
@@ -702,20 +701,114 @@ impl str {
702701 pub fn split_at_mut ( & mut self , mid : usize ) -> ( & mut str , & mut str ) {
703702 // is_char_boundary checks that the index is in [0, .len()]
704703 if self . is_char_boundary ( mid) {
705- let len = self . len ( ) ;
706- let ptr = self . as_mut_ptr ( ) ;
707704 // SAFETY: just checked that `mid` is on a char boundary.
708- unsafe {
709- (
710- from_utf8_unchecked_mut ( slice:: from_raw_parts_mut ( ptr, mid) ) ,
711- from_utf8_unchecked_mut ( slice:: from_raw_parts_mut ( ptr. add ( mid) , len - mid) ) ,
712- )
713- }
705+ unsafe { self . split_at_mut_unchecked ( mid) }
714706 } else {
715707 slice_error_fail ( self , 0 , mid)
716708 }
717709 }
718710
711+ /// Divide one string slice into two at an index.
712+ ///
713+ /// The argument, `mid`, should be a valid byte offset from the start of the
714+ /// string. It must also be on the boundary of a UTF-8 code point. The
715+ /// method returns `None` if that’s not the case.
716+ ///
717+ /// The two slices returned go from the start of the string slice to `mid`,
718+ /// and from `mid` to the end of the string slice.
719+ ///
720+ /// To get mutable string slices instead, see the [`split_at_mut_checked`]
721+ /// method.
722+ ///
723+ /// [`split_at_mut_checked`]: str::split_at_mut_checked
724+ ///
725+ /// # Examples
726+ ///
727+ /// ```
728+ /// #![feature(split_at_checked)]
729+ ///
730+ /// let s = "Per Martin-Löf";
731+ ///
732+ /// let (first, last) = s.split_at_checked(3).unwrap();
733+ /// assert_eq!("Per", first);
734+ /// assert_eq!(" Martin-Löf", last);
735+ ///
736+ /// assert_eq!(None, s.split_at_checked(13)); // Inside “ö”
737+ /// assert_eq!(None, s.split_at_checked(16)); // Beyond the string length
738+ /// ```
739+ #[ inline]
740+ #[ must_use]
741+ #[ unstable( feature = "split_at_checked" , reason = "new API" , issue = "119128" ) ]
742+ pub fn split_at_checked ( & self , mid : usize ) -> Option < ( & str , & str ) > {
743+ // is_char_boundary checks that the index is in [0, .len()]
744+ if self . is_char_boundary ( mid) {
745+ // SAFETY: just checked that `mid` is on a char boundary.
746+ Some ( unsafe { ( self . get_unchecked ( 0 ..mid) , self . get_unchecked ( mid..self . len ( ) ) ) } )
747+ } else {
748+ None
749+ }
750+ }
751+
752+ /// Divide one mutable string slice into two at an index.
753+ ///
754+ /// The argument, `mid`, should be a valid byte offset from the start of the
755+ /// string. It must also be on the boundary of a UTF-8 code point. The
756+ /// method returns `None` if that’s not the case.
757+ ///
758+ /// The two slices returned go from the start of the string slice to `mid`,
759+ /// and from `mid` to the end of the string slice.
760+ ///
761+ /// To get immutable string slices instead, see the [`split_at_checked`] method.
762+ ///
763+ /// [`split_at_checked`]: str::split_at_checked
764+ ///
765+ /// # Examples
766+ ///
767+ /// ```
768+ /// #![feature(split_at_checked)]
769+ ///
770+ /// let mut s = "Per Martin-Löf".to_string();
771+ /// if let Some((first, last)) = s.split_at_mut_checked(3) {
772+ /// first.make_ascii_uppercase();
773+ /// assert_eq!("PER", first);
774+ /// assert_eq!(" Martin-Löf", last);
775+ /// }
776+ /// assert_eq!("PER Martin-Löf", s);
777+ ///
778+ /// assert_eq!(None, s.split_at_mut_checked(13)); // Inside “ö”
779+ /// assert_eq!(None, s.split_at_mut_checked(16)); // Beyond the string length
780+ /// ```
781+ #[ inline]
782+ #[ must_use]
783+ #[ unstable( feature = "split_at_checked" , reason = "new API" , issue = "119128" ) ]
784+ pub fn split_at_mut_checked ( & mut self , mid : usize ) -> Option < ( & mut str , & mut str ) > {
785+ // is_char_boundary checks that the index is in [0, .len()]
786+ if self . is_char_boundary ( mid) {
787+ // SAFETY: just checked that `mid` is on a char boundary.
788+ Some ( unsafe { self . split_at_mut_unchecked ( mid) } )
789+ } else {
790+ None
791+ }
792+ }
793+
794+ /// Divide one string slice into two at an index.
795+ ///
796+ /// # Safety
797+ ///
798+ /// The caller must ensure that `mid` is a valid byte offset from the start
799+ /// of the string and falls on the boundary of a UTF-8 code point.
800+ unsafe fn split_at_mut_unchecked ( & mut self , mid : usize ) -> ( & mut str , & mut str ) {
801+ let len = self . len ( ) ;
802+ let ptr = self . as_mut_ptr ( ) ;
803+ // SAFETY: caller guarantees `mid` is on a char boundary.
804+ unsafe {
805+ (
806+ from_utf8_unchecked_mut ( slice:: from_raw_parts_mut ( ptr, mid) ) ,
807+ from_utf8_unchecked_mut ( slice:: from_raw_parts_mut ( ptr. add ( mid) , len - mid) ) ,
808+ )
809+ }
810+ }
811+
719812 /// Returns an iterator over the [`char`]s of a string slice.
720813 ///
721814 /// As a string slice consists of valid UTF-8, we can iterate through a
0 commit comments