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
&rawstr
ofencoded
has lifetime'f
. - a
string
created out ofurl_decode
, lives until end of function serde_json
takes&'x str
'x
not 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
deserialize
trait 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: deserializeowned
this 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,
deserializeowned
trait equivalent higher-rank trait boundfor<'de> deserialize<'de>
. differencedeserializeowned
more 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