Skip to content

Commit 897896d

Browse files
committed
Auto merge of #59591 - kennytm:needle-api, r=<try>
[WIP] Implement Needle API (RFC 2500) cc #56345 ---- Insta-stable changes: * `impl Index<Range***> for OsStr` cannot be gated and is insta-stable. I'll add more comments after the crater run.
2 parents b025802 + d8bdeb6 commit 897896d

30 files changed

+7085
-3467
lines changed

src/liballoc/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
#![feature(needs_allocator)]
9494
#![feature(nll)]
9595
#![feature(optin_builtin_traits)]
96-
#![feature(pattern)]
96+
#![feature(needle)]
9797
#![feature(ptr_internals)]
9898
#![feature(ptr_offset_from)]
9999
#![feature(rustc_attrs)]

src/liballoc/slice.rs

+35
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ use core::cmp::Ordering::{self, Less};
9292
use core::mem::{self, size_of};
9393
use core::ptr;
9494
use core::{u8, u16, u32};
95+
use core::needle::{ext, Needle, Searcher, Consumer};
9596

9697
use crate::borrow::ToOwned;
9798
use crate::boxed::Box;
@@ -485,6 +486,40 @@ impl<T> [T] {
485486
}
486487
buf
487488
}
489+
490+
/// Replaces all matches of a predicate with another slice.
491+
#[unstable(feature = "slice_needle_methods", issue = "56345")]
492+
#[inline]
493+
#[must_use = "this returns the replaced slice as a new allocation, \
494+
without modifying the original"]
495+
pub fn replace<'s: 'a, 'a, F>(&'s self, from: F, to: &'a [T]) -> Vec<T>
496+
where
497+
T: Clone,
498+
F: Needle<&'a [T]>,
499+
F::Searcher: Searcher<[T]>, // FIXME: RFC 2089
500+
F::Consumer: Consumer<[T]>, // FIXME: RFC 2089
501+
{
502+
let mut result = Vec::with_capacity(self.len());
503+
ext::replace_with(self, from, |_| to, |s| result.extend_from_slice(s));
504+
result
505+
}
506+
507+
/// Replaces first N matches of a predicate with another slice.
508+
#[unstable(feature = "slice_needle_methods", issue = "56345")]
509+
#[inline]
510+
#[must_use = "this returns the replaced slice as a new allocation, \
511+
without modifying the original"]
512+
pub fn replacen<'s: 'a, 'a, F>(&'s self, from: F, to: &'a [T], count: usize) -> Vec<T>
513+
where
514+
T: Clone,
515+
F: Needle<&'a [T]>,
516+
F::Searcher: Searcher<[T]>, // FIXME: RFC 2089
517+
F::Consumer: Consumer<[T]>, // FIXME: RFC 2089
518+
{
519+
let mut result = Vec::with_capacity(self.len());
520+
ext::replacen_with(self, from, |_| to, count, |s| result.extend_from_slice(s));
521+
result
522+
}
488523
}
489524

490525
#[lang = "slice_u8_alloc"]

src/liballoc/str.rs

+19-23
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@
2828
// It's cleaner to just turn off the unused_imports warning than to fix them.
2929
#![allow(unused_imports)]
3030

31-
use core::borrow::Borrow;
32-
use core::str::pattern::{Pattern, Searcher, ReverseSearcher, DoubleEndedSearcher};
31+
use core::fmt;
32+
use core::needle::{ext, Needle, Searcher, Consumer};
3333
use core::mem;
3434
use core::ptr;
3535
use core::iter::FusedIterator;
3636
use core::unicode::conversions;
3737

