Question about "returns a value referencing data owned by the current function"

Hi everyone,

I am relatively new in Rust, and I try to deserialize XML payload return by HTTP request using serde. XML is quite completed since there are JSON inside. I have already deserialized it by serde_json and quick-xml.

However, I want to return the deserialized struct by http request caller, wrapped it into anyhow Result. There is my code.

    pub async fn login(&self, personal_data: &PersonalDataCore<'_>) -> Result<PersonalDataCore> {
        let password = personal_data.hashed_password.to_string();
        let data = ; // json payload of HTTP request.

        let result = self.request(data.to_string()).await?; // HTTP request using reqwest
        let response: APIXMLResponse = quick_xml::de::from_str(&result)?; // first level of deserialization
        let response: APIJSONResponse = serde_json::from_str(&response.value)?;  // second level of deserialization
       // destructure the real struct inside
        match response.data.result_data {
            ResultData::PersonalDataContainer { result } => Ok(result),
            _ => Err(anyhow!("failed to deserialze result data")),
        }
        .and_then(|p_data| match p_data.personal_data.data_table.row {
            DataRow::PersonalDataCell(core) => Ok(core),
            _ => Err(anyhow!("failed to deserialze result_data")),
        })

There are error coming from compiler.

error[E0515]: cannot return value referencing local data `response.value`
  --> src/client.rs:69:9
   |
68 |           let response: APIJSONResponse = serde_json::from_str(&response.value)?;
   |                                                                --------------- `response.value` is borrowed here
69 | /         match response.data.result_data {
70 | |             ResultData::PersonalDataContainer { result } => Ok(result),
71 | |             _ => Err(anyhow!("failed to deserialze result data")),
72 | |         }
...  |
75 | |             _ => Err(anyhow!("failed to deserialze result_data")),
76 | |         })
   | |__________^ returns a value referencing data owned by the current function


I have known the reason why this error comes out, but how do I fix this case?

Thank you for advance.

Updated:
I noticed that there is post at [here]( Zero-copy Deserializing with ArcRef and Serde - help - The Rust Programming Language Forum (rust-lang.org)), and I'll try it.

Thanks to Zero-copy Deserializing with ArcRef and Serde - help - The Rust Programming Language Forum (rust-lang.org), it turns out I solve it by myself.

I move struct deserialization out of login method, and it just returns Result<String> type.

    pub async fn login(&self, personal_data: &PersonalDataCore<'_>) -> Result<String> {
        let data = ; // json payload of HTTP request.

        Ok(self.request(data.to_string()).await?)
    }

Both deserialization for APIJSONResponse and APIXMLResponse move into their own implementation like this.

impl APIXMLResponse<'_> {
    pub fn deserialize<'a>(result: &'a str) -> Result<APIXMLResponse<'a>> {
        Ok(quick_xml::de::from_str(result)?)
    }
}

impl PersonalDataCore<'_> {
    pub fn deserialize<'a>(xml_response: &'a APIXMLResponse) -> Result<PersonalDataCore<'a>> {
        let response: APIJSONResponse = serde_json::from_str(&xml_response.value)?;
        match response.data.result_data {
            ResultData::PersonalDataContainer { result } => Ok(result),
            _ => Err(anyhow!("failed to deserialze result data")),
        }
        .and_then(|p_data| match p_data.personal_data.data_table.row {
            DataRow::PersonalDataCell(core) => Ok(core),
            _ => Err(anyhow!("failed to deserialze result_data")),
        })
    }
}

In main function,

async fn main() {
    let mut personal_data = PersonalDataCore::new(XXX);
    let client = CourtsClient::new();
    let result = client.login(&personal_data).await.unwrap();
    let xml_response = APIXMLResponse::deserialize(&result).unwrap();
    let personal_data = PersonalDataCore::deserialize(&xml_response).unwrap();
    println!("{:?}", personal_data);
}

It really takes me LOTS of time to figure out that we could not put lifetime 'a into returned type Self. ,so I return PersonalDataCore<'a> for deserialize method and could use lifetime in argument to tell compiler.

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.