fn get_data<'de, Lt: LastfmType<'de>>(url : Url) -> Result<Lt,lastfm_parse_rs::error::Error> {
let mut data = Vec::new();
/* fill data */
let result : Result<Lt, lastfm_parse_rs::error::Error> = from_json_slice(&data);
result
}
fn main() {
let r = get_data::<artist::GetInfo>("url");
}
the error:
30 | let result : Result<Lt, lastfm_parse_rs::error::Error> = from_json_slice(&data);
| ----------------^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `data` is borrowed for `'de`
31 | result
32 | }
| - `data` dropped here while still borrowed
The 'de lifetime is the lifetime of the data the value is parsed from, and it allows avoiding copying things from the original string when possible. In this case since you're throwing away the data vector before you finish using the item, you shouldn't be using 'de like that. Typically the solution is to use DeserializeOwned, but if you don't have access to how LastfmType interacts with deserialize, you can use LastfmType<'static> to only allow deserialization that copies the data into the resulting value.
fn get_data<Lt: for<'de> LastfmType<'de>>(url : Url) -> Result<Lt,lastfm_parse_rs::error::Error>
Like this?
Then I get the following error:
50 | match get_data::artist::GetInfo(url) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait for<'de> lastfm_parse_rs::LastfmType<'de> is not implemented for lastfm_parse_rs::artist::GetInfo<'_>
Given that artist::GetInfo<'_> does not implement DeserializeOwned == for<'de> Deserialize<'de>, you will need to keep the bytes you deserialize from (i.e., your data vector) in scope: data must not be dropped before you are done using GetInfo (your program thus fails because data is dropped when the get_data function returns, which is right before the caller tries to get a GetInfo that refers / points to that (now stale) data.
There are multiple ways to design your code to keep data alive.
Making data exist at the caller scope
type Result<T> = ::std::result::Result<T, ::lastfm_parse_rs::error::Error>;
fn get_data<'de, Lt: LastfmType<'de>>(
url: Url,
data: &'de mut Vec<u8>
) -> Result<Lt>
{
data.clear();
/* fill data */
from_json_slice(&data)
}
fn main ()
{
let mut data = Vec::new();
let artist_info: artist::GetInfo = get_data("url", &mut data).unwrap();
}
This should work fine, but then there is the whole "the caller must provide this extra data parameter that they need to have previously set up, and which will be unusable for as long as we are using / moving the obtained artist_info is around".
The fact that data cannot be used can be alleviated using shadowing:
let ref mut artist_info = Vec::new();
let artist_info = get_data("url", artist_info).unwrap();
But there is another pattern that makes this easier to use from a caller perspective: CPS, i.e., using a callback rather than a let binding to obtain the artist_info value.
Using a callback
This is how using a callback-based API looks like:
fn main ()
{
with_artist_info("url", |r: Result<artist::GetInfo<'_>>| {
let artist_info = r.unwrap();
// use artist_info here
});
}
And this is how you implement it:
type Result<T> = ::std::result::Result<T, ::lastfm_parse_rs::error::Error>;
fn get_data<'de, Lt: LastfmType<'de>>(
url: Url,
data: &'de mut Vec<u8>
) -> Result<Lt>
{
data.clear();
/* fill data */
from_json_slice(&data)
}
fn with_artist_info<R, F> (
url: Url,
f: F,
) -> R
where
F : FnOnce(Result<artist::GetInfo<'_>>) -> R,
{
let ref mut data = Vec::new();
f(get_data(url, data))
}
(It is annoying to have to split a specific function for each specific Lt type, but in order to avoid that we'd need GAT-level hacks, which I have been unable to make function. That is:
To get a generic callback interface, you need to have GATs, to express it nicely. Number 2 looks like chalk could solve it, and number 3 should work, once that gets fixed.
Thanks for all the explaining!
I went with the easy solution (1), but the error remains the same:
error[E0597]: `data` does not live long enough
--> src/main.rs:35:21
|
16 | fn get_data<'de, Lt: LastfmType<'de>>(
| --- lifetime `'de` defined here
...
35 | from_json_slice(&data)
| ----------------^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `data` is borrowed for `'de`
36 | }
| - `data` dropped here while still borrowed