Skip to content

Commit

Permalink
Auto merge of #59591 - kennytm:needle-api, r=<try>
Browse files Browse the repository at this point in the history
[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.
  • Loading branch information
bors committed Apr 6, 2019
2 parents 209b0b4 + 544e867 commit 81a1b6c
Show file tree
Hide file tree
Showing 30 changed files with 7,083 additions and 3,467 deletions.
2 changes: 1 addition & 1 deletion src/liballoc/lib.rs
Expand Up @@ -93,7 +93,7 @@
#![feature(needs_allocator)]
#![feature(nll)]
#![feature(optin_builtin_traits)]
#![feature(pattern)]
#![feature(needle)]
#![feature(ptr_internals)]
#![feature(ptr_offset_from)]
#![feature(rustc_attrs)]
Expand Down
35 changes: 35 additions & 0 deletions src/liballoc/slice.rs
Expand Up @@ -92,6 +92,7 @@ use core::cmp::Ordering::{self, Less};
use core::mem::{self, size_of};
use core::ptr;
use core::{u8, u16, u32};
use core::needle::{ext, Needle, Searcher, Consumer};

use crate::borrow::ToOwned;
use crate::boxed::Box;
Expand Down Expand Up @@ -485,6 +486,40 @@ impl<T> [T] {
}
buf
}

/// Replaces all matches of a predicate with another slice.
#[unstable(feature = "slice_needle_methods", issue = "56345")]
#[inline]
#[must_use = "this returns the replaced slice as a new allocation, \
without modifying the original"]
pub fn replace<'s: 'a, 'a, F>(&'s self, from: F, to: &'a [T]) -> Vec<T>
where
T: Clone,
F: Needle<&'a [T]>,
F::Searcher: Searcher<[T]>, // FIXME: RFC 2089
F::Consumer: Consumer<[T]>, // FIXME: RFC 2089
{
let mut result = Vec::with_capacity(self.len());
ext::replace_with(self, from, |_| to, |s| result.extend_from_slice(s));
result
}

/// Replaces first N matches of a predicate with another slice.
#[unstable(feature = "slice_needle_methods", issue = "56345")]
#[inline]
#[must_use = "this returns the replaced slice as a new allocation, \
without modifying the original"]
pub fn replacen<'s: 'a, 'a, F>(&'s self, from: F, to: &'a [T], count: usize) -> Vec<T>
where
T: Clone,
F: Needle<&'a [T]>,
F::Searcher: Searcher<[T]>, // FIXME: RFC 2089
F::Consumer: Consumer<[T]>, // FIXME: RFC 2089
{
let mut result = Vec::with_capacity(self.len());
ext::replacen_with(self, from, |_| to, count, |s| result.extend_from_slice(s));
result
}
}

#[lang = "slice_u8_alloc"]
Expand Down
42 changes: 19 additions & 23 deletions src/liballoc/str.rs
Expand Up @@ -28,14 +28,14 @@
// It's cleaner to just turn off the unused_imports warning than to fix them.
#![allow(unused_imports)]

use core::borrow::Borrow;
use core::str::pattern::{Pattern, Searcher, ReverseSearcher, DoubleEndedSearcher};
use core::fmt;
use core::needle::{ext, Needle, Searcher, Consumer};
use core::mem;
use core::ptr;
use core::iter::FusedIterator;
use core::unicode::conversions;

