Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions library/alloc/src/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use core::borrow::{Borrow, BorrowMut};
use core::iter::FusedIterator;
use core::mem::MaybeUninit;
use core::pattern::{Pattern, Utf8Pattern};
#[stable(feature = "encode_utf16", since = "1.8.0")]
pub use core::str::EncodeUtf16;
#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
Expand All @@ -20,7 +21,6 @@ pub use core::str::SplitInclusive;
pub use core::str::SplitWhitespace;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::str::pattern;
use core::str::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher, Utf8Pattern};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::str::{Bytes, CharIndices, Chars, from_utf8, from_utf8_mut};
#[stable(feature = "str_escape", since = "1.34.0")]
Expand Down Expand Up @@ -305,7 +305,10 @@ impl str {
without modifying the original"]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn replace<P: Pattern>(&self, from: P, to: &str) -> String {
pub fn replace<'a, P>(&'a self, from: P, to: &str) -> String
where
P: Pattern<&'a str>,
{
// Fast path for replacing a single ASCII character with another.
if let Some(from_byte) = match from.as_utf8_pattern() {
Some(Utf8Pattern::StringPattern(s)) => match s.as_bytes() {
Expand Down Expand Up @@ -363,7 +366,10 @@ impl str {
#[must_use = "this returns the replaced string as a new allocation, \
without modifying the original"]
#[stable(feature = "str_replacen", since = "1.16.0")]
pub fn replacen<P: Pattern>(&self, pat: P, to: &str, count: usize) -> String {
pub fn replacen<'a, P>(&'a self, pat: P, to: &str, count: usize) -> String
where
P: Pattern<&'a str>,
{
// Hope to reduce the times of re-allocation
let mut result = String::with_capacity(32);
let mut last_end = 0;
Expand Down
32 changes: 19 additions & 13 deletions library/alloc/src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use core::ops::Add;
#[cfg(not(no_global_oom_handling))]
use core::ops::AddAssign;
use core::ops::{self, Range, RangeBounds};
use core::str::pattern::{Pattern, Utf8Pattern};
use core::pattern::{Pattern, Utf8Pattern};
use core::{fmt, hash, ptr, slice};

#[cfg(not(no_global_oom_handling))]
Expand Down Expand Up @@ -1580,8 +1580,11 @@ impl String {
/// ```
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "string_remove_matches", issue = "72826")]
pub fn remove_matches<P: Pattern>(&mut self, pat: P) {
use core::str::pattern::Searcher;
pub fn remove_matches<'a, P>(&'a mut self, pat: P)
where
P: for<'x> Pattern<&'x str>,
{
use core::pattern::Searcher;

let rejections = {
let mut searcher = pat.into_searcher(self);
Expand Down Expand Up @@ -2130,7 +2133,10 @@ impl String {
/// [replacen]: ../../std/primitive.str.html#method.replacen
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "string_replace_in_place", issue = "147949")]
pub fn replace_first<P: Pattern>(&mut self, from: P, to: &str) {
pub fn replace_first<'a, P>(&'a mut self, from: P, to: &str)
where
P: for<'x> Pattern<&'x str>,
{
let range = match self.match_indices(from).next() {
Some((start, match_str)) => start..start + match_str.len(),
None => return,
Expand All @@ -2156,9 +2162,9 @@ impl String {
/// ```
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "string_replace_in_place", issue = "147949")]
pub fn replace_last<P: Pattern>(&mut self, from: P, to: &str)
pub fn replace_last<'a, P>(&'a mut self, from: P, to: &str)
where
for<'a> P::Searcher<'a>: core::str::pattern::ReverseSearcher<'a>,
P: for<'x> Pattern<&'x str, Searcher: core::pattern::ReverseSearcher<&'x str>>,
{
let range = match self.rmatch_indices(from).next() {
Some((start, match_str)) => start..start + match_str.len(),
Expand Down Expand Up @@ -2651,10 +2657,10 @@ impl<'a> Extend<&'a core::ascii::Char> for String {
reason = "API not fully fleshed out and ready to be stabilized",
issue = "27721"
)]
impl<'b> Pattern for &'b String {
type Searcher<'a> = <&'b str as Pattern>::Searcher<'a>;
impl<'a, 'b> Pattern<&'a str> for &'b String {
type Searcher = <&'b str as Pattern<&'a str>>::Searcher;

fn into_searcher(self, haystack: &str) -> <&'b str as Pattern>::Searcher<'_> {
fn into_searcher(self, haystack: &'a str) -> <&'b str as Pattern<&'a str>>::Searcher {
self[..].into_searcher(haystack)
}

Expand All @@ -2674,17 +2680,17 @@ impl<'b> Pattern for &'b String {
}

#[inline]
fn is_suffix_of<'a>(self, haystack: &'a str) -> bool
fn is_suffix_of(self, haystack: &'a str) -> bool
where
Self::Searcher<'a>: core::str::pattern::ReverseSearcher<'a>,
Self::Searcher: core::pattern::ReverseSearcher<&'a str>,
{
self[..].is_suffix_of(haystack)
}

#[inline]
fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str>
fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str>
where
Self::Searcher<'a>: core::str::pattern::ReverseSearcher<'a>,
Self::Searcher: core::pattern::ReverseSearcher<&'a str>,
{
self[..].strip_suffix_of(haystack)
}
Expand Down
62 changes: 37 additions & 25 deletions library/alloctests/tests/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,18 @@ fn test_trim_matches() {
assert_eq!("123foo1bar123".trim_matches(|c: char| c.is_numeric()), "foo1bar");
}

#[test]
fn test_trim_matches_with_str_pattern() {
assert_eq!("abc".trim_start_matches("ab"), "c");
assert_eq!("xyzabcxyz".trim_start_matches("xyz"), "abcxyz");
assert_eq!("abcabc".trim_start_matches("abc"), "");
assert_eq!("ababab".trim_start_matches("ab"), "");

assert_eq!("abcab".trim_end_matches("ab"), "abc");
assert_eq!("xyzabcxyz".trim_end_matches("xyz"), "xyzabc");
assert_eq!("abcabc".trim_end_matches("abc"), "");
}

#[test]
fn test_trim_start() {
assert_eq!("".trim_start(), "");
Expand Down Expand Up @@ -2009,14 +2021,14 @@ fn test_repeat() {
}

mod pattern {
use std::str::pattern::SearchStep::{self, Done, Match, Reject};
use std::str::pattern::{Pattern, ReverseSearcher, Searcher};
use std::pattern::SearchStep::{self, Done, Match, Reject};
use std::pattern::{Pattern, ReverseSearcher, Searcher};

macro_rules! make_test {
($name:ident, $p:expr, $h:expr, [$($e:expr,)*]) => {
#[allow(unused_imports)]
mod $name {
use std::str::pattern::SearchStep::{Match, Reject};
use std::pattern::SearchStep::{Match, Reject};
use super::{cmp_search_to_vec};
#[test]
fn fwd() {
Expand All @@ -2032,7 +2044,7 @@ mod pattern {

fn cmp_search_to_vec<P>(rev: bool, pat: P, haystack: &str, right: Vec<SearchStep>)
where
P: for<'a> Pattern<Searcher<'a>: ReverseSearcher<'a>>,
P: for<'a> Pattern<&'a str, Searcher: ReverseSearcher<&'a str>>,
{
let mut searcher = pat.into_searcher(haystack);
let mut v = vec![];
Expand Down Expand Up @@ -2107,12 +2119,7 @@ mod pattern {
Match(7, 7),
]
);
make_test!(
str_searcher_multibyte_haystack,
" ",
"├──",
[Reject(0, 3), Reject(3, 6), Reject(6, 9),]
);
make_test!(str_searcher_multibyte_haystack, " ", "├──", [Reject(0, 9),]);
make_test!(
str_searcher_empty_needle_multibyte_haystack,
"",
Expand Down Expand Up @@ -2143,18 +2150,8 @@ mod pattern {
Reject(6, 7),
]
);
make_test!(
char_searcher_multibyte_haystack,
' ',
"├──",
[Reject(0, 3), Reject(3, 6), Reject(6, 9),]
);
make_test!(
char_searcher_short_haystack,
'\u{1F4A9}',
"* \t",
[Reject(0, 1), Reject(1, 2), Reject(2, 3),]
);
make_test!(char_searcher_multibyte_haystack, ' ', "├──", [Reject(0, 9),]);
make_test!(char_searcher_short_haystack, '\u{1F4A9}', "* \t", [Reject(0, 3),]);

// See #85462
#[test]
Expand Down Expand Up @@ -2196,6 +2193,21 @@ mod pattern {
assert_eq!(searcher.next_back(), SearchStep::Done);
}
}

#[test]
fn str_searcher_empty_needle_interleaved() {
let mut searcher = "".into_searcher("abc");

assert_eq!(searcher.next(), SearchStep::Match(0, 0));
assert_eq!(searcher.next_back(), SearchStep::Match(3, 3));
assert_eq!(searcher.next(), SearchStep::Reject(0, 1));
assert_eq!(searcher.next_back(), SearchStep::Reject(2, 3));
assert_eq!(searcher.next(), SearchStep::Match(1, 1));
assert_eq!(searcher.next_back(), SearchStep::Match(2, 2));
assert_eq!(searcher.next(), SearchStep::Reject(1, 2));
assert_eq!(searcher.next_back(), SearchStep::Done);
assert_eq!(searcher.next(), SearchStep::Done);
}
}

macro_rules! generate_iterator_test {
Expand Down Expand Up @@ -2290,11 +2302,11 @@ generate_iterator_test! {

#[test]
fn different_str_pattern_forwarding_lifetimes() {
use std::str::pattern::Pattern;
use std::pattern::Pattern;

fn foo<P>(p: P)
fn foo<'a, P>(p: P)
where
for<'b> &'b P: Pattern,
for<'b> &'b P: Pattern<&'a str>,
{
for _ in 0..3 {
"asdf".find(&p);
Expand Down
2 changes: 2 additions & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,10 @@ pub mod unsafe_binder;

pub mod fmt;
pub mod hash;
pub mod pattern;
pub mod slice;
pub mod str;
pub mod str_bytes;
pub mod time;

pub mod wtf8;
Expand Down
Loading
Loading