rust - Lifetimes when Deserializing JSON within a FromForm -
i'm having trouble understanding relationship between lifetimes on code. basically, have rocket api receives x-www-form-urlencoded data, 1 key: json. key contains, intuitively, json value, encoded percent-encoding, of struct message<t>.
(i'm aware suboptimal api design, reverse-engineering work, have no option)
to used request guard from<message<t>>, i'm implementing fromform. that, need implement fromform<'f> message<t> t implements deserialize<'de>. wrote impl signature impl<'f, 'de, t> fromform<'f> message<t> t: deserialize<'de>.
to perform decoding, i:
- get
"json"key of form data; - url-decode value;
- parse json contained in value.
bailing out possible. code doing (explicit type annotations reader's convenience):
fn from_form(items: &mut formitems<'f>, strict: bool) -> result<self, self::error> { // json field let encoded: option<&rawstr> = items.find(|&(k, _)| k.as_str() == "json") .map(|(_, v)| v); if let none = encoded { return err(messageformerror::missingjsonkey); } // decode url-string let decoded: result<string, utf8error> = encoded.unwrap().url_decode(); if let err(e) = decoded { return err(messageformerror::invalidurl(e)); } // parse json let json: string = decoded.unwrap(); serde_json::from_str::<self>(&json) // line 205 .map_err(|e| messageformerror::invalidjson(e)) } a gist demonstrating problem in paste-and-run way (doesn't work on playground since depends on rocket).
as understand:
- the
&rawstrofencodedhas lifetime'f. - a
stringcreated out ofurl_decode, lives until end of function serde_jsontakes&'x str'xnot need coincide'de, , returns value (so lives end of function, , since it's returned, gets moved beyond it)
but seems understanding incorrect:
205 | serde_json::from_str::<self>(&json) | ^^^^ not live long enough 206 | .map_err(|e| messageformerror::invalidjson(e)) 207 | } | - borrowed value lives until here | note: borrowed value must valid lifetime 'f defined on impl @ 184:1... --> src/transport.rs:184:1 | 184 | / impl<'f, t> fromform<'f> message<t> 185 | | t: deserialize<'f> 186 | | { 187 | | type error = messageformerror; ... | 207 | | } 208 | | } | |_^ what getting wrong, , how can return deserialized value properly?
this section of serde website covers deserialize bounds in detail.
there 2 main ways write
deserializetrait bounds, whether on impl block or function or anywhere else.
<'de, t> t: deserialize<'de>this means "t can deserialized some lifetime." caller gets decide lifetime is. typically used when caller provides data being deserialized from, example in function
serde_json::from_str. in case input data must have lifetime'de, example&'de str.
<t> t: deserializeownedthis means "t can deserialized any lifetime." callee gets decide lifetime. because data being deserialized going thrown away before function returns, t must not allowed borrow it. in case data coming url-decoding input, , decoded data thrown away after deserializing t. common use of bound functions deserialize io stream, such
serde_json::from_reader.to more technically,
deserializeownedtrait equivalent higher-rank trait boundfor<'de> deserialize<'de>. differencedeserializeownedmore intuitive read. means t owns data gets deserialized.
replacing t: deserialize<'f> bound t: deserializeowned correctly communicates t not allowed borrow url-decoded data because url-decoded data not outlive t.
Comments
Post a Comment