use crate::borrow::ToOwned;
use crate::borrow::{Borrow, ToOwned};
use crate::boxed::Box;
use crate::slice::{SliceConcatExt, SliceIndex};
use crate::string::String;
Expand All @@ -62,8 +62,6 @@ pub use core::str::{from_utf8, from_utf8_mut, Chars, CharIndices, Bytes};
pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::str::SplitWhitespace;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::str::pattern;
#[stable(feature = "encode_utf16", since = "1.8.0")]
pub use core::str::EncodeUtf16;
#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
Expand Down Expand Up @@ -253,15 +251,14 @@ impl str {
without modifying the original"]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn replace<'a, P: Pattern<'a>>(&'a self, from: P, to: &str) -> String {
let mut result = String::new();
let mut last_end = 0;
for (start, part) in self.match_indices(from) {
result.push_str(unsafe { self.get_unchecked(last_end..start) });
result.push_str(to);
last_end = start + part.len();
}
result.push_str(unsafe { self.get_unchecked(last_end..self.len()) });
pub fn replace<'s: 'a, 'a, P>(&'s self, from: P, to: &'a str) -> String
where
P: Needle<&'a str>,
P::Searcher: Searcher<str>, // FIXME: RFC 2089
P::Consumer: Consumer<str>, // FIXME: RFC 2089
{
let mut result = String::with_capacity(self.len());
ext::replace_with(self, from, |_| to, |s| result.push_str(s));
result
}

Expand Down Expand Up @@ -293,16 +290,15 @@ 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<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String {
pub fn replacen<'s: 'a, 'a, P>(&'s self, pat: P, to: &'a str, count: usize) -> String
where
P: Needle<&'a str>,
P::Searcher: Searcher<str>, // FIXME: RFC 2089
P::Consumer: Consumer<str>, // FIXME: RFC 2089
{
// Hope to reduce the times of re-allocation
let mut result = String::with_capacity(32);
let mut last_end = 0;
for (start, part) in self.match_indices(pat).take(count) {
result.push_str(unsafe { self.get_unchecked(last_end..start) });
result.push_str(to);
last_end = start + part.len();
}
result.push_str(unsafe { self.get_unchecked(last_end..self.len()) });
let mut result = String::with_capacity(self.len());
ext::replacen_with(self, pat, |_| to, count, |s| result.push_str(s));
result
}

Expand Down
24 changes: 10 additions & 14 deletions src/liballoc/string.rs
Expand Up @@ -53,7 +53,8 @@ use core::iter::{FromIterator, FusedIterator};
use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds};
use core::ops::Bound::{Excluded, Included, Unbounded};
use core::ptr;
use core::str::{pattern::Pattern, lossy};
use core::needle::Needle;
use core::str::lossy;

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

/// A convenience impl that delegates to the impl for `&str`
#[unstable(feature = "pattern",
reason = "API not fully fleshed out and ready to be stabilized",
issue = "27721")]
impl<'a, 'b> Pattern<'a> for &'b String {
type Searcher = <&'b str as Pattern<'a>>::Searcher;

fn into_searcher(self, haystack: &'a str) -> <&'b str as Pattern<'a>>::Searcher {
self[..].into_searcher(haystack)
}
#[unstable(feature = "needle", issue = "56345")]
impl<'a, 'b> Needle<&'a str> for &'b String {
type Searcher = <&'b str as Needle<&'a str>>::Searcher;
type Consumer = <&'b str as Needle<&'a str>>::Consumer;

#[inline]
fn is_contained_in(self, haystack: &'a str) -> bool {
self[..].is_contained_in(haystack)
fn into_searcher(self) -> Self::Searcher {
<&'b str as Needle<&'a str>>::into_searcher(&**self)
}

#[inline]
fn is_prefix_of(self, haystack: &'a str) -> bool {
self[..].is_prefix_of(haystack)
fn into_consumer(self) -> Self::Consumer {
<&'b str as Needle<&'a str>>::into_consumer(&**self)
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/liballoc/tests/lib.rs
Expand Up @@ -2,11 +2,13 @@
#![feature(box_syntax)]
#![feature(drain_filter)]
#![feature(exact_size_is_empty)]
#![feature(pattern)]
#![feature(repeat_generic_slice)]
#![feature(needle)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(vecdeque_rotate)]
#![feature(mut_str_needle_methods)]
#![feature(slice_needle_methods)]

use std::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;
Expand Down
110 changes: 82 additions & 28 deletions src/liballoc/tests/slice.rs
Expand Up @@ -5,6 +5,7 @@ use std::panic;
use std::rc::Rc;
use std::sync::atomic::{Ordering::Relaxed, AtomicUsize};
use std::thread;
use std::f64::NAN;

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

let splits: &[&[_]] = &[&[1], &[3], &[5]];
assert_eq!(xs.split(|x| *x % 2 == 0).collect::<Vec<_>>(), splits);
assert_eq!(xs.split(|x: &i32| *x % 2 == 0).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[], &[2, 3, 4, 5]];
assert_eq!(xs.split(|x| *x == 1).collect::<Vec<_>>(), splits);
assert_eq!(xs.split(|x: &i32| *x == 1).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4], &[]];
assert_eq!(xs.split(|x| *x == 5).collect::<Vec<_>>(), splits);
assert_eq!(xs.split(|x: &i32| *x == 5).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.split(|x| *x == 10).collect::<Vec<_>>(), splits);
assert_eq!(xs.split(|x: &i32| *x == 10).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[], &[], &[], &[], &[], &[]];
assert_eq!(xs.split(|_| true).collect::<Vec<&[i32]>>(), splits);
assert_eq!(xs.split(|_: &i32| true).collect::<Vec<&[i32]>>(), splits);

let xs: &[i32] = &[];
let splits: &[&[i32]] = &[&[]];
assert_eq!(xs.split(|x| *x == 5).collect::<Vec<&[i32]>>(), splits);
assert_eq!(xs.split(|x: &i32| *x == 5).collect::<Vec<&[i32]>>(), splits);
}

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

let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(), splits);
assert_eq!(xs.splitn(1, |x: &i32| *x % 2 == 0).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1], &[3, 4, 5]];
assert_eq!(xs.splitn(2, |x| *x % 2 == 0).collect::<Vec<_>>(), splits);
assert_eq!(xs.splitn(2, |x: &i32| *x % 2 == 0).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[], &[], &[], &[4, 5]];
assert_eq!(xs.splitn(4, |_| true).collect::<Vec<_>>(), splits);
assert_eq!(xs.splitn(4, |_: &i32| true).collect::<Vec<_>>(), splits);

let xs: &[i32] = &[];
let splits: &[&[i32]] = &[&[]];
assert_eq!(xs.splitn(2, |x| *x == 5).collect::<Vec<_>>(), splits);
assert_eq!(xs.splitn(2, |x: &i32| *x == 5).collect::<Vec<_>>(), splits);
}

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

