about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSimon Sapin <simon.sapin@exyr.org>2016-10-21 16:51:59 +0200
committerSimon Sapin <simon.sapin@exyr.org>2016-10-21 17:42:29 +0200
commit7e603d4e3b2551608a225e115da4e83559b94761 (patch)
tree9bb200cfcbad55de7f3ed5bc539d96fa7dc103f0
parentda5b6467c33f7f86b4964b08b37726f7611a8f0c (diff)
Implement `From<Cow<str>> for String` and `From<Cow<[T]>> for Vec<T>`.
Motivation: the `selectors` crate is generic over a string type,
in order to support all of `String`, `string_cache::Atom`, and
`gecko_string_cache::Atom`. Multiple trait bounds are used
for the various operations done with these strings.
One of these operations is creating a string (as efficiently as possible,
re-using an existing memory allocation if possible) from `Cow<str>`.

The `std::convert::From` trait seems natural for this, but
the relevant implementation was missing before this PR.
To work around this I’ve added a `FromCowStr` trait in `selectors`,
but with trait coherence that means one of `selectors` or `string_cache`
needs to depend on the other to implement this trait.
Using a trait from `std` would solve this.

The `Vec<T>` implementation is just added for consistency.
I also tried a more general
`impl<'a, O, B: ?Sized + ToOwned<Owned=O>> From<Cow<'a, B>> for O`,
but (the compiler thinks?) it conflicts with `From<T> for T` the impl
(after moving all of `collections::borrow` into `core::borrow`
to work around trait coherence).
-rw-r--r--src/libcollections/string.rs7
-rw-r--r--src/libcollections/vec.rs7
-rw-r--r--src/libcollectionstest/string.rs6
-rw-r--r--src/libcollectionstest/vec.rs8
4 files changed, 28 insertions, 0 deletions
diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs
index 7a61451b900..ce9fec32917 100644
--- a/src/libcollections/string.rs
+++ b/src/libcollections/string.rs
@@ -1860,6 +1860,13 @@ impl<'a> From<&'a str> for String {
     }
 }
 
+#[stable(feature = "string_from_cow_str", since = "1.14.0")]
+impl<'a> From<Cow<'a, str>> for String {
+    fn from(s: Cow<'a, str>) -> String {
+        s.into_owned()
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> From<&'a str> for Cow<'a, str> {
     #[inline]
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index f3d78c20a4d..f7c3e8ea1ed 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -1764,6 +1764,13 @@ impl<'a, T: Clone> From<&'a [T]> for Vec<T> {
     }
 }
 
+#[stable(feature = "vec_from_cow_slice", since = "1.14.0")]
+impl<'a, T> From<Cow<'a, [T]>> for Vec<T> where [T]: ToOwned<Owned=Vec<T>> {
+    fn from(s: Cow<'a, [T]>) -> Vec<T> {
+        s.into_owned()
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> From<&'a str> for Vec<u8> {
     fn from(s: &'a str) -> Vec<u8> {
diff --git a/src/libcollectionstest/string.rs b/src/libcollectionstest/string.rs
index 1652fb5a88d..98de33bdaa8 100644
--- a/src/libcollectionstest/string.rs
+++ b/src/libcollectionstest/string.rs
@@ -36,6 +36,12 @@ fn test_from_str() {
 }
 
 #[test]
+fn test_from_cow_str() {
+    assert_eq!(String::from(Cow::Borrowed("string")), "string");
+    assert_eq!(String::from(Cow::Owned(String::from("string"))), "string");
+}
+
+#[test]
 fn test_unsized_to_string() {
     let s: &str = "abc";
     let _: String = (*s).to_string();
diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs
index 991c456fe74..9a04673d1da 100644
--- a/src/libcollectionstest/vec.rs
+++ b/src/libcollectionstest/vec.rs
@@ -597,6 +597,14 @@ fn test_cow_from() {
     }
 }
 
+#[test]
+fn test_from_cow() {
+    let borrowed: &[_] = &["borrowed", "(slice)"];
+    let owned = vec!["owned", "(vec)"];
+    assert_eq!(Vec::from(Cow::Borrowed(borrowed)), vec!["borrowed", "(slice)"]);
+    assert_eq!(Vec::from(Cow::Owned(owned)), vec!["owned", "(vec)"]);
+}
+
 #[allow(dead_code)]
 fn assert_covariance() {
     fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d }