Функция локальной переменной не живет достаточно долго
Я пытаюсь написать обертку вокруг serde_json & Rocket's FromData
чтобы строго набрать часть JSON, которым я обмениваюсь с сервером.
Я не могу скомпилировать следующий код:
extern crate serde_json;
extern crate rocket;
extern crate serde;
use serde::ser::Error;
use serde_json::Value;
use rocket::data::DataStream;
use rocket::outcome::IntoOutcome;
use std::io::Read;
static NULL: Value = serde_json::Value::Null;
pub struct ResponseJSON<'v> {
success: bool,
http_code: u16,
data: &'v serde_json::Value,
}
impl<'v> ResponseJSON<'v> {
pub fn ok() -> ResponseJSON<'v> {
ResponseJSON {
success: true,
http_code: 200,
data: &NULL,
}
}
pub fn http_code(mut self, code: u16) -> ResponseJSON<'v> {
self.http_code = code;
self
}
pub fn data(mut self, ref_data: &'v serde_json::Value) -> ResponseJSON<'v> {
self.data = ref_data;
self
}
pub fn from_serde_value(json: &'v serde_json::Value) -> ResponseJSON<'v> {
if !json["success"].is_null() {
ResponseJSON::ok()
.http_code(json["http_code"].as_u64().unwrap() as u16)
.data(json.get("data").unwrap_or(&NULL))
} else {
ResponseJSON::ok()
.data(json.pointer("").unwrap())
}
}
}
impl<'v> rocket::data::FromData for ResponseJSON<'v> {
type Error = serde_json::Error;
fn from_data(request: &rocket::Request, data: rocket::Data) -> rocket::data::Outcome<Self, serde_json::Error> {
if !request.content_type().map_or(false, |ct| ct.is_json()) {
println!("Content-Type is not JSON.");
return rocket::Outcome::Forward(data);
}
let data_from_reader = data.open().take(1<<20);
let value = serde_json::from_reader(data_from_reader);
let unwraped_value : Value = if value.is_ok() { value.unwrap() } else { Value::Null };
if !unwraped_value.is_null() {
Ok(ResponseJSON::from_serde_value(&unwraped_value)).into_outcome()
} else {
Err(serde_json::Error::custom("Unable to create JSON from reader")).into_outcome()
}
}
}
fn main() {
println!("it runs!");
}
Ошибка компилятора:
Compiling tests v0.1.0 (file:///Users/bgbahoue/Projects.nosync/tests)
error: `unwraped_value` does not live long enough
--> src/main.rs:64:48
|
64 | Ok(ResponseJSON::from_serde_value(&unwraped_value)).into_outcome()
| ^^^^^^^^^^^^^^ does not live long enough
...
68 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'v as defined on the body at 53:114...
--> src/main.rs:53:115
|
53 | fn from_data(request: &rocket::Request, data: rocket::Data) -> rocket::data::Outcome<Self, serde_json::Error> {
| ___________________________________________________________________________________________________________________^
54 | | if !request.content_type().map_or(false, |ct| ct.is_json()) {
55 | | println!("Content-Type is not JSON.");
56 | | return rocket::Outcome::Forward(data);
... |
67 | | }
68 | | }
| |_____^
error: aborting due to previous error
поскольку data_from_reader
, value
а также unwraped_value
родом из data
Я думал, что компилятор может сделать вывод, что у него одинаковое время жизни, но, видимо, это не так. Можно ли как-то заявить об этом или сделать что-то, что сработает в таком случае?
serde_json::from_reader
:
pub fn from_reader<R, T>(rdr: R) -> Result<T>
where
R: Read,
T: DeserializeOwned,
rocket::data::Data::open
:
fn open(self) -> DataStream
rocket::data::DataStream::take
:
fn take(self, limit: u64) -> Take<Self>
1 ответ
Согласно приведенному выше комментарию @LukasKalbertodt, он работает, когда ResponseJSON владеет serde_json::Value
Пересмотренный код (вставлен как есть, хотя есть и лучшие способы связать некоторые части кода)
#![allow(dead_code)]
extern crate serde_json;
extern crate rocket;
extern crate serde;
use serde::ser::Error;
use serde_json::Value;
use rocket::outcome::IntoOutcome;
use std::io::Read;
static NULL: Value = serde_json::Value::Null;
pub struct ResponseJSON { // <-- changed to remove the lifetime parameter
success: bool,
http_code: u16,
data: serde_json::Value, // <- changed to remove the '&'
}
impl ResponseJSON {
pub fn ok() -> ResponseJSON {
ResponseJSON {
success: true,
http_code: 200,
data: Value::Null,
}
}
pub fn http_code(mut self, code: u16) -> ResponseJSON {
self.http_code = code;
self
}
pub fn data(mut self, data: serde_json::Value) -> ResponseJSON { // <- changed to remove the '&'
self.data = data;
self
}
pub fn from_serde_value(json: serde_json::Value) -> ResponseJSON { // <- changed to remove the reference & lifetime parameter
if !json["success"].is_null() {
ResponseJSON::ok()
.http_code(json["http_code"].as_u64().unwrap() as u16)
.data(json.get("data").unwrap_or(&NULL).clone())
} else {
ResponseJSON::ok()
.data(json.pointer("").unwrap().clone())
}
}
}
impl rocket::data::FromData for ResponseJSON {
type Error = serde_json::Error;
fn from_data(request: &rocket::Request, data: rocket::Data) -> rocket::data::Outcome<Self, serde_json::Error> {
if !request.content_type().map_or(false, |ct| ct.is_json()) {
println!("Content-Type is not JSON.");
return rocket::Outcome::Forward(data);
}
let data_from_reader = data.open().take(1<<20);
let value = serde_json::from_reader(data_from_reader);
let unwraped_value : Value = if value.is_ok() { value.unwrap() } else { Value::Null };
if !unwraped_value.is_null() {
Ok(ResponseJSON::from_serde_value(unwraped_value)).into_outcome() // <- changed to remove the '&' in front of `unwraped_value`
} else {
Err(serde_json::Error::custom("Unable to create JSON from reader")).into_outcome()
}
}
}
fn main() {
println!("it compiles & runs");
}
cargo run
выход
Compiling tests v0.1.0 (file:///Users/bgbahoue/Projects.nosync/tests)
Finished dev [unoptimized + debuginfo] target(s) in 1.28 secs
Running `target/debug/tests`
it compiles & runs
Я полагаю, что в этом случае владение (время жизни?) Входного параметра data
передается data_from_reader
в value
в unwraped_value
на ответ ResponseJSON на возвращаемый rocket::data::Outcome
; так что вроде нормально.
Что касается ссылок, temp ResponseJSON не пережил конец функции, поскольку он пережил serde_json::Value
из которого он был создан т.е. unwraped_value
время жизни, т.е. конец функции; отсюда проблема с компилятором.
Не уверен на 100% в моем объяснении, хотя, хотел бы ваши мысли об этом