From 274e2993cbbfe7182ff6b79064addf171cf5a5aa Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Mon, 12 Oct 2020 15:52:46 +0100 Subject: [PATCH 1/5] Stablize slice::strip_prefix and strip_suffix, with SlicePattern We hope later to extend `core::str::Pattern` to slices too, perhaps as part of stabilising that. We want to minimise the amount of type inference breakage when we do that, so we don't want to stabilise strip_prefix and strip_suffix taking a simple `&[T]`. @KodrAus suggested the approach of introducing a new perma-unstable trait, which reduces this future inference break risk. I found it necessary to make two impls of this trait, as the unsize coercion don't apply when hunting for trait implementations. Since SlicePattern's only method returns a reference, and the whole trait is just a wrapper for slices, I made the trait type be the non-reference type [T] or [T;N] rather than the reference. Otherwise the trait would have a lifetime parameter. I marked both the no-op conversion functions `#[inline]`. I'm not sure if that is necessary but it seemed at the very least harmless. Signed-off-by: Ian Jackson --- library/core/src/slice/mod.rs | 48 ++++++++++++++++++++++++++++++----- library/std/src/lib.rs | 1 - 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index f5af48e0dd277..0556bb1e633db 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1778,7 +1778,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_strip)] /// let v = &[10, 40, 30]; /// assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..])); /// assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..])); @@ -1786,12 +1785,14 @@ impl [T] { /// assert_eq!(v.strip_prefix(&[10, 50]), None); /// ``` #[must_use = "returns the subslice without modifying the original"] - #[unstable(feature = "slice_strip", issue = "73413")] - pub fn strip_prefix(&self, prefix: &[T]) -> Option<&[T]> + #[stable(feature = "slice_strip", since = "1.50.0")] + pub fn strip_prefix>(&self, prefix: &P) -> Option<&[T]> where T: PartialEq, { - let n = prefix.len(); + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let prefix = prefix.as_slice(); + let n = prefix.as_slice().len(); if n <= self.len() { let (head, tail) = self.split_at(n); if head == prefix { @@ -1811,7 +1812,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_strip)] /// let v = &[10, 40, 30]; /// assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..])); /// assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..])); @@ -1819,11 +1819,13 @@ impl [T] { /// assert_eq!(v.strip_suffix(&[50, 30]), None); /// ``` #[must_use = "returns the subslice without modifying the original"] - #[unstable(feature = "slice_strip", issue = "73413")] - pub fn strip_suffix(&self, suffix: &[T]) -> Option<&[T]> + #[stable(feature = "slice_strip", since = "1.50.0")] + pub fn strip_suffix>(&self, suffix: &P) -> Option<&[T]> where T: PartialEq, { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let suffix = suffix.as_slice(); let (len, n) = (self.len(), suffix.len()); if n <= len { let (head, tail) = self.split_at(len - n); @@ -3216,3 +3218,35 @@ impl Default for &mut [T] { &mut [] } } + +#[unstable(feature = "x", issue = "none")] +/// Patterns in slices - currently, only used by `strip_prefix` and `strip_suffix`. At a future +/// point, we hope to generalise `core::str::Pattern` (which at the time of writing is limited to +/// `str`) to slices, and then this trait will be replaced or abolished. +pub trait SlicePattern { + /// The element type of the slice being matched on. + type Item; + + /// Currently, the consumers of `SlicePattern` need a slice. + fn as_slice(&self) -> &[Self::Item]; +} + +#[stable(feature = "slice_strip", since = "1.50.0")] +impl SlicePattern for [T] { + type Item = T; + + #[inline] + fn as_slice(&self) -> &[Self::Item] { + self + } +} + +#[stable(feature = "slice_strip", since = "1.50.0")] +impl SlicePattern for [T; N] { + type Item = T; + + #[inline] + fn as_slice(&self) -> &[Self::Item] { + self + } +} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 5bc5ddaa5fe30..6c3c2fd53d8ca 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -307,7 +307,6 @@ #![feature(slice_internals)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] -#![feature(slice_strip)] #![feature(staged_api)] #![feature(std_internals)] #![feature(stdsimd)] From f51b68199c80288185f8619c5a2e34cc1cfd85c4 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sat, 12 Dec 2020 13:41:38 +0000 Subject: [PATCH 2/5] Use existing slice_pattern feature for SlicePattern Co-authored-by: Ashley Mannix --- library/core/src/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 0556bb1e633db..5f1fe08fe8102 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3219,7 +3219,7 @@ impl Default for &mut [T] { } } -#[unstable(feature = "x", issue = "none")] +#[unstable(feature = "slice_pattern", reason = "stopgap trait for slice patterns", issue = "56345")] /// Patterns in slices - currently, only used by `strip_prefix` and `strip_suffix`. At a future /// point, we hope to generalise `core::str::Pattern` (which at the time of writing is limited to /// `str`) to slices, and then this trait will be replaced or abolished. From beb293d5dfeb17e3dcf1ed348a665f33861691fe Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sun, 27 Dec 2020 00:20:59 +0000 Subject: [PATCH 3/5] Drop pointless as_slice call. Co-authored-by: David Tolnay --- library/core/src/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 5f1fe08fe8102..1ab7d68805abf 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1792,7 +1792,7 @@ impl [T] { { // This function will need rewriting if and when SlicePattern becomes more sophisticated. let prefix = prefix.as_slice(); - let n = prefix.as_slice().len(); + let n = prefix.len(); if n <= self.len() { let (head, tail) = self.split_at(n); if head == prefix { From 03b4ea463a8b2e45032e9cd6f7e293561b01c3ce Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sun, 27 Dec 2020 01:13:21 +0000 Subject: [PATCH 4/5] Mark SlicePattern trait uses as ?Sized This trait is ?Sized and is often slices. Signed-off-by: Ian Jackson --- library/core/src/slice/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 1ab7d68805abf..23830548f68de 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1786,7 +1786,7 @@ impl [T] { /// ``` #[must_use = "returns the subslice without modifying the original"] #[stable(feature = "slice_strip", since = "1.50.0")] - pub fn strip_prefix>(&self, prefix: &P) -> Option<&[T]> + pub fn strip_prefix + ?Sized>(&self, prefix: &P) -> Option<&[T]> where T: PartialEq, { @@ -1820,7 +1820,7 @@ impl [T] { /// ``` #[must_use = "returns the subslice without modifying the original"] #[stable(feature = "slice_strip", since = "1.50.0")] - pub fn strip_suffix>(&self, suffix: &P) -> Option<&[T]> + pub fn strip_suffix + ?Sized>(&self, suffix: &P) -> Option<&[T]> where T: PartialEq, { From 8b2e79dbac324b703493113c9f823e63cf1df4e0 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sun, 27 Dec 2020 00:53:02 +0000 Subject: [PATCH 5/5] Add test for slice as prefix/suffix pattern Signed-off-by: Ian Jackson --- library/core/src/slice/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 23830548f68de..fb6d9156cea4f 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1783,6 +1783,10 @@ impl [T] { /// assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..])); /// assert_eq!(v.strip_prefix(&[50]), None); /// assert_eq!(v.strip_prefix(&[10, 50]), None); + /// + /// let prefix : &str = "he"; + /// assert_eq!(b"hello".strip_prefix(prefix.as_bytes()), + /// Some(b"llo".as_ref())); /// ``` #[must_use = "returns the subslice without modifying the original"] #[stable(feature = "slice_strip", since = "1.50.0")]