let splits: &[&mut [_]] = &[&mut [1, 2, 3, 4, 5]];
assert_eq!(xs.splitn_mut(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
assert_eq!(xs.splitn_mut(1, |x: &i32| *x % 2 == 0).collect::<Vec<_>>(),
splits);
let splits: &[&mut [_]] = &[&mut [1], &mut [3, 4, 5]];
assert_eq!(xs.splitn_mut(2, |x| *x % 2 == 0).collect::<Vec<_>>(),
assert_eq!(xs.splitn_mut(2, |x: &i32| *x % 2 == 0).collect::<Vec<_>>(),
splits);
let splits: &[&mut [_]] = &[&mut [], &mut [], &mut [], &mut [4, 5]];
assert_eq!(xs.splitn_mut(4, |_| true).collect::<Vec<_>>(), splits);
assert_eq!(xs.splitn_mut(4, |_: &i32| true).collect::<Vec<_>>(), splits);

let xs: &mut [i32] = &mut [];
let splits: &[&mut [i32]] = &[&mut []];
assert_eq!(xs.splitn_mut(2, |x| *x == 5).collect::<Vec<_>>(), splits);
assert_eq!(xs.splitn_mut(2, |x: &i32| *x == 5).collect::<Vec<_>>(), splits);
}

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

let splits: &[&[_]] = &[&[5], &[3], &[1]];
assert_eq!(xs.split(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
assert_eq!(xs.split(|x: &i32| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[2, 3, 4, 5], &[]];
assert_eq!(xs.split(|x| *x == 1).rev().collect::<Vec<_>>(), splits);
assert_eq!(xs.split(|x: &i32| *x == 1).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[], &[1, 2, 3, 4]];
assert_eq!(xs.split(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
assert_eq!(xs.split(|x: &i32| *x == 5).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.split(|x| *x == 10).rev().collect::<Vec<_>>(), splits);
assert_eq!(xs.split(|x: &i32| *x == 10).rev().collect::<Vec<_>>(), splits);

let xs: &[i32] = &[];
let splits: &[&[i32]] = &[&[]];
assert_eq!(xs.split(|x| *x == 5).rev().collect::<Vec<&[i32]>>(), splits);
assert_eq!(xs.split(|x: &i32| *x == 5).rev().collect::<Vec<&[i32]>>(), splits);
}

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

let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(), splits);
assert_eq!(xs.rsplitn(1, |x: &i32| *x % 2 == 0).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[5], &[1, 2, 3]];
assert_eq!(xs.rsplitn(2, |x| *x % 2 == 0).collect::<Vec<_>>(), splits);
assert_eq!(xs.rsplitn(2, |x: &i32| *x % 2 == 0).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[], &[], &[], &[1, 2]];
assert_eq!(xs.rsplitn(4, |_| true).collect::<Vec<_>>(), splits);
assert_eq!(xs.rsplitn(4, |_: &i32| true).collect::<Vec<_>>(), splits);

let xs: &[i32] = &[];
let splits: &[&[i32]] = &[&[]];
assert_eq!(xs.rsplitn(2, |x| *x == 5).collect::<Vec<&[i32]>>(), splits);
assert!(xs.rsplitn(0, |x| *x % 2 == 0).next().is_none());
assert_eq!(xs.rsplitn(2, |x: &i32| *x == 5).collect::<Vec<&[i32]>>(), splits);
assert!(xs.rsplitn(0, |x: &i32| *x % 2 == 0).next().is_none());
}

#[test]
Expand Down Expand Up @@ -1209,14 +1210,14 @@ fn test_ends_with() {
#[test]
fn test_mut_splitator() {
let mut xs = [0, 1, 0, 2, 3, 0, 0, 4, 5, 0];
assert_eq!(xs.split_mut(|x| *x == 0).count(), 6);
for slice in xs.split_mut(|x| *x == 0) {
assert_eq!(xs.split_mut(|x: &i32| *x == 0).count(), 6);
for slice in xs.split_mut(|x: &i32| *x == 0) {
slice.reverse();
}
assert!(xs == [0, 1, 0, 3, 2, 0, 0, 5, 4, 0]);

let mut xs = [0, 1, 0, 2, 3, 0, 0, 4, 5, 0, 6, 7];
for slice in xs.split_mut(|x| *x == 0).take(5) {
for slice in xs.split_mut(|x: &i32| *x == 0).take(5) {
slice.reverse();
}
assert!(xs == [0, 1, 0, 3, 2, 0, 0, 5, 4, 0, 6, 7]);
Expand All @@ -1225,7 +1226,7 @@ fn test_mut_splitator() {
#[test]
fn test_mut_splitator_rev() {
let mut xs = [1, 2, 0, 3, 4, 0, 0, 5, 6, 0];
for slice in xs.split_mut(|x| *x == 0).rev().take(4) {
for slice in xs.split_mut(|x: &i32| *x == 0).rev().take(4) {
slice.reverse();
}
assert!(xs == [1, 2, 0, 4, 3, 0, 0, 6, 5, 0]);
Expand Down Expand Up @@ -1646,3 +1647,56 @@ fn repeat_generic_slice() {
vec![1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
);
}

#[test]
fn test_match_indices_simple() {
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][..];
let needle = &[2.0, 3.0][..];

assert_eq!(haystack.match_indices(needle).collect::<Vec<_>>(), vec![
(1, needle),
(8, needle),
]);
}

#[test]
fn test_match_indices_nan_haystack() {
let haystack = &[1.0, 2.0, NAN, 1.0, 2.0, NAN, 1.0, NAN, NAN, NAN, 2.0, 1.0, 2.0][..];
let needle = &[1.0, 2.0][..];

assert_eq!(haystack.match_indices(needle).collect::<Vec<_>>(), vec![
(0, needle),
(3, needle),
(11, needle),
]);
}

#[test]
fn test_match_indices_nan_needle() {
let haystack = &[1.0, 2.0, NAN, 1.0, 2.0, NAN, 1.0, NAN, NAN, NAN, 2.0, 1.0, 2.0][..];
let needle = &[2.0, NAN][..];

assert_eq!(haystack.match_indices(needle).collect::<Vec<_>>(), vec![
]);
}

#[test]
fn test_match_indices_negative_zero() {
let haystack = &[-0.0, 0.0, 0.0, -0.0, 0.0][..];
let needle = &[0.0, -0.0][..];

assert_eq!(haystack.match_indices(needle).collect::<Vec<_>>(), vec![
(0, needle),
(2, needle),
]);
}

#[test]
fn test_replace() {
let haystack = &b" empowering everyone to build reliable and efficient software."[..];

assert_eq!(
haystack.replace(&b" e"[..], b" **E**"),
b" **E**mpowering **E**veryone to build reliable and **E**fficient software.".to_vec()
);
}

0 comments on commit 81a1b6c

Please sign in to comment.