3

我正在尝试围绕 serde_json 和 Rocket 编写一个包装器,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, valueand unwraped_valuecome fromdata我认为编译器可以推断出它具有相同的生命周期,但显然情况并非如此。有什么办法可以说明或做一些在这种情况下可行的事情吗?

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>
4

1 回答 1

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_readerto valuetounwraped_value到 temp ResponseJSON 到返回的rocket::data::Outcome; 所以看起来还可以。

使用引用,临时 ResponseJSON 并没有超过函数结束,因为它超过了serde_json::Value创建它的对象,即unwraped_value生命周期,即函数结束;因此编译器问题。

虽然不是 100% 肯定我的解释,但我会喜欢你的想法

于 2017-05-17T05:59:28.187 回答