From 6dc294b102014fd2f18a406f8580135d0a7bab26 Mon Sep 17 00:00:00 2001 From: William Venner Date: Sat, 11 Jun 2022 01:01:18 +0100 Subject: [PATCH 1/5] Add `String::replace_first` and `String::replace_last` --- library/alloc/src/lib.rs | 1 + library/alloc/src/string.rs | 57 +++++++++++++++++++++++++++++++++++ library/alloc/tests/lib.rs | 1 + library/alloc/tests/string.rs | 34 +++++++++++++++++++++ 4 files changed, 93 insertions(+) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index f0597f295b3f0..476510f55e109 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -139,6 +139,7 @@ #![feature(ptr_metadata)] #![feature(ptr_sub_ptr)] #![feature(receiver_trait)] +#![feature(string_replace_in_place)] #![feature(set_ptr_value)] #![feature(sized_type_properties)] #![feature(slice_from_ptr_range)] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 6daab5bc73a9c..f5693aecc0482 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1985,6 +1985,63 @@ impl String { unsafe { self.as_mut_vec() }.splice((start, end), replace_with.bytes()); } + /// Replaces the leftmost occurrence of a pattern with another string, in-place. + /// + /// This method should be preferred over [`String::replacen(..., 1)`](str::replacen) as it can use the `String`'s existing capacity to prevent a reallocation if sufficient space is available. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(string_replace_in_place)] + /// + /// let mut s = String::from("Test Results: ❌❌❌"); + /// + /// // Replace the leftmost ❌ with a ✅ + /// s.replace_first('❌', "✅"); + /// assert_eq!(s, "Test Results: ✅❌❌"); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "string_replace_in_place", issue = "none")] + pub fn replace_first Pattern<'a>>(&mut self, from: P, to: &str) { + let range = match self.match_indices(from).next() { + Some((start, match_str)) => start..start + match_str.len(), + None => return, + }; + + self.replace_range(range, to); + } + + /// Replaces the rightmost occurrence of a pattern with another string, in-place. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(string_replace_in_place)] + /// + /// let mut s = String::from("Test Results: ❌❌❌"); + /// + /// // Replace the rightmost ❌ with a ✅ + /// s.replace_last::('❌', "✅"); + /// assert_eq!(s, "Test Results: ❌❌✅"); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "string_replace_in_place", issue = "none")] + pub fn replace_last

