Leopard2A5
Leopard2A5

Reputation: 55

Handling collections of std::borrow::Cow

I have this setup:

use std::borrow::Cow;

fn encode_text<'a, T: Into<Cow<'a, str>>>(text: T) {}

fn encode_texts<'a, T: Into<Cow<'a, str>>>(texts: &[T]) {
    for text in texts {
        encode_text(text);
    }
}

fn main() {
    encode_texts(&vec!["foo", "bar"]);
}

The error that I get is:

error[E0277]: the trait bound `std::borrow::Cow<'_, str>: std::convert::From<&T>` is not satisfied
 --> src/main.rs:7:9
  |
7 |         encode_text(text);
  |         ^^^^^^^^^^^ the trait `std::convert::From<&T>` is not implemented for `std::borrow::Cow<'_, str>`
  |
  = help: consider adding a `where std::borrow::Cow<'_, str>: std::convert::From<&T>` bound
  = note: required because of the requirements on the impl of `std::convert::Into<std::borrow::Cow<'_, str>>` for `&T`
note: required by `encode_text`
 --> src/main.rs:3:1
  |
3 | fn encode_text<'a, T: Into<Cow<'a, str>>>(text: T) {}
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This makes sense as a T is a valid param to encode_text and &T is not, but somehow I fail to get this to work. I can't call encode_text(*text) because I can't move it out of borrowed content (the texts param of encode_texts).

I haven't added a where std::borrow::Cow<'_, str>: std::convert::From<&T> because it basically states that I want the standard library type Cow to implement From<&T>. If that's not already the case, then my adding the constraint won't help.

I am stuck and I can't find any resources on how to work with Cows in collections or slices.

Upvotes: 0

Views: 693

Answers (1)

Shepmaster
Shepmaster

Reputation: 431489

Your code cannot be made generic because it doesn't work in the non-generic case to start with. Substitute the concrete type in:

use std::borrow::Cow;

fn encode_text<'a, T: Into<Cow<'a, str>>>(text: T) {}

fn encode_texts(texts: &[&'static str]) {
    for text in texts {
        encode_text(text);
    }
}

fn main() {
    encode_texts(&["foo", "bar"]);
}
error[E0277]: the trait bound `std::borrow::Cow<'_, str>: std::convert::From<&&str>` is not satisfied
 --> src/main.rs:7:9
  |
7 |         encode_text(text);
  |         ^^^^^^^^^^^ the trait `std::convert::From<&&str>` is not implemented for `std::borrow::Cow<'_, str>`
  |
  = help: the following implementations were found:
            <std::borrow::Cow<'a, std::path::Path> as std::convert::From<&'a std::path::Path>>
            <std::borrow::Cow<'a, std::path::Path> as std::convert::From<std::path::PathBuf>>
            <std::borrow::Cow<'a, str> as std::convert::From<&'a str>>
            <std::borrow::Cow<'a, [T]> as std::convert::From<&'a [T]>>
          and 2 others
  = note: required because of the requirements on the impl of `std::convert::Into<std::borrow::Cow<'_, str>>` for `&&str`
note: required by `encode_text`
 --> src/main.rs:3:1
  |
3 | fn encode_text<'a, T: Into<Cow<'a, str>>>(text: T) {}
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Cow has a limited set of From implementations:

impl<'a> From<&'a str> for Cow<'a, str> {}

impl<'a, T> From<&'a [T]> for Cow<'a, [T]>
where
    T: Clone
{}

impl<'a, T> From<Vec<T>> for Cow<'a, [T]>
where
    T: Clone,
{}

impl<'a> From<String> for Cow<'a, str> {}

Converting from a &&str is not in the list. This makes some amount of sense as dereferencing one level from &&str would give you &str, which wouldn't be useful in a Cow.

Instead, I'd implement the code as taking any iterator where the value can be converted to a Cow. You then need to adapt the slice before passing it in:

use std::borrow::Cow;

fn encode_text<'a, T>(_text: T)
where
    T: Into<Cow<'a, str>>,
{}

fn encode_texts<'a, I>(texts: I)
where
    I: IntoIterator,
    I::Item: Into<Cow<'a, str>>,
{
    for text in texts {
        encode_text(text);
    }
}

fn main() {
    encode_texts(["foo", "bar"].iter().cloned());
}

Upvotes: 3

Related Questions