0

I'm a newbie that is trying to make a simple email parser, but I'm facing the usual newcomers' problems with the borrowing stuff in Rust.

I'm trying to make compile the following code that wants to parse a json response with reqwest into my struct MessagesListResponse and then I just want to return a Vec of strings only containing the mapped ids:

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct MessagesListResponse{
    messages: Vec<MessageId>
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct MessageId{
    id: String,
    thread_id: String
}


#[async_trait]
impl MessageGetter for GmailMessageGetter{

    async fn get_message_ids(&self) -> Vec<String> {
        

        let url = "https://gmail.googleapis.com/gmail/v1/users/me/messages?q=from%3Awebank%40webank.it%20subject%3Aautorizzato%20pagamento".to_owned();
        
        dbg!(&url);
        let response = &self.client.get(url).send().await.unwrap();

        _ = &response.error_for_status_ref().unwrap();
        let msg_list_response = response.json::<MessagesListResponse>().await.unwrap();
        msg_list_response.messages.into_iter().map(|message_id| message_id.id).collect()
    }
    
}

unfortunately I keep getting the error

cannot move out of `*response` which is behind a shared reference

at the line

let msg_list_response = response.json::<MessagesListResponse>().await.unwrap();

but I'm not understanding how to make it work because the response type reqwest::async_impl::response is not cloneable and the response.json method consumes the response. Can I get some help? Thanks a lot.

exrezzo
  • 497
  • 1
  • 5
  • 24
  • Why is the fact that the [`Response::json`](https://docs.rs/reqwest/latest/reqwest/struct.Response.html#method.json) method consumes the response a problem? In your example, it is not. – Jonas Fassbender May 29 '23 at 12:08
  • 1
    `response` has type `&reqwest::async_impl::response` because *you* borrowed it at the line `let response = &...`. Try removing the ampersand. – jthulhu May 29 '23 at 12:08

1 Answers1

1

There's an unnecessary reference here.

let response = &client.get(url).send().await.unwrap();

Remove it, and your code works.

let response = client.get(url).send().await.unwrap();

The assignment and reference here are unnecessary and do nothing.

_ = &response.error_for_status_ref().unwrap();

You can remove them.

response.error_for_status_ref().unwrap();

The .to_owned() at the end of the URL is also unnecessary. You should remove it.

Those are the only issues, but another way to write this is as one big method chain.

client
    .get(url)
    .send()
    .await
    .unwrap()
    .error_for_status()
    .unwrap()
    .json::<MessagesListResponse>()
    .await
    .unwrap()
    .messages
    .into_iter()
    .map(|message_id| message_id.id)
    .collect()
drewtato
  • 6,783
  • 1
  • 12
  • 17
  • thank you @drewtato, now it works. Removing the ampersand from &self.client.get did the job; this makes understand how less I'm understanding Rust . I was trying to understand why the get method accepts &self as first parameter but by passing it just self.client still works... – exrezzo May 31 '23 at 08:33
  • 1
    @exrezzo ahh, I see what you were going for. So there's two things. `&` has less precedence than `.`, so `&client.get(url)` is the same as `&(client.get(url))`, not `(&client).get(url)`. And `.` will automatically remove or add references in order to find a method, so you don't need to add them manually. – drewtato May 31 '23 at 20:30