Cow internal conversion

Hi all,

I have a struct containing a reference to [u8] that I want to keep as is, or sometimes to convert it to a Vec<u8> to escape the lifetime.

I think the best way is to use Cow<'a, [u8]>.

I'd like to convert the Borrowed variant to the Owned variant internally, without resorting to to_mut() or into_owned() because they don't return Self. The solution is came up with is to define a convert() method like this:

struct Label<'a>(Cow<'a, [u8]>);

impl<'a> Label<'a> {
    pub fn convert(&mut self) {
        self.0 = Cow::from(self.0.to_vec())
    }
}

Any more elegant solution ?

Thanks a lot for your hints :slight_smile:

If your reason for converting to Vec<u8> is to "escape the lifetime", this doesn't help, as the Label instance that you call convert() on remains associated with 'a. In order to get rid of 'a, you need to create a new Label instance with a 'static lifetime that contains the Vec-in-Cow:

impl<'a> Label<'a> {
    pub fn convert(&self) -> Label<'static> {
        Label(Cow::from(self.0.to_vec()))
    }
}
4 Likes

Thanks for your solution, I'm not very familiar with the 'static lifetime, but it seems promising :wink:

For the 'static version, I'd make it take ownership and use into_owned...

impl<'a> Label<'a> {
    pub fn convert(self) -> Label<'static> {
        Label(Cow::from(self.0.into_owned()))
    }
}

...as the &self version duplicates the data once, unconditionally, whereas this one doesn't duplicate the data if it's already the owned variant.

And also derive Clone for Label<'_>; then if you can't give up ownership to call this version, you can instead

let unbound = label.clone().convert();

to regain the ability of duplicating the data once, unconditionally.


This comes up once in awhile. I wonder if Cow<'a, B> itself should have a

/// Returns a `Cow<'b, B>` with any lifetime that is valid for the
/// owned variant `B`.  In particular if `B: 'static`, this can be
/// used to convert a `Cow<'_, B>` with a short or arbitrary lifetime
/// into a `Cow<'static, B>`.
///
/// Clones the data if it's not already owned.
///
/// ```
/// fn example(cow: Cow<'_, str>) {
///     let cow: Cow<'static, str> = Cow::with_lifetime(cow);
/// }
/// ```
fn with_lifetime<'b>(this: Self) -> Cow<'b, B> where B: 'b {
    Cow::Owned(this.into_owned())
}

(with a better name).

5 Likes

This case is special and a bit unusual, because lifetimes apply only to references and types that can hold a reference, but don't apply at all to self-contained owning types like Vec.

So in this case with a Vec inside, you can give this type any lifetime annotation you want, because the Vec is not restricted by it, and there's no temporary reference in the Cow anymore either.

'static is a special case of maximally long lifetime, which makes this type compatible with every lifetime bound.

2 Likes

Thanks for your comment.

Is it so unusual to perform such an internal conversion from Borrowed to Owned, such that no convenient method is defined in std ?

Thanks for your suggestion :slight_smile:

You can (ab)use Cow::to_mut to guarantee that a Cow is Cow::Owned; the usual use case for this sort of conversion is when you're about to mutate the contained data.

Just discard the return value, as in this Rust Playground showing Cow::to_mut making the Cow go from Cow::Borrowed(_) to Cow::Owned(_).

However it's still true that...

2 Likes