@@ -187,11 +187,19 @@ pub fn is_upper_snake_case(s: &str) -> bool {
187187}
188188
189189pub fn replace ( buf : & mut String , from : char , to : & str ) {
190- if !buf. contains ( from) {
190+ let replace_count = buf. chars ( ) . filter ( |& ch| ch == from) . count ( ) ;
191+ if replace_count == 0 {
191192 return ;
192193 }
193- // FIXME: do this in place.
194- * buf = buf. replace ( from, to) ;
194+ let from_len = from. len_utf8 ( ) ;
195+ let additional = to. len ( ) . saturating_sub ( from_len) ;
196+ buf. reserve ( additional * replace_count) ;
197+
198+ let mut end = buf. len ( ) ;
199+ while let Some ( i) = buf[ ..end] . rfind ( from) {
200+ buf. replace_range ( i..i + from_len, to) ;
201+ end = i;
202+ }
195203}
196204
197205#[ must_use]
@@ -343,4 +351,34 @@ mod tests {
343351 "fn main() {\n return 92;\n }\n "
344352 ) ;
345353 }
354+
355+ #[ test]
356+ fn test_replace ( ) {
357+ #[ track_caller]
358+ fn test_replace ( src : & str , from : char , to : & str , expected : & str ) {
359+ let mut s = src. to_owned ( ) ;
360+ replace ( & mut s, from, to) ;
361+ assert_eq ! ( s, expected, "from: {from:?}, to: {to:?}" ) ;
362+ }
363+
364+ test_replace ( "" , 'a' , "b" , "" ) ;
365+ test_replace ( "" , 'a' , "😀" , "" ) ;
366+ test_replace ( "" , '😀' , "a" , "" ) ;
367+ test_replace ( "a" , 'a' , "b" , "b" ) ;
368+ test_replace ( "aa" , 'a' , "b" , "bb" ) ;
369+ test_replace ( "ada" , 'a' , "b" , "bdb" ) ;
370+ test_replace ( "a" , 'a' , "😀" , "😀" ) ;
371+ test_replace ( "😀" , '😀' , "a" , "a" ) ;
372+ test_replace ( "😀x" , '😀' , "a" , "ax" ) ;
373+ test_replace ( "y😀x" , '😀' , "a" , "yax" ) ;
374+ test_replace ( "a,b,c" , ',' , "." , "a.b.c" ) ;
375+ test_replace ( "a,b,c" , ',' , ".." , "a..b..c" ) ;
376+ test_replace ( "a.b.c" , '.' , ".." , "a..b..c" ) ;
377+ test_replace ( "a.b.c" , '.' , ".." , "a..b..c" ) ;
378+ test_replace ( "a😀b😀c" , '😀' , "." , "a.b.c" ) ;
379+ test_replace ( "a.b.c" , '.' , "😀" , "a😀b😀c" ) ;
380+ test_replace ( "a.b.c" , '.' , "😀😀" , "a😀😀b😀😀c" ) ;
381+ test_replace ( ".a.b.c." , '.' , "()" , "()a()b()c()" ) ;
382+ test_replace ( ".a.b.c." , '.' , "" , "abc" ) ;
383+ }
346384}
0 commit comments