about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/slice.rs104
-rw-r--r--src/liballoc/str.rs21
2 files changed, 96 insertions, 29 deletions
diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs
index bc4ae167984..881d499c074 100644
--- a/src/liballoc/slice.rs
+++ b/src/liballoc/slice.rs
@@ -494,10 +494,10 @@ impl<T> [T] {
     /// 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>
+    pub fn concat<Item: ?Sized>(&self) -> <Self as Concat<Item>>::Output
+        where Self: Concat<Item>
     {
-        SliceConcat::concat(self)
+        Concat::concat(self)
     }
 
     /// Flattens a slice of `T` into a single value `Self::Output`, placing a
@@ -508,12 +508,13 @@ impl<T> [T] {
     /// ```
     /// assert_eq!(["hello", "world"].join(" "), "hello world");
     /// assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]);
+    /// assert_eq!([[1, 2], [3, 4]].join(&[0, 0][..]), [1, 2, 0, 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>
+    pub fn join<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Output
+        where Self: Join<Separator>
     {
-        SliceConcat::join(self, sep)
+        Join::join(self, sep)
     }
 
     /// Flattens a slice of `T` into a single value `Self::Output`, placing a
@@ -528,10 +529,10 @@ impl<T> [T] {
     /// ```
     #[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>
+    pub fn connect<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Output
+        where Self: Join<Separator>
     {
-        SliceConcat::join(self, sep)
+        Join::join(self, sep)
     }
 
 }
@@ -578,30 +579,63 @@ impl [u8] {
 // Extension traits for slices over specific kinds of data
 ////////////////////////////////////////////////////////////////////////////////
 
-/// Helper trait for [`[T]::concat`](../../std/primitive.slice.html#method.concat)
-/// and [`[T]::join`](../../std/primitive.slice.html#method.join)
+/// Helper trait for [`[T]::concat`](../../std/primitive.slice.html#method.concat).
+///
+/// Note: the `Item` type parameter is not used in this trait,
+/// but it allows impls to be more generic.
+/// Without it, we get this error:
+///
+/// ```error
+/// error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predica
+///    --> src/liballoc/slice.rs:608:6
+///     |
+/// 608 | impl<T: Clone, V: Borrow<[T]>> Concat for [V] {
+///     |      ^ unconstrained type parameter
+/// ```
+///
+/// This is because there could exist `V` types with multiple `Borrow<[_]>` impls,
+/// such that multiple `T` types would apply:
+///
+/// ```
+/// # #[allow(dead_code)]
+/// pub struct Foo(Vec<u32>, Vec<String>);
+///
+/// impl std::borrow::Borrow<[u32]> for Foo {
+///     fn borrow(&self) -> &[u32] { &self.0 }
+/// }
+///
+/// impl std::borrow::Borrow<[String]> for Foo {
+///     fn borrow(&self) -> &[String] { &self.1 }
+/// }
+/// ```
 #[unstable(feature = "slice_concat_trait", issue = "27747")]
-pub trait SliceConcat<Separator: ?Sized>: Sized {
+pub trait Concat<Item: ?Sized> {
     #[unstable(feature = "slice_concat_trait", issue = "27747")]
     /// The resulting type after concatenation
     type Output;
 
     /// Implementation of [`[T]::concat`](../../std/primitive.slice.html#method.concat)
     #[unstable(feature = "slice_concat_trait", issue = "27747")]
-    fn concat(slice: &[Self]) -> Self::Output;
+    fn concat(slice: &Self) -> Self::Output;
+}
+
+/// Helper trait for [`[T]::join`](../../std/primitive.slice.html#method.join)
+#[unstable(feature = "slice_concat_trait", issue = "27747")]
+pub trait Join<Separator> {
+    #[unstable(feature = "slice_concat_trait", issue = "27747")]
+    /// The resulting type after concatenation
+    type Output;
 
     /// 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;
+    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]>> SliceConcat<T> for V {
+#[unstable(feature = "slice_concat_ext", issue = "27747")]
+impl<T: Clone, V: Borrow<[T]>> Concat<T> for [V] {
     type Output = Vec<T>;
 
-    fn concat(slice: &[Self]) -> Vec<T> {
+    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 slice {
@@ -609,14 +643,19 @@ impl<T: Clone, V: Borrow<[T]>> SliceConcat<T> for V {
         }
         result
     }
+}
+
+#[unstable(feature = "slice_concat_ext", issue = "27747")]
+impl<T: Clone, V: Borrow<[T]>> Join<&T> for [V] {
+    type Output = Vec<T>;
 
-    fn join(slice: &[Self], sep: &T) -> Vec<T> {
+    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 = slice.iter().map(|slice| slice.borrow().len()).sum::<usize>() + slice.len() - 1;
+        let size = slice.iter().map(|v| v.borrow().len()).sum::<usize>() + slice.len() - 1;
         let mut result = Vec::with_capacity(size);
         result.extend_from_slice(first.borrow());
 
@@ -628,6 +667,29 @@ impl<T: Clone, V: Borrow<[T]>> SliceConcat<T> for V {
     }
 }
 
+#[unstable(feature = "slice_concat_ext", issue = "27747")]
+impl<T: Clone, V: Borrow<[T]>> Join<&[T]> for [V] {
+    type Output = Vec<T>;
+
+    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 = slice.iter().map(|v| v.borrow().len()).sum::<usize>() +
+            sep.len() * (slice.len() - 1);
+        let mut result = Vec::with_capacity(size);
+        result.extend_from_slice(first.borrow());
+
+        for v in iter {
+            result.extend_from_slice(sep);
+            result.extend_from_slice(v.borrow())
+        }
+        result
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Standard trait implementations for slices
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs
index 37a1046d094..9a1342c30d5 100644
--- a/src/liballoc/str.rs
+++ b/src/liballoc/str.rs
@@ -37,7 +37,7 @@ use core::unicode::conversions;
 
 use crate::borrow::ToOwned;
 use crate::boxed::Box;
-use crate::slice::{SliceConcat, SliceIndex};
+use crate::slice::{Concat, Join, SliceIndex};
 use crate::string::String;
 use crate::vec::Vec;
 
@@ -71,17 +71,22 @@ pub use core::str::SplitAsciiWhitespace;
 #[stable(feature = "str_escape", since = "1.34.0")]
 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>> SliceConcat<str> for S {
+/// Note: `str` in `Concat<str>` is not meaningful here.
+/// This type parameter of the trait only exists to enable another impl.
+#[unstable(feature = "slice_concat_ext", issue = "27747")]
+impl<S: Borrow<str>> Concat<str> for [S] {
     type Output = String;
 
-    fn concat(slice: &[Self]) -> String {
-        Self::join(slice, "")
+    fn concat(slice: &Self) -> String {
+        Join::join(slice, "")
     }
+}
+
+#[unstable(feature = "slice_concat_ext", issue = "27747")]
+impl<S: Borrow<str>> Join<&str> for [S] {
+    type Output = String;
 
-    fn join(slice: &[Self], sep: &str) -> String {
+    fn join(slice: &Self, sep: &str) -> String {
         unsafe {
             String::from_utf8_unchecked( join_generic_copy(slice, sep.as_bytes()) )
         }