Skip to content

Commit

Permalink
Replace SliceConcatExt trait with inherent methods and SliceConcat he…
Browse files Browse the repository at this point in the history
…lper trait

Before this change `SliceConcatExt` was an unstable extension trait
with stable methods. It was in the libstd prelude, so that its methods
could be used on the stable channel.

This replaces it with inherent methods,
which can be used without any addition to the prelude.
Since the methods are stable and very generic
(with for example a return type that depends on the types of parameters),
an helper trait is still needed.
But now that trait does not need to be in scope for the methods to be used.

Removing this depedency on the libstd prelude allows the methods to be used
in `#![no_std]` crate that use liballoc, which does not have its own
implicitly-imported prelude.
  • Loading branch information
SimonSapin committed Jul 5, 2019
1 parent baab191 commit e808d92
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 74 deletions.
1 change: 0 additions & 1 deletion src/liballoc/prelude/v1.rs
Expand Up @@ -6,6 +6,5 @@

#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::borrow::ToOwned;
#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::boxed::Box;
#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::slice::SliceConcatExt;
#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::string::{String, ToString};
#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::vec::Vec;
129 changes: 69 additions & 60 deletions src/liballoc/slice.rs
Expand Up @@ -484,6 +484,56 @@ impl<T> [T] {
}
buf
}

/// Flattens a slice of `T` into a single value `Self::Output`.
///
/// # Examples
///
/// ```
/// assert_eq!(["hello", "world"].concat(), "helloworld");
/// assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn concat<Separator: ?Sized>(&self) -> T::Output
where T: SliceConcat<Separator>
{
SliceConcat::concat(self)
}

/// Flattens a slice of `T` into a single value `Self::Output`, placing a
/// given separator between each.
///
/// # Examples
///
/// ```
/// assert_eq!(["hello", "world"].join(" "), "hello world");
/// assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]);
/// ```
#[stable(feature = "rename_connect_to_join", since = "1.3.0")]
pub fn join<Separator: ?Sized>(&self, sep: &Separator) -> T::Output
where T: SliceConcat<Separator>
{
SliceConcat::join(self, sep)
}

/// Flattens a slice of `T` into a single value `Self::Output`, placing a
/// given separator between each.
///
/// # Examples
///
/// ```
/// # #![allow(deprecated)]
/// assert_eq!(["hello", "world"].connect(" "), "hello world");
/// assert_eq!([[1, 2], [3, 4]].connect(&0), [1, 2, 0, 3, 4]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(since = "1.3.0", reason = "renamed to join")]
pub fn connect<Separator: ?Sized>(&self, sep: &Separator) -> T::Output
where T: SliceConcat<Separator>
{
SliceConcat::join(self, sep)
}

}

#[lang = "slice_u8_alloc"]
Expand Down Expand Up @@ -527,87 +577,46 @@ impl [u8] {
////////////////////////////////////////////////////////////////////////////////
// Extension traits for slices over specific kinds of data
////////////////////////////////////////////////////////////////////////////////
#[unstable(feature = "slice_concat_ext",
reason = "trait should not have to exist",
issue = "27747")]
/// An extension trait for concatenating slices
///
/// While this trait is unstable, the methods are stable. `SliceConcatExt` is
/// included in the [standard library prelude], so you can use [`join()`] and
/// [`concat()`] as if they existed on `[T]` itself.
///
/// [standard library prelude]: ../../std/prelude/index.html
/// [`join()`]: #tymethod.join
/// [`concat()`]: #tymethod.concat
pub trait SliceConcatExt<T: ?Sized> {
#[unstable(feature = "slice_concat_ext",
reason = "trait should not have to exist",
issue = "27747")]

/// Helper trait for [`[T]::concat`](../../std/primitive.slice.html#method.concat)
/// and [`[T]::join`](../../std/primitive.slice.html#method.join)
#[unstable(feature = "slice_concat_trait", issue = "27747")]
pub trait SliceConcat<Separator: ?Sized>: Sized {
#[unstable(feature = "slice_concat_trait", issue = "27747")]
/// The resulting type after concatenation
type Output;

/// Flattens a slice of `T` into a single value `Self::Output`.
///
/// # Examples
///
/// ```
/// assert_eq!(["hello", "world"].concat(), "helloworld");
/// assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn concat(&self) -> Self::Output;

/// Flattens a slice of `T` into a single value `Self::Output`, placing a
/// given separator between each.
///
/// # Examples
///
/// ```
/// assert_eq!(["hello", "world"].join(" "), "hello world");
/// assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]);
/// ```
#[stable(feature = "rename_connect_to_join", since = "1.3.0")]
fn join(&self, sep: &T) -> Self::Output;
/// Implementation of [`[T]::concat`](../../std/primitive.slice.html#method.concat)
#[unstable(feature = "slice_concat_trait", issue = "27747")]
fn concat(slice: &[Self]) -> Self::Output;

/// Flattens a slice of `T` into a single value `Self::Output`, placing a
/// given separator between each.
///
/// # Examples
///
/// ```
/// # #![allow(deprecated)]
/// assert_eq!(["hello", "world"].connect(" "), "hello world");
/// assert_eq!([[1, 2], [3, 4]].connect(&0), [1, 2, 0, 3, 4]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(since = "1.3.0", reason = "renamed to join")]
fn connect(&self, sep: &T) -> Self::Output {
self.join(sep)
}
/// Implementation of [`[T]::join`](../../std/primitive.slice.html#method.join)
#[unstable(feature = "slice_concat_trait", issue = "27747")]
fn join(slice: &[Self], sep: &Separator) -> Self::Output;
}

