Borrow checked treat value as borrowed after using `to_owned`

I've got the following code snippet which is part of a bigger function and I have borrow checker complaining for (obviously valid) reason but I don't quite understand why.

 async fn func() -> Result<()> { 
  let mut file_mime_sub_type = None;

  while let Some(item) = payload.try_next().await? {
    let mut field = item;
    let mut content = vec![];
    
    // Field in turn is stream of *Bytes* object
    while let Some(chunk) = field.next().await {
      let chunk = chunk?;
      content.push(chunk);
    }

    let field_name = field.name();
    let content_type = field.content_type().unwrap_or(&mime::TEXT_PLAIN).to_owned();
    let mime_subtype = content_type.subtype();
    let content = content.concat();

    if mime_subtype.eq(&mime::TEXT_PLAIN.subtype()) {
      
    } else if is_supported_media_type(mime_subtype) {
      file_mime_sub_type = Some(mime_subtype);
    }
  }

  if let Some(mime_subtype) = file_mime_sub_type {
    // do something
  }
  ...
}

The error I see is:

   |
63 |     let content_type = field.content_type().unwrap_or(&mime::TEXT_PLAIN).to_owned();
   |         ------------ binding `content_type` declared here
64 |     let mime_subtype = content_type.subtype();
   |                                        ^^^^^^^^^^^^ borrowed value does not live long enough
...
79 |   }
   |   - `content_type` dropped here while still borrowed
...
93 |   if let Some(mime_subtype) = file_mime_sub_type {
   |                                                    ------------------ borrow later used here

I'm struggling to understand why content_type is a borrowed value. I did use to_owned and then assigned it to file_mime_sub_type. Doesn't this move the owned value to that variable?

Below I add the fn signature of a couple of function. Hopefully that helps.

pub fn content_type(&self) -> Option<&mime::Mime> {
    self.ct.as_ref()
}


pub fn subtype(&self) -> Name {}
``

The content_type is indeed owned. But the Name returned by calling content_type.subtype() borrows from the content_type. You don't assign the owned content_type to file_mime_sub_type thus transferring ownership, but the borrowing mime_subtype. That is causing the lifetime error. To fix this I would suggest assigning file_mime_sub_type[1] to content_type instead of mime_subtype. You can always retrieve the subtype when you need it and there is no convenient way to convert a Name<'a> to Name<'static> and make Name own the underlying data.


  1. Renaming the variable to file_mime_type instead I guess. ↩ī¸Ž

Thanks for the prompt reply mate, much appreciated. However, if Name is copy so shouldn't it simply copy it?

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]

pub struct Name<'a> {}

Also why wouldn't the following work either (fails with the same exact error)

let content_type = field.content_type().unwrap_or(&mime::TEXT_PLAIN).to_owned();
let mime_subtype = content_type.subtype().to_owned();

.to_owned() for a type that implements Clone is simply a .clone(). For Name this means you're simply copying the reference it contains (but not the referenced value!). Thus the value you get is still borrowing the same thing.

2 Likes

The Copy implementation of Name just copies the reference inside of Name to the underlying string slice, it doesn't copy the content of the str and makes it owned data.

2 Likes

Oh ok that does make sense indeed. Thanks buddy :slight_smile: Basically, Name still has the lifetime of content_type. Got it now.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.