如何为我不拥有的类型实现 serde 并让它支持复合/wrapper/collection 类型 [英] How can I implement serde for a type that I don't own and have it support compound /wrapper/collection types

查看:46
本文介绍了如何为我不拥有的类型实现 serde 并让它支持复合/wrapper/collection 类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题很相似怎么做我为我不拥有的类型实现了一个我不拥有的特征?

我使用文档中描述的机制为 Date 编写了一个序列化程序,我的模块包装了一个序列化函数

<预><代码>pub mod my_date_format {使用 chrono::{Date, NaiveDate, Utc};使用 serde::{self, Deserialize, Deserializer, Serializer};const SERIALIZE_FORMAT: &'static str = "%Y-%m-%d";pub fn serialize(日期:&Date,序列化器:S)->结果在哪里S:序列化器,{let s = format!("{}", date.format(SERIALIZE_FORMAT));serializer.serialize_str(&s)}pub fn deserialize<'de, D>(解串器:D)->结果<日期,D::错误>在哪里D:解串器de",{让 s = String::deserialize(deserializer)?;NaiveDate::parse_from_str(s.as_str(), SERIALIZE_FORMAT).map_err(serde::de::Error::custom).map(|x| {let now = Utc::now();让日期:Date<Utc>= Date::from_utc(x, now.offset().clone());日期})}}

然后我可以这样做:

struct MyStruct {#[serde(with = "my_date_format")]酒吧开始:日期,}

问题是如果我将序列化的东西包装在其他类型(它们本身是可序列化的)中,我会得到错误:

#[serde(with = "my_date_format")]发布日期:Vec//这现在不起作用,因为我的函数没有序列化向量pubmaybe_date:选项<日期>//不会工作pub box_date:Box>//不会工作...

如何在使用自己的序列化程序时获得提供的实现?

https://docs.serde.rs/serde/ser/index.html#implementations-of-serialize-provided-by-serde

解决方案

使用 serde_as 宏来自 serde_with crate.它的工作方式类似于带有属性的 serde,但也支持包装器和集合类型.

既然你已经有了一个与 serde 一起使用的模块,那么困难的部分已经完成了.您可以在 板条箱文档.您只需要为特征 SerializeAsDeserializeAs 添加一个本地类型和两个样板实现即可使用您的自定义转换.

使用 chrono::{Date, NaiveDate, Utc};struct MyDateFormat;impl serde_with::SerializeAs>对于 MyDateFormat {fn serialize_as(值:&Date,序列化器:S) ->结果在哪里S: serde::Serializer,{my_date_format::serialize(value, serializer)}}实现<'de>serde_with::DeserializeAs<'de, Date>对于 MyDateFormat {fn deserialize_as(解串器:D)->结果<日期,D::错误>在哪里D: serde::Deserializer<'de>,{my_date_format::deserialize(deserializer)}}#[serde_with::serde_as]#[派生(序列化,反序列化,调试)]结构我的结构{#[serde_as(as = "MyDateFormat")]日期:日期,#[serde_as(as = "Vec")]日期:Vec,#[serde_as(as = "Option")]opt_date:选项<Date<Utc>>,#[serde_as(as = "Box")]boxed_date: Box>,}fn 主(){让 s = MyStruct {日期:UTC::now().date().into(),日期: std::iter::repeat(Utc::now().date().into()).take(4).collect(),opt_date: 一些(Utc::now().date().into()),boxed_date: Box::new(Utc::now().date().into()),};让 json = serde_json::to_string_pretty(&s).unwrap();println!("{}", json);}//这个模块是从问题中未修改的pub mod my_date_format {使用 chrono::{Date, NaiveDate, Utc};使用 serde::{self, Deserialize, Deserializer, Serializer};const SERIALIZE_FORMAT: &'static str = "%Y-%m-%d";pub fn serialize(日期:&Date,序列化器:S)->结果在哪里S:序列化器,{let s = format!("{}", date.format(SERIALIZE_FORMAT));serializer.serialize_str(&s)}pub fn deserialize<'de, D>(deserializer: D) ->结果<日期,D::错误>在哪里D:解串器de",{让 s = String::deserialize(deserializer)?;NaiveDate::parse_from_str(s.as_str(), SERIALIZE_FORMAT).map_err(serde::de::Error::custom).map(|x| {let now = Utc::now();让日期:Date<Utc>= Date::from_utc(x, now.offset().clone());日期})}}

This question is similar How do I implement a trait I don't own for a type I don't own?

I wrote a serializer for Date, using the mechanism described in the documentation with my module wrapping a serialize function


pub mod my_date_format {
    use chrono::{Date, NaiveDate, Utc};
    use serde::{self, Deserialize, Deserializer, Serializer};

    const SERIALIZE_FORMAT: &'static str = "%Y-%m-%d";

    pub fn serialize<S>(date: &Date<Utc>, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let s = format!("{}", date.format(SERIALIZE_FORMAT));
        serializer.serialize_str(&s)
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Date<Utc>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        NaiveDate::parse_from_str(s.as_str(), SERIALIZE_FORMAT)
            .map_err(serde::de::Error::custom)
            .map(|x| {
                let now = Utc::now();
                let date: Date<Utc> = Date::from_utc(x, now.offset().clone());
                date
            })
    }
}

then I can do:

struct MyStruct {
    #[serde(with = "my_date_format")]
    pub start: Date<Utc>,
}

Problem is if I wrap the serialized thing in other types (which are serializable themselves) I get errors:

#[serde(with = "my_date_format")]
pub dates: Vec<Date<Utc> // this won't work now since my function doesn't serialize vectors
pub maybe_date: Option<Date<Utc>>> // won't work
pub box_date: Box<Date<Utc>> // won't work...

How can I gain the implementations provided while using my own serializer?

https://docs.serde.rs/serde/ser/index.html#implementations-of-serialize-provided-by-serde

解决方案

Instead of relying on wrapper types it is possible to achieve the same results with the serde_as macro from the serde_with crate. It works like the serde with attribute but also supports wrapper and collections types.

Since you already have a module to use with serde's with, the hard part is already done. You can find the details in the crate documentation. You only need to add a local type and two boilerplate implementations for the traits SerializeAs and DeserializeAs to use your custom transformations.

use chrono::{Date, NaiveDate, Utc};

struct MyDateFormat;

impl serde_with::SerializeAs<Date<Utc>> for MyDateFormat {
    fn serialize_as<S>(value: &Date<Utc>, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {  
        my_date_format::serialize(value, serializer)
    }
}

impl<'de> serde_with::DeserializeAs<'de, Date<Utc>> for MyDateFormat {
    fn deserialize_as<D>(deserializer: D) -> Result<Date<Utc>, D::Error>
    where
        D: serde::Deserializer<'de>,
    {  
        my_date_format::deserialize(deserializer)
    }
}

#[serde_with::serde_as]
#[derive(Serialize, Deserialize, Debug)]
struct MyStruct {
    #[serde_as(as = "MyDateFormat")]
    date: Date<Utc>,
    #[serde_as(as = "Vec<MyDateFormat>")]
    dates: Vec<Date<Utc>>,
    #[serde_as(as = "Option<MyDateFormat>")]
    opt_date: Option<Date<Utc>>,
    #[serde_as(as = "Box<MyDateFormat>")]
    boxed_date: Box<Date<Utc>>,
}

fn main() {
    let s = MyStruct {
        date: Utc::now().date().into(),
        dates: std::iter::repeat(Utc::now().date().into()).take(4).collect(),
        opt_date: Some(Utc::now().date().into()),
        boxed_date: Box::new(Utc::now().date().into()),
    };

    let json = serde_json::to_string_pretty(&s).unwrap();
    println!("{}", json);
}

// This module is taken uunmodified from the question
pub mod my_date_format {
    use chrono::{Date, NaiveDate, Utc};
    use serde::{self, Deserialize, Deserializer, Serializer};

    const SERIALIZE_FORMAT: &'static str = "%Y-%m-%d";

    pub fn serialize<S>(date: &Date<Utc>, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let s = format!("{}", date.format(SERIALIZE_FORMAT));
        serializer.serialize_str(&s)
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Date<Utc>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        NaiveDate::parse_from_str(s.as_str(), SERIALIZE_FORMAT)
            .map_err(serde::de::Error::custom)
            .map(|x| {
                let now = Utc::now();
                let date: Date<Utc> = Date::from_utc(x, now.offset().clone());
                date
            })
    }
}

这篇关于如何为我不拥有的类型实现 serde 并让它支持复合/wrapper/collection 类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