@@ -718,16 +718,20 @@ impl StrExt for str {
718718 // Fast path for replacing a single ASCII character with another inline.
719719 if let [ from_u8] = from. as_bytes ( ) {
720720 if let [ to_u8] = to. as_bytes ( ) {
721- return match self . len ( ) <= count {
722- true => replacen_1_ascii ( self , |b| if b == * from_u8 { * to_u8 } else { b } ) ,
723- _ => replacen_1_ascii ( self , |b| {
724- if b == * from_u8 && count != 0 {
725- count -= 1 ;
726- * to_u8
727- } else {
728- b
729- }
730- } ) ,
721+ return if self . len ( ) <= count {
722+ // SAFETY: `from_u8` & `to_u8` are ascii
723+ unsafe { replacen_1_ascii ( self , |b| if b == from_u8 { * to_u8 } else { * b } ) }
724+ } else {
725+ unsafe {
726+ replacen_1_ascii ( self , |b| {
727+ if b == from_u8 && count != 0 {
728+ count -= 1 ;
729+ * to_u8
730+ } else {
731+ * b
732+ }
733+ } )
734+ }
731735 } ;
732736 }
733737 }
@@ -748,20 +752,21 @@ impl StrExt for str {
748752 }
749753}
750754
755+ /// SAFETY: `map` fn must only replace ascii with ascii or return unchanged bytes.
751756#[ inline]
752- fn replacen_1_ascii ( src : & str , mut map : impl FnMut ( u8 ) -> u8 ) -> SmolStr {
757+ unsafe fn replacen_1_ascii ( src : & str , mut map : impl FnMut ( & u8 ) -> u8 ) -> SmolStr {
753758 if src. len ( ) <= INLINE_CAP {
754759 let mut buf = [ 0u8 ; INLINE_CAP ] ;
755760 for ( idx, b) in src. as_bytes ( ) . iter ( ) . enumerate ( ) {
756- buf[ idx] = map ( * b) ;
761+ buf[ idx] = map ( b) ;
757762 }
758763 SmolStr ( Repr :: Inline {
759764 // SAFETY: `len` is in bounds
760765 len : unsafe { InlineSize :: transmute_from_u8 ( src. len ( ) as u8 ) } ,
761766 buf,
762767 } )
763768 } else {
764- let out = src. as_bytes ( ) . iter ( ) . map ( |b| map ( * b ) ) . collect ( ) ;
769+ let out = src. as_bytes ( ) . iter ( ) . map ( map) . collect ( ) ;
765770 // SAFETY: We replaced ascii with ascii on valid utf8 strings.
766771 unsafe { String :: from_utf8_unchecked ( out) . into ( ) }
767772 }
0 commit comments