Correct trait bounds for input that needs to convert into [u8] then Cow<'a, [u8]>

How do I convey in Trait Bounds that after having the ability to take an AsRef<[u8]> of an input parameter I then want to be able to put it Into a Cow<[u8]?

Playground link

use std::borrow::Cow;
use std::marker::PhantomData;

pub struct Label<T> {
   unused: PhantomData<T>,
   fragment: Vec<u8>,
}

impl<T> Label<T> {
    pub fn new() -> Self {
       Label { unused: PhantomData, fragment: vec![]}    
    }
    
    pub fn insert(&mut self, item: T) 
    where T: AsRef<[u8]>      <---------------------
   {
      let cow: Cow<[u8]> = item.as_ref().into();
      println!("I have a cow! {:?}", cow);
      // more processing ....
      self.fragment = cow.into_owned()
    }
}


fn main() {
    println!("Hello, world!");
    let mut l = Label::new();
    l.insert("Holy Crickets");
}

I have tried

where T: AsRef<U>,
           U: Into<Cow<'a, [u8]>>

and have gotten an error like:

^^^^ the trait `From<&[U]>` is not implemented for `Cow<'_, [u8]>`

Its not totally clear to me what I'm really doing in the nested trait bounds so to speak that I have tried just sort of a vague it "looks right sort of thing" and would appreciate some help.

Thank you kindly -- BTW, this is my first post to the Rust language forum!

The playground you linked compiles?

Yes

What is your question?

What is the proper way to add the Into<Cow<[u8]> trait bound in addition to the AsRef trait bound that already compiles?

The code that doesn't compile is here: Rust Playground


Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `Cow<'_, [u8]>: From<&U>` is not satisfied
  --> src/main.rs:18:42
   |
18 |       let cow: Cow<[u8]> = item.as_ref().into();
   |                                          ^^^^ the trait `From<&U>` is not implemented for `Cow<'_, [u8]>`
   |
   = note: required because of the requirements on the impl of `Into<Cow<'_, [u8]>>` for `&U`
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
   |
9  | impl<T> Label<T> where Cow<'_, [u8]>: From<&U> {
   |                  +++++++++++++++++++++++++++++

error[E0283]: type annotations needed
  --> src/main.rs:29:7
   |
29 |     l.insert("Holy Crickets");
   |       ^^^^^^ cannot infer type for type parameter `U` declared on the associated function `insert`
   |
   = note: cannot satisfy `_: Into<Cow<'_, [u8]>>`
note: required by a bound in `Label::<T>::insert`
  --> src/main.rs:16:15
   |
14 |     pub fn insert<'a, U>(&mut self, item: T) 
   |            ------ required by a bound in this
15 |     where T: AsRef<U>,
16 |            U: Into<Cow<'a, [u8]>>
   |               ^^^^^^^^^^^^^^^^^^^ required by this bound in `Label::<T>::insert`
help: consider specifying the type arguments in the function call
   |
29 |     l.insert::<'a, U>("Holy Crickets");
   |             +++++++++

error[E0283]: type annotations needed
  --> src/main.rs:29:7
   |
29 |     l.insert("Holy Crickets");
   |       ^^^^^^ cannot infer type for type parameter `U`
   |
   = note: multiple `impl`s satisfying `str: ~const AsRef<_>` found in the following crates: `core`, `std`:
           - impl AsRef<OsStr> for str;
           - impl AsRef<Path> for str;
           - impl AsRef<[u8]> for str;
           - impl AsRef<str> for str;
   = note: required because of the requirements on the impl of `AsRef<_>` for `&str`
note: required by a bound in `Label::<T>::insert`
  --> src/main.rs:15:14
   |
14 |     pub fn insert<'a, U>(&mut self, item: T) 
   |            ------ required by a bound in this
15 |     where T: AsRef<U>,
   |              ^^^^^^^^ required by this bound in `Label::<T>::insert`

Some errors have detailed explanations: E0277, E0283.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `playground` due to 3 previous errors

Perhaps you are looking for this?

pub fn insert<U>(&mut self, item: T)
where
    T: AsRef<U>,
    for<'a> &'a U: Into<Cow<'a, [u8]>>,
{
    let cow: Cow<[u8]> = item.as_ref().into();
    println!("I have a cow! {:?}", cow);
    // more processing ....
    self.fragment = cow.into_owned()
}

I might be however I am not able to get it to compile and am not quite the advanced Rust user yet so I don't fully understand what this means (unless it relaxes the lifetime restrictions for a ref to U which its not clear to me why a &U would be helpful :wink: )

I'm assuming this desire of mine is a somewhat of a common thing? Or is this a rare use case? Just want to signal that I may mutate some form of the original value passed in by the user

I had originally thought of using something like a where I: <ToOwned<Owned=Vec> but its not guarenteed that I will always take the to_owned() version. Plus I want to be able to take in a String/&str which AsRef converts to a [u8] quite easily.

I mean, if you want to mutate the value you got from the user, then take a mutable reference.