#[unstable(feature = "slice_concat_ext",
reason = "trait should not have to exist",
issue = "27747")]
impl<T: Clone, V: Borrow<[T]>> SliceConcatExt<T> for [V] {
impl<T: Clone, V: Borrow<[T]>> SliceConcat<T> for V {
type Output = Vec<T>;

fn concat(&self) -> Vec<T> {
let size = self.iter().map(|slice| slice.borrow().len()).sum();
fn concat(slice: &[Self]) -> Vec<T> {
let size = slice.iter().map(|slice| slice.borrow().len()).sum();
let mut result = Vec::with_capacity(size);
for v in self {
for v in slice {
result.extend_from_slice(v.borrow())
}
result
}

fn join(&self, sep: &T) -> Vec<T> {
let mut iter = self.iter();
fn join(slice: &[Self], sep: &T) -> Vec<T> {
let mut iter = slice.iter();
let first = match iter.next() {
Some(first) => first,
None => return vec![],
};
let size = self.iter().map(|slice| slice.borrow().len()).sum::<usize>() + self.len() - 1;
let size = slice.iter().map(|slice| slice.borrow().len()).sum::<usize>() + slice.len() - 1;
let mut result = Vec::with_capacity(size);
result.extend_from_slice(first.borrow());

Expand Down
14 changes: 7 additions & 7 deletions src/liballoc/str.rs
Expand Up @@ -37,7 +37,7 @@ use core::unicode::conversions;

use crate::borrow::ToOwned;
use crate::boxed::Box;
use crate::slice::{SliceConcatExt, SliceIndex};
use crate::slice::{SliceConcat, SliceIndex};
use crate::string::String;
use crate::vec::Vec;

Expand Down Expand Up @@ -74,16 +74,16 @@ pub use core::str::{EscapeDebug, EscapeDefault, EscapeUnicode};
#[unstable(feature = "slice_concat_ext",
reason = "trait should not have to exist",
issue = "27747")]
impl<S: Borrow<str>> SliceConcatExt<str> for [S] {
impl<S: Borrow<str>> SliceConcat<str> for S {
type Output = String;

fn concat(&self) -> String {
self.join("")
fn concat(slice: &[Self]) -> String {
Self::join(slice, "")
}

fn join(&self, sep: &str) -> String {
fn join(slice: &[Self], sep: &str) -> String {
unsafe {
String::from_utf8_unchecked( join_generic_copy(self, sep.as_bytes()) )
String::from_utf8_unchecked( join_generic_copy(slice, sep.as_bytes()) )
}
}
}
Expand Down Expand Up @@ -126,7 +126,7 @@ macro_rules! copy_slice_and_advance {

// Optimized join implementation that works for both Vec<T> (T: Copy) and String's inner vec
// Currently (2018-05-13) there is a bug with type inference and specialization (see issue #36262)
// For this reason SliceConcatExt<T> is not specialized for T: Copy and SliceConcatExt<str> is the
// For this reason SliceConcat<T> is not specialized for T: Copy and SliceConcat<str> is the
// only user of this function. It is left in place for the time when that is fixed.
//
// the bounds for String-join are S: Borrow<str> and for Vec-join Borrow<[T]>
Expand Down
3 changes: 0 additions & 3 deletions src/libstd/prelude/mod.rs
Expand Up @@ -71,9 +71,6 @@
//! * [`std::result`]::[`Result`]::{`self`, `Ok`, `Err`}. A type for functions
//! that may succeed or fail. Like [`Option`], its variants are exported as
//! well.
//! * [`std::slice`]::[`SliceConcatExt`], a trait that exists for technical
//! reasons, but shouldn't have to exist. It provides a few useful methods on
//! slices.
//! * [`std::string`]::{[`String`], [`ToString`]}, heap allocated strings.
//! * [`std::vec`]::[`Vec`](../vec/struct.Vec.html), a growable, heap-allocated
//! vector.
Expand Down
3 changes: 0 additions & 3 deletions src/libstd/prelude/v1.rs
Expand Up @@ -60,9 +60,6 @@ pub use crate::boxed::Box;
pub use crate::borrow::ToOwned;
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use crate::slice::SliceConcatExt;
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use crate::string::{String, ToString};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
Expand Down

0 comments on commit e808d92

Please sign in to comment.