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