If you want to mutate a copy of the user's value, then there's no need to signal that. You're mutating a copy that the caller doesn't know about. (This is what happens when you use Cow — it's called copy-on-write for a reason.)

Cool, thanks for trying to provide clarification on the signaling and intention here.

Just for the technical merit of getting the code to compile how would I make the trait bound you suggested compile?

You have to decide what U should be.

fn main() {
    println!("Hello, world!");
    let mut l = Label::new();
    l.insert::<[u8]>("Holy Crickets");
}

(also requires adding ?Sized)

    pub fn insert<U>(&mut self, item: T)
    where
        T: AsRef<U>,
        for<'a> &'a U: Into<Cow<'a, [u8]>>,
        U: ?Sized,
    {

This works thank you so much (and thanks for posting late I know its late in the EU).

Could you walk through what this means? I understand the ?Sized part because the U we pass in isn't technically sized but we know it will be since it will eventually be a &U once in the Cow.

What does the for<'a> &'a U syntax mean?

The U: ?Sized bound actually disables a bound that Rust adds by default. The U: Sized bound is always added to all generic parameters because when a type is not sized, it can only be used if its behind a reference or pointer of some kind. If it wasn't default, most of generics functions would need to specify it.

Note that U: ?Sized doesn't mean that U is not sized. It means that U might or might not be sized. Hence the question mark rather than a "not".

As for the for<'a> syntax, it short-hand for the following infinite list of trait bounds:

  • &'lifetime1 U: Into<Cow<'lifetime1, [u8]>>,
  • &'lifetime2 U: Into<Cow<'lifetime2, [u8]>>,
  • &'lifetime3 U: Into<Cow<'lifetime3, [u8]>>,
  • ...
  • &'static U: Into<Cow<'static, [u8]>>,

where the list is infinite and goes through every possible lifetime.

Thank you -- and yes Sized? means may or may not be Sized

So let me push further: why is it necessary to provide the for<'a> syntax which gives -- the infinite list of lifetime trait bounds? Isn't this somewhat overkill? What is the compiler trying to rule out by such thoroughness?

At the end of the day does this allow me to pass in a &'static str which gets turned into a AsRef<[u8]> which then allows it to be put into a Cow<[u8]> alongside another value e.g. a Vector (on another invocation) that say does not have such a long lifetime?

(If this is so, why not just iterate for two lifetimes a non-static lifetime and a 'static lifetime)

First, one thing to be aware of is that lifetimes are the duration in which something is borrowed — not the duration in which a value exists.

The lifetime you really want in the for<'a> bound is the duration in which you are borrowing the local item variable inside the insert call. However, there's no way to talk about that lifetime in particular, so the only way to specify the bound is to require it for all lifetimes.

Note that this is not an especially restrictive requirement. The only possibilities is that it implements the trait only for 'static, or for all possible lifetimes. Only 'static is not enough for our purposes, so we use the other option.

Thank you so much.

So the 'a lifetime which as you mention as

the duration in which you are borrowing the local item variable inside the insert call

Is this the lifetime as a result of the AsRef trait applied on the item variable? Just trying to connect the dots between the trait bounds

Yeah, the AsRef trait has this signature: for<'a> &'a T -> &'a U. Thus, to call the function you must first create a &'a T, and creating such a reference borrows the T for the duration of 'a.

1 Like

Very cool!

Finally another technical ask, is there a way to get around the type annotation of insert e.g.

    l.insert::<[u8]>("Holy Crickets");

by using say (shooting off the top of my head) an associated type parameter on the impl Label such as
type something like

impl<T> Label<T> {
    type Item = [u8]

    pub fn insert<Item>(&mut self, item: T)....

If you always want to use the [u8] type, then replacing every instance of U with [u8] should work.

pub fn insert(&mut self, item: T)
where
    T: AsRef<[u8]>,
    for<'a> &'a [u8]: Into<Cow<'a, [u8]>>,
{
    let cow: Cow<[u8]> = item.as_ref().into();
    println!("I have a cow! {:?}", cow);
    // more processing ....
    self.fragment = cow.into_owned()
}

The for<'a> bound can then be removed because it is always true.

Thanks again, however I don't fully understand why removing the for<'a> bound would work since we are just swapping in a concrete type of [u8] for type variable U but haven't eliminated the original ambiguity over lifetimes that for<'a> was meant to address after the AsRef trait was applied on item:

The for<'a> bound can then be removed because it is always true.

Upon trying this shorter trait bound

    &'a [u8]: Into<Cow<'a, [u8]>>,

( Rust Playground )
I get the error:

   Compiling playground v0.0.1 (/playground)
error[E0261]: use of undeclared lifetime name `'a`
  --> src/main.rs:16:12
   |
16 |           &'a [u8]: Into<Cow<'a, [u8]>>,
   |            ^^ undeclared lifetime

How to fix the error?

It does indeed work with the bound left in - so thank you!

for<'a> &'a [u8]: Into<Cow<'a, [u8]>>,