(&mut self, from: P, to: &str) + where + P: for<'a> Pattern<'a, Searcher: str::pattern::ReverseSearcher<'a>>, + { + let range = match self.rmatch_indices(from).next() { + Some((start, match_str)) => start..start + match_str.len(), + None => return, + }; + + self.replace_range(range, to); + } + /// Converts this `String` into a [Box]<[str]>. /// /// Before doing the conversion, this method discards excess capacity like [`shrink_to_fit`]. diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index ffc9a233b665d..c279390aec56d 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -28,6 +28,7 @@ #![feature(iter_next_chunk)] #![feature(round_char_boundary)] #![feature(slice_partition_dedup)] +#![feature(string_replace_in_place)] #![feature(string_remove_matches)] #![feature(const_btree_len)] #![feature(const_trait_impl)] diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index dc03c4860e84b..3a32c4b96e4d4 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -682,6 +682,40 @@ fn test_replace_range_evil_end_bound() { assert_eq!(Ok(""), str::from_utf8(s.as_bytes())); } +#[test] +fn test_replace_first() { + let mut s = String::from("~ First ❌ Middle ❌ Last ❌ ~"); + s.replace_first("❌", "✅✅"); + assert_eq!(s, "~ First ✅✅ Middle ❌ Last ❌ ~"); + s.replace_first("🦀", "😳"); + assert_eq!(s, "~ First ✅✅ Middle ❌ Last ❌ ~"); + + let mut s = String::from("❌"); + s.replace_first('❌', "✅✅"); + assert_eq!(s, "✅✅"); + + let mut s = String::from(""); + s.replace_first('🌌', "❌"); + assert_eq!(s, ""); +} + +#[test] +fn test_replace_last() { + let mut s = String::from("~ First ❌ Middle ❌ Last ❌ ~"); + s.replace_last::<&str>("❌", "✅✅"); + assert_eq!(s, "~ First ❌ Middle ❌ Last ✅✅ ~"); + s.replace_last::<&str>("🦀", "😳"); + assert_eq!(s, "~ First ❌ Middle ❌ Last ✅✅ ~"); + + let mut s = String::from("❌"); + s.replace_last::('❌', "✅✅"); + assert_eq!(s, "✅✅"); + + let mut s = String::from(""); + s.replace_last::('🌌', "❌"); + assert_eq!(s, ""); +} + #[test] fn test_extend_ref() { let mut a = "foo".to_string(); From 168c5a075003f8bac5f2b5653e91a589dffa02b7 Mon Sep 17 00:00:00 2001 From: William Venner Date: Sat, 11 Jun 2022 03:30:32 +0100 Subject: [PATCH 2/5] Change doc link --- library/alloc/src/string.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index f5693aecc0482..3e916f29e25ea 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1987,7 +1987,9 @@ impl String { /// Replaces the leftmost occurrence of a pattern with another string, in-place. /// - /// This method should be preferred over [`String::replacen(..., 1)`](str::replacen) as it can use the `String`'s existing capacity to prevent a reallocation if sufficient space is available. + /// This method should be preferred over [`str::replacen(..., 1)`] as it can use the `String`'s existing capacity to prevent a reallocation if sufficient space is available. + /// + /// [`str::replacen(..., 1)`]: str::replacen /// /// # Examples /// From 8dd1b5e7f098f11bc37dd5a76c1896b1a481ca87 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Sat, 27 Apr 2024 02:13:33 -0500 Subject: [PATCH 3/5] Hard-code doclink to avoid issue 98941 --- library/alloc/src/string.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 3e916f29e25ea..b45798d606744 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1987,9 +1987,7 @@ impl String { /// Replaces the leftmost occurrence of a pattern with another string, in-place. /// - /// This method should be preferred over [`str::replacen(..., 1)`] as it can use the `String`'s existing capacity to prevent a reallocation if sufficient space is available. - /// - /// [`str::replacen(..., 1)`]: str::replacen + /// This method should be preferred over [`str::replacen(..., 1)`](../../std/primitive.str.html#method.replacen) as it can use the `String`'s existing capacity to prevent a reallocation if sufficient space is available. /// /// # Examples /// From 7a626d7bbf17eccde6575298fc99829a3dd02f38 Mon Sep 17 00:00:00 2001 From: William Venner Date: Thu, 19 Sep 2024 17:15:27 +0100 Subject: [PATCH 4/5] Sort feature gates --- library/alloc/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 476510f55e109..e8323c6855f00 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -139,7 +139,6 @@ #![feature(ptr_metadata)] #![feature(ptr_sub_ptr)] #![feature(receiver_trait)] -#![feature(string_replace_in_place)] #![feature(set_ptr_value)] #![feature(sized_type_properties)] #![feature(slice_from_ptr_range)] @@ -149,6 +148,7 @@ #![feature(std_internals)] #![feature(str_internals)] #![feature(strict_provenance)] +#![feature(string_replace_in_place)] #![feature(trusted_fused)] #![feature(trusted_len)] #![feature(trusted_random_access)] From 841b24ea8a91a54dbd411c496d9f4d363e90a5da Mon Sep 17 00:00:00 2001 From: William Venner Date: Thu, 19 Sep 2024 17:59:22 +0100 Subject: [PATCH 5/5] Update lifetimes --- library/alloc/src/string.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index b45798d606744..eb4bab4e1b988 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2004,7 +2004,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "string_replace_in_place", issue = "none")] - pub fn replace_first Pattern<'a>>(&mut self, from: P, to: &str) { + pub fn replace_first(&mut self, from: P, to: &str) { let range = match self.match_indices(from).next() { Some((start, match_str)) => start..start + match_str.len(), None => return, @@ -2032,7 +2032,7 @@ impl String { #[unstable(feature = "string_replace_in_place", issue = "none")] pub fn replace_last

(&mut self, from: P, to: &str) where - P: for<'a> Pattern<'a, Searcher: str::pattern::ReverseSearcher<'a>>, + P: for<'a> Pattern: str::pattern::ReverseSearcher<'a>>, { let range = match self.rmatch_indices(from).next() { Some((start, match_str)) => start..start + match_str.len(),