Функция локальной переменной не живет достаточно долго

Я пытаюсь написать обертку вокруг 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% в моем объяснении, хотя, хотел бы ваши мысли об этом

Другие вопросы по тегам