我正在使用serde_json来解码来自GCP发布/订阅的推送消息.

#[derive(Debug, Deserialize, Serialize)]
pub struct PushMessage {
    pub message: Message,
    pub subscription: String,
}

在消息中,有效负载是data键下的Base64编码字符串:

#[derive(Debug, Deserialize, Serialize)]
pub struct Message {
    message_id: String,
    #[serde(with = "base64data")]
    pub data: String,
}

…我用一个简单的base64data模来解码:

// A serializer/deserializer for base64-encoded data
mod base64data {
    use serde::{Deserialize, Serialize};
    use serde::{Deserializer, Serializer};

    use base64::engine::general_purpose::STANDARD as base64;
    use base64::engine::Engine as _;

    pub fn serialize<S: Serializer>(v: &str, s: S) -> Result<S::Ok, S::Error> {
        let b64 = base64.encode(v);
        String::serialize(&b64, s)
    }

    pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<String, D::Error> {
        let b64 = String::deserialize(d)?;
        base64
            .decode(&b64)
            .map(|v| String::from_utf8(v).expect("Invalid UTF-8"))
            .map_err(|e| serde::de::Error::custom(e))
    }
}

然而,我知道我期望接收的类型也被序列化为JSON(即,Base64编码的字符串解码为JSON字符串),所以理想情况下,我想告诉serde_json继续处理该字段,而不仅仅是解码Base64数据.这可能吗(例如,通过为我们想要反序列化的类型传递一个泛型参数)?

推荐答案

将其注入相同的JSON处理流水线是有问题的,因为(A)并不是每个序列化器/反序列化器都是serde_json,您需要与所有序列化器兼容,并且(B)serde_json还允许对流进行写入和读取,而不仅仅是字符串.

相反,只需在方法中使用serde_json序列化/反序列化它:

// A serializer/deserializer for base64-encoded data
mod json_base64data {
    use serde::de::DeserializeOwned;
    use serde::{Deserialize, Serialize};
    use serde::{Deserializer, Serializer};

    use base64::engine::general_purpose::STANDARD as base64;
    use base64::engine::Engine as _;

    pub fn serialize<T: ?Sized + Serialize, S: Serializer>(v: &T, s: S) -> Result<S::Ok, S::Error> {
        let v = match serde_json::to_string(v) {
            Ok(v) => v,
            Err(e) => return Err(serde::ser::Error::custom(e)),
        };
        let b64 = base64.encode(v);
        String::serialize(&b64, s)
    }

    pub fn deserialize<'de, T: DeserializeOwned, D: Deserializer<'de>>(
        d: D,
    ) -> Result<T, D::Error> {
        let b64 = String::deserialize(d)?;
        match base64.decode(&b64) {
            Ok(v) => match serde_json::from_slice(&v) {
                Ok(v) => Ok(v),
                Err(e) => Err(serde::de::Error::custom(e)),
            },
            Err(e) => Err(serde::de::Error::custom(e)),
        }
    }
}

Rust相关问答推荐

什么是谓词的简短和简洁类型

当为a Self:IntoIterator设置trait bind `时,获取`a T `不是迭代器"&'"<'>&'

关联类型(类型参数)命名约定

如何创建引用构造函数拥有的变量的对象?

通过使用光标拖动角来绕其中心旋转矩形

异步FN中的 rust 递归

支持TLS的模拟HTTP服务器

原始数组数据类型的默认trait实现

在铁 rust 中传递所有权

异步函数返回的future 生存期

我无法理解Rust范围的定义(Rust Programming Language,第二版克拉布尼克和尼科尔斯)

如果变量本身不是None,如何返回;如果没有,则返回None&Quot;?

在复制类型中使用std::ptr::WRITE_VILAR进行内部可变性的安全性(即没有UnSafeCell)

什么时候使用FuturesOrdered?

为什么 tokio 在以奇怪的方式调用时只运行 n 个任务中的 n-1 个?

如何重命名 clap_derive 中的子命令占位符?

如何返回 struct 体中向量的切片

更新 rust ndarray 中矩阵的一行

Google chrome 和 Apple M1 中的计算着色器

为什么 match 语句对引用类型比函数参数更挑剔?