38-
use crate::borrow::ToOwned;
38+
use crate::borrow::{Borrow, ToOwned};
3939
use crate::boxed::Box;
4040
use crate::slice::{SliceConcatExt, SliceIndex};
4141
use crate::string::String;
@@ -62,8 +62,6 @@ pub use core::str::{from_utf8, from_utf8_mut, Chars, CharIndices, Bytes};
6262
pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError};
6363
#[stable(feature = "rust1", since = "1.0.0")]
6464
pub use core::str::SplitWhitespace;
65-
#[stable(feature = "rust1", since = "1.0.0")]
66-
pub use core::str::pattern;
6765
#[stable(feature = "encode_utf16", since = "1.8.0")]
6866
pub use core::str::EncodeUtf16;
6967
#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
@@ -253,15 +251,14 @@ impl str {
253251
without modifying the original"]
254252
#[stable(feature = "rust1", since = "1.0.0")]
255253
#[inline]
256-
pub fn replace<'a, P: Pattern<'a>>(&'a self, from: P, to: &str) -> String {
257-
let mut result = String::new();
258-
let mut last_end = 0;
259-
for (start, part) in self.match_indices(from) {
260-
result.push_str(unsafe { self.get_unchecked(last_end..start) });
261-
result.push_str(to);
262-
last_end = start + part.len();
263-
}
264-
result.push_str(unsafe { self.get_unchecked(last_end..self.len()) });
254+
pub fn replace<'s: 'a, 'a, P>(&'s self, from: P, to: &'a str) -> String
255+
where
256+
P: Needle<&'a str>,
257+
P::Searcher: Searcher<str>, // FIXME: RFC 2089
258+
P::Consumer: Consumer<str>, // FIXME: RFC 2089
259+
{
260+
let mut result = String::with_capacity(self.len());
261+
ext::replace_with(self, from, |_| to, |s| result.push_str(s));
265262
result
266263
}
267264

@@ -293,16 +290,15 @@ impl str {
293290
#[must_use = "this returns the replaced string as a new allocation, \
294291
without modifying the original"]
295292
#[stable(feature = "str_replacen", since = "1.16.0")]
296-
pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String {
293+
pub fn replacen<'s: 'a, 'a, P>(&'s self, pat: P, to: &'a str, count: usize) -> String
294+
where
295+
P: Needle<&'a str>,
296+
P::Searcher: Searcher<str>, // FIXME: RFC 2089
297+
P::Consumer: Consumer<str>, // FIXME: RFC 2089
298+
{
297299
// Hope to reduce the times of re-allocation
298-
let mut result = String::with_capacity(32);
299-
let mut last_end = 0;
300-
for (start, part) in self.match_indices(pat).take(count) {
301-
result.push_str(unsafe { self.get_unchecked(last_end..start) });
302-
result.push_str(to);
303-
last_end = start + part.len();
304-
}
305-
result.push_str(unsafe { self.get_unchecked(last_end..self.len()) });
300+
let mut result = String::with_capacity(self.len());
301+
ext::replacen_with(self, pat, |_| to, count, |s| result.push_str(s));
306302
result
307303
}
308304

src/liballoc/string.rs

+10-14
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ use core::iter::{FromIterator, FusedIterator};
5353
use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds};
5454
use core::ops::Bound::{Excluded, Included, Unbounded};
5555
use core::ptr;
56-
use core::str::{pattern::Pattern, lossy};
56+
use core::needle::Needle;
57+
use core::str::lossy;
5758

5859
use crate::borrow::{Cow, ToOwned};
5960
use crate::collections::CollectionAllocErr;
@@ -1792,24 +1793,19 @@ impl<'a> Extend<Cow<'a, str>> for String {
17921793
}
17931794

17941795
/// A convenience impl that delegates to the impl for `&str`
1795-
#[unstable(feature = "pattern",
1796-
reason = "API not fully fleshed out and ready to be stabilized",
1797-
issue = "27721")]
1798-
impl<'a, 'b> Pattern<'a> for &'b String {
1799-
type Searcher = <&'b str as Pattern<'a>>::Searcher;
1800-
1801-
fn into_searcher(self, haystack: &'a str) -> <&'b str as Pattern<'a>>::Searcher {
1802-
self[..].into_searcher(haystack)
1803-
}
1796+
#[unstable(feature = "needle", issue = "56345")]
1797+
impl<'a, 'b> Needle<&'a str> for &'b String {
1798+
type Searcher = <&'b str as Needle<&'a str>>::Searcher;
1799+
type Consumer = <&'b str as Needle<&'a str>>::Consumer;
18041800

18051801
#[inline]
1806-
fn is_contained_in(self, haystack: &'a str) -> bool {
1807-
self[..].is_contained_in(haystack)
1802+
fn into_searcher(self) -> Self::Searcher {
1803+
<&'b str as Needle<&'a str>>::into_searcher(&**self)
18081804
}
18091805

18101806
#[inline]
1811-
fn is_prefix_of(self, haystack: &'a str) -> bool {
1812-
self[..].is_prefix_of(haystack)
1807+
fn into_consumer(self) -> Self::Consumer {
1808+
<&'b str as Needle<&'a str>>::into_consumer(&**self)
18131809
}
18141810
}
18151811

src/liballoc/tests/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
#![feature(box_syntax)]
33
#![feature(drain_filter)]
44
#![feature(exact_size_is_empty)]
5-
#![feature(pattern)]
65
#![feature(repeat_generic_slice)]
6+
#![feature(needle)]
77
#![feature(try_reserve)]
88
#![feature(unboxed_closures)]
99
#![feature(vecdeque_rotate)]
10+
#![feature(mut_str_needle_methods)]
11+
#![feature(slice_needle_methods)]
1012

1113
use std::hash::{Hash, Hasher};
1214
use std::collections::hash_map::DefaultHasher;

src/liballoc/tests/slice.rs

+82-28
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::panic;
55
use std::rc::Rc;
66
use std::sync::atomic::{Ordering::Relaxed, AtomicUsize};
77
use std::thread;
8+
use std::f64::NAN;
89

910
use rand::{Rng, RngCore, thread_rng};
1011
use rand::seq::SliceRandom;
@@ -835,88 +836,88 @@ fn test_splitator() {
835836
let xs = &[1, 2, 3, 4, 5];
836837

837838
let splits: &[&[_]] = &[&[1], &[3], &[5]];
838-
assert_eq!(xs.split(|x| *x % 2 == 0).collect::<Vec<_>>(), splits);
839+
assert_eq!(xs.split(|x: &i32| *x % 2 == 0).collect::<Vec<_>>(), splits);
839840
let splits: &[&[_]] = &[&[], &[2, 3, 4, 5]];
840-
assert_eq!(xs.split(|x| *x == 1).collect::<Vec<_>>(), splits);
841+
assert_eq!(xs.split(|x: &i32| *x == 1).collect::<Vec<_>>(), splits);
841842
let splits: &[&[_]] = &[&[1, 2, 3, 4], &[]];
842-
assert_eq!(xs.split(|x| *x == 5).collect::<Vec<_>>(), splits);
843+
assert_eq!(xs.split(|x: &i32| *x == 5).collect::<Vec<_>>(), splits);
843844
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
844-
assert_eq!(xs.split(|x| *x == 10).collect::<Vec<_>>(), splits);
845+
assert_eq!(xs.split(|x: &i32| *x == 10).collect::<Vec<_>>(), splits);
845846
let splits: &[&[_]] = &[&[], &[], &[], &[], &[], &[]];
846-
assert_eq!(xs.split(|_| true).collect::<Vec<&[i32]>>(), splits);
847+
assert_eq!(xs.split(|_: &i32| true).collect::<Vec<&[i32]>>(), splits);
847848

848849
let xs: &[i32] = &[];
849850
let splits: &[&[i32]] = &[&[]];
850-
assert_eq!(xs.split(|x| *x == 5).collect::<Vec<&[i32]>>(), splits);
851+
assert_eq!(xs.split(|x: &i32| *x == 5).collect::<Vec<&[i32]>>(), splits);
851852
}
852853

853854
#[test]
854855
fn test_splitnator() {
855856
let xs = &[1, 2, 3, 4, 5];
856857

857858
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
858-
assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(), splits);
859+
assert_eq!(xs.splitn(1, |x: &i32| *x % 2 == 0).collect::<Vec<_>>(), splits);
859860
let splits: &[&[_]] = &[&[1], &[3, 4, 5]];
860-
assert_eq!(xs.splitn(2, |x| *x % 2 == 0).collect::<Vec<_>>(), splits);
861+
assert_eq!(xs.splitn(2, |x: &i32| *x % 2 == 0).collect::<Vec<_>>(), splits);
861862
let splits: &[&[_]] = &[&[], &[], &[], &[4, 5]];
862-
assert_eq!(xs.splitn(4, |_| true).collect::<Vec<_>>(), splits);
863+
assert_eq!(xs.splitn(4, |_: &i32| true).collect::<Vec<_>>(), splits);
863864

864865
let xs: &[i32] = &[];
865866
let splits: &[&[i32]] = &[&[]];
866-
assert_eq!(xs.splitn(2, |x| *x == 5).collect::<Vec<_>>(), splits);
867+
assert_eq!(xs.splitn(2, |x: &i32| *x == 5).collect::<Vec<_>>(), splits);
867868
}
868869

869870
#[test]
870871
fn test_splitnator_mut() {
871872
let xs = &mut [1, 2, 3, 4, 5];
872873

873874
let splits: &[&mut [_]] = &[&mut [1, 2, 3, 4, 5]];
874-
assert_eq!(xs.splitn_mut(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
875+
assert_eq!(xs.splitn_mut(1, |x: &i32| *x % 2 == 0).collect::<Vec<_>>(),
875876
splits);
876877
let splits: &[&mut [_]] = &[&mut [1], &mut [3, 4, 5]];
877-
assert_eq!(xs.splitn_mut(2, |x| *x % 2 == 0).collect::<Vec<_>>(),
878+
assert_eq!(xs.splitn_mut(2, |x: &i32| *x % 2 == 0).collect::<Vec<_>>(),
878879
splits);
879880
let splits: &[&mut [_]] = &[&mut [], &mut [], &mut [], &mut [4, 5]];
880-
assert_eq!(xs.splitn_mut(4, |_| true).collect::<Vec<_>>(), splits);
881+
assert_eq!(xs.splitn_mut(4, |_: &i32| true).collect::<Vec<_>>(), splits);
881882

882883
let xs: &mut [i32] = &mut [];
883884
let splits: &[&mut [i32]] = &[&mut []];
884-
assert_eq!(xs.splitn_mut(2, |x| *x == 5).collect::<Vec<_>>(), splits);
885+
assert_eq!(xs.splitn_mut(2, |x: &i32| *x == 5).collect::<Vec<_>>(), splits);
885886
}
886887

887888
#[test]
888889
fn test_rsplitator() {
889890
let xs = &[1, 2, 3, 4, 5];
890891

891892
let splits: &[&[_]] = &[&[5], &[3], &[1]];
892-
assert_eq!(xs.split(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
893+
assert_eq!(xs.split(|x: &i32| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
893894
let splits: &[&[_]] = &[&[2, 3, 4, 5], &[]];
894-
assert_eq!(xs.split(|x| *x == 1).rev().collect::<Vec<_>>(), splits);
895+
assert_eq!(xs.split(|x: &i32| *x == 1).rev().collect::<Vec<_>>(), splits);
895896
let splits: &[&[_]] = &[&[], &[1, 2, 3, 4]];
896-
assert_eq!(xs.split(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
897+
assert_eq!(xs.split(|x: &i32| *x == 5).rev().collect::<Vec<_>>(), splits);
897898
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
898-
assert_eq!(xs.split(|x| *x == 10).rev().collect::<Vec<_>>(), splits);
899+
assert_eq!(xs.split(|x: &i32| *x == 10).rev().collect::<Vec<_>>(), splits);
899900

900901
let xs: &[i32] = &[];
901902
let splits: &[&[i32]] = &[&[]];
902-
assert_eq!(xs.split(|x| *x == 5).rev().collect::<Vec<&[i32]>>(), splits);
903+
assert_eq!(xs.split(|x: &i32| *x == 5).rev().collect::<Vec<&[i32]>>(), splits);
903904
}
904905

905906
#[test]
906907
fn test_rsplitnator() {
907908
let xs = &[1, 2, 3, 4, 5];
908909

909910
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
910-
assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(), splits);
911+
assert_eq!(xs.rsplitn(1, |x: &i32| *x % 2 == 0).collect::<Vec<_>>(), splits);
911912
let splits: &[&[_]] = &[&[5], &[1, 2, 3]];
912-
assert_eq!(xs.rsplitn(2, |x| *x % 2 == 0).collect::<Vec<_>>(), splits);
913+
assert_eq!(xs.rsplitn(2, |x: &i32| *x % 2 == 0).collect::<Vec<_>>(), splits);
913914
let splits: &[&[_]] = &[&[], &[], &[], &[1, 2]];
914-
assert_eq!(xs.rsplitn(4, |_| true).collect::<Vec<_>>(), splits);
915+
assert_eq!(xs.rsplitn(4, |_: &i32| true).collect::<Vec<_>>(), splits);
915916

916917
let xs: &[i32] = &[];
917918
let splits: &[&[i32]] = &[&[]];
918-
assert_eq!(xs.rsplitn(2, |x| *x == 5).collect::<Vec<&[i32]>>(), splits);
919-
assert!(xs.rsplitn(0, |x| *x % 2 == 0).next().is_none());
919+
assert_eq!(xs.rsplitn(2, |x: &i32| *x == 5).collect::<Vec<&[i32]>>(), splits);
920+
assert!(xs.rsplitn(0, |x: &i32| *x % 2 == 0).next().is_none());
920921
}
921922

922923
#[test]
@@ -1209,14 +1210,14 @@ fn test_ends_with() {
12091210
#[test]
12101211
fn test_mut_splitator() {
12111212
let mut xs = [0, 1, 0, 2, 3, 0, 0, 4, 5, 0];
1212-
assert_eq!(xs.split_mut(|x| *x == 0).count(), 6);
1213-
for slice in xs.split_mut(|x| *x == 0) {
1213+
assert_eq!(xs.split_mut(|x: &i32| *x == 0).count(), 6);
1214+
for slice in xs.split_mut(|x: &i32| *x == 0) {
12141215
slice.reverse();
12151216
}
12161217
assert!(xs == [0, 1, 0, 3, 2, 0, 0, 5, 4, 0]);
12171218

12181219
let mut xs = [0, 1, 0, 2, 3, 0, 0, 4, 5, 0, 6, 7];
1219-
for slice in xs.split_mut(|x| *x == 0).take(5) {
1220+
for slice in xs.split_mut(|x: &i32| *x == 0).take(5) {
12201221
slice.reverse();
12211222
}
12221223
assert!(xs == [0, 1, 0, 3, 2, 0, 0, 5, 4, 0, 6, 7]);
@@ -1225,7 +1226,7 @@ fn test_mut_splitator() {
12251226
#[test]
12261227
fn test_mut_splitator_rev() {
12271228
let mut xs = [1, 2, 0, 3, 4, 0, 0, 5, 6, 0];
1228-
for slice in xs.split_mut(|x| *x == 0).rev().take(4) {
1229+
for slice in xs.split_mut(|x: &i32| *x == 0).rev().take(4) {
12291230
slice.reverse();
12301231
}
12311232
assert!(xs == [1, 2, 0, 4, 3, 0, 0, 6, 5, 0]);
@@ -1646,3 +1647,56 @@ fn repeat_generic_slice() {
16461647
vec![1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
16471648
);
16481649
}
1650+
1651+
#[test]
1652+
fn test_match_indices_simple() {
1653+
let haystack = &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 2.0, 3.0, 2.0, 4.0, 8.0][..];
1654+
let needle = &[2.0, 3.0][..];
1655+
1656+
assert_eq!(haystack.match_indices(needle).collect::<Vec<_>>(), vec![
1657+
(1, needle),
1658+
(8, needle),
1659+
]);
1660+
}
1661+
1662+
#[test]
1663+
fn test_match_indices_nan_haystack() {
1664+
let haystack = &[1.0, 2.0, NAN, 1.0, 2.0, NAN, 1.0, NAN, NAN, NAN, 2.0, 1.0, 2.0][..];
1665+
let needle = &[1.0, 2.0][..];
1666+
1667+
assert_eq!(haystack.match_indices(needle).collect::<Vec<_>>(), vec![
1668+
(0, needle),
1669+
(3, needle),
1670+
(11, needle),
1671+
]);
1672+
}
1673+
1674+
#[test]
1675+
fn test_match_indices_nan_needle() {
1676+
let haystack = &[1.0, 2.0, NAN, 1.0, 2.0, NAN, 1.0, NAN, NAN, NAN, 2.0, 1.0, 2.0][..];
1677+
let needle = &[2.0, NAN][..];
1678+
1679+
assert_eq!(haystack.match_indices(needle).collect::<Vec<_>>(), vec![
1680+
]);
1681+
}
1682+
1683+
#[test]
1684+
fn test_match_indices_negative_zero() {
1685+
let haystack = &[-0.0, 0.0, 0.0, -0.0, 0.0][..];
1686+
let needle = &[0.0, -0.0][..];
1687+
1688+
assert_eq!(haystack.match_indices(needle).collect::<Vec<_>>(), vec![
1689+
(0, needle),
1690+
(2, needle),
1691+
]);
1692+
}
1693+
1694+
#[test]
1695+
fn test_replace() {
1696+
let haystack = &b" empowering everyone to build reliable and efficient software."[..];
1697+
1698+
assert_eq!(
1699+
haystack.replace(&b" e"[..], b" **E**"),
1700+
b" **E**mpowering **E**veryone to build reliable and **E**fficient software.".to_vec()
1701+
);
1702+
}

0 commit comments

Comments
 (0)