一个 implement/derive 可以在没有 #[derive(Serialize)] 的情况下对枚举进行序列化吗?

Can one implement/derive Serialize on an enum without #[derive(Serialize)]?

我正在使用 rust + rocket + diesel (orm) + serde_derive 休息一下 api。目前,如果 diesel 由于某种原因未能插入用户,我正在处理 api 的错误处理。看起来像这样:

pub fn create(user: InsertableUser, connection: &MysqlConnection) -> ApiResponse {
    let result = diesel::insert_into(users::table)
        .values(&InsertableUser::hashed_user(user))
        .execute(connection);
    match result {
        Ok(_) => ApiResponse {
            json: json!({"success": true, "error": null}),
            status: Status::Ok,
        },
        Err(error) => {
            println!("Cannot create the recipe: {:?}", error);
            ApiResponse {
                json: json!({"success": false, "error": error}),
                status: Status::UnprocessableEntity,
            }
        }
    }
}

但是,json: json!({"success": false, "error": error}), 给我这个错误:

the trait bound `diesel::result::Error: user::_IMPL_DESERIALIZE_FOR_User::_serde::Serialize` is not satisfied

the trait `user::_IMPL_DESERIALIZE_FOR_User::_serde::Serialize` is not implemented for `diesel::result::Error`

note: required because of the requirements on the impl of `user::_IMPL_DESERIALIZE_FOR_User::_serde::Serialize` for `&diesel::result::Error`
note: required by `serde_json::value::to_value`rustc(E0277)
<::serde_json::macros::json_internal macros>(123, 27): the trait `user::_IMPL_DESERIALIZE_FOR_User::_serde::Serialize` is not implemented for `diesel::result::Error`

听上去,diesel::result::Error 不是 #[derive(Serialize)],因此不能用 json! 宏序列化。因此,我需要一些方法来制作 diesel::result::Error implement/derive Serialize.

在此先感谢您的帮助。

顺便说一句,ApiResponse 看起来像:

use rocket::http::{ContentType, Status};
use rocket::request::Request;
use rocket::response;
use rocket::response::{Responder, Response};
use rocket_contrib::json::JsonValue;

#[derive(Debug)]
pub struct ApiResponse {
    pub json: JsonValue,
    pub status: Status,
}

impl<'r> Responder<'r> for ApiResponse {
    fn respond_to(self, req: &Request) -> response::Result<'r> {
        Response::build_from(self.json.respond_to(&req).unwrap())
            .status(self.status)
            .header(ContentType::JSON)
            .ok()
    }
}

Serde 提供了一种为外部 crate 导出序列化实现的解决方法 - 请参阅其文档中的 Derive for remote crates 部分。

您必须定义一个与您尝试序列化的枚举具有相同定义的枚举(在您的情况下为 diesel::result::Error),然后将其识别为您尝试序列化的类型的一种代理序列化,像这样:

#[derive(Serialize, Deserialize)]
#[serde(remote = "diesel::result::Error")]
struct ErrorDef {
    // Definition in here the same as the enum diesel::result::Error
    // ...
}

当然,您也必须对 Error 类型中包含的所有类型(或至少任何尚未实现序列化的类型)执行相同的操作。

文档指出 Serde 根据 'remote' 包中的定义检查您提供的定义,如果它们不同则抛出错误,这将有助于保持它们同步。

另请注意,这不会导致 diesel::result::Error 实现序列化 - 而是您现在有一个可以像这样使用的替代类型:

struct JsonErrorRespone {
    pub success: bool,
    #[serde(with = "ErrorDef")]
    pub error: diesel::result::Error,
}

然后您将序列化上述结构的实例,而不是现有的 json! 宏调用。

此外,上面链接的文档还提供了一些有关手动调用正确的序列化/反序列化实现的提示。

免责声明:我还没有使用过这个工具,以上内容仅从文档中收集。

简短回答:yes you can。我个人一直觉得有点难。

作为折衷方案,您可以只提取与您相关的错误部分,甚至可以这样做:

ApiResponse {
    json: json!({"success": false, "error": error.to_string() }),
    status: Status::UnprocessableEntity,
}

如果您对错误的文本表示感到满意。