【问题标题】:How do I serialize and deserialize a remote crate's enum as a number?如何将远程 crate 的枚举序列化和反序列化为数字?
【发布时间】:2020-05-20 21:11:36
【问题描述】:

我一直在尝试使用serde 为Rust 中的serialport crate 设置以下配置,因此我可以直观地在data_bits 的配置中提供7,但它将被反序列化为serialport::DataBits::Seven .不幸的是,当我希望它是数字 (7) 而不是字符串 (seven) 时,它似乎失败了。

测试用例

cargo.toml

[package]
name = "serde_error"
version = "0.1.0"
authors = ["Jason Miller"]
edition = "2018"

[dependencies]
serialport = "3.3.0"
serde = { version = "1.0", features = ["derive"] }
ron = "0.5.1"

以下导致错误:

6:16: Expected identifier

ma​​in.rs

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug)]
#[serde(remote = "serialport::DataBits")]
pub enum DataBitsDef {
    #[serde(rename = "5")]
    Five,
    #[serde(rename = "6")]
    Six,
    #[serde(rename = "7")]
    Seven,
    #[serde(rename = "8")]
    Eight,
}

fn default_data_bits() -> serialport::DataBits {
    serialport::DataBits::Eight
}

#[derive(Debug, Serialize, Deserialize)]
pub struct TransceiverSettings {
    pub vid: u16,
    pub pid: u16,
    pub baud_rate: u32,

    #[serde(default = "default_data_bits", with = "DataBitsDef")]
    pub data_bits: serialport::DataBits,
}

impl Default for TransceiverSettings {
    fn default() -> Self {
        Self {
            vid: 0x2341,
            pid: 0x0043,
            baud_rate: 115_200,

            data_bits: serialport::DataBits::Eight,
        }
    }
}

const TRX_CONFIG: &str = "
(
    vid: 0x2341,
    pid: 0x0043, 
    baud_rate: 9600,
    data_bits: 7,
)
";

fn main() {
    match ron::de::from_str::<TransceiverSettings>(&TRX_CONFIG) {
        Err(e) => eprintln!("{}", e),
        Ok(c) => println!("{:?}", c),
    }
}

奇怪的是,将7 写成seven 成功并返回:

TransceiverSettings { vid: 9025, pid: 67, baud_rate: 9600, data_bits: Seven }

ma​​in.rs

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug)]
#[serde(remote = "serialport::DataBits")]
pub enum DataBitsDef {
    #[serde(rename = "5")]
    Five,
    #[serde(rename = "6")]
    Six,
    #[serde(rename = "seven")]
    Seven,
    #[serde(rename = "8")]
    Eight,
}

fn default_data_bits() -> serialport::DataBits {
    serialport::DataBits::Eight
}

#[derive(Debug, Serialize, Deserialize)]
pub struct TransceiverSettings {
    pub vid: u16,
    pub pid: u16,
    pub baud_rate: u32,

    #[serde(default = "default_data_bits", with = "DataBitsDef")]
    pub data_bits: serialport::DataBits,
}

impl Default for TransceiverSettings {
    fn default() -> Self {
        Self {
            vid: 0x2341,
            pid: 0x0043,
            baud_rate: 115_200,

            data_bits: serialport::DataBits::Eight,
        }
    }
}

const TRX_CONFIG: &str = "
(
    vid: 0x2341,
    pid: 0x0043, 
    baud_rate: 9600,
    data_bits: seven,
)
";

fn main() {
    match ron::de::from_str::<TransceiverSettings>(&TRX_CONFIG) {
        Err(e) => eprintln!("{}", e),
        Ok(c) => println!("{:?}", c),
    }
}

serde_repr

serdedocumentation 中的一个给定示例似乎与我的案例相关,但我还没有设法让它与我的设置一起使用。

Serialize enum as number
serde_repr crate 提供了替代派生宏,它们派生相同的序列化和反序列化特征,但委托给类 C 枚举的底层表示。这允许将类似 C 的枚举格式化为整数而不是 JSON 中的字符串

#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
enum SmallPrime {
    Two = 2,
    Three = 3,
    Five = 5,
    Seven = 7,
}

【问题讨论】:

    标签: rust serde


    【解决方案1】:

    在 serde_repr 0.1.5 中支持 #[serde(remote)]not present。您需要提交拉取请求或问题以添加对它的支持。

    请遵循How to transform fields during deserialization using Serde?How to transform fields during serialization using Serde? 中的建议:

    use serde::{Deserialize, Serialize};
    
    mod shim {
        use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
        use serialport::DataBits;
    
        pub fn serialize<S>(v: &DataBits, s: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            use DataBits::*;
    
            let v: u8 = match v {
                Five => 5,
                Six => 6,
                Seven => 7,
                Eight => 8,
            };
    
            v.serialize(s)
        }
    
        pub fn deserialize<'de, D>(d: D) -> Result<DataBits, D::Error>
        where
            D: Deserializer<'de>,
        {
            use DataBits::*;
    
            match u8::deserialize(d)? {
                5 => Ok(Five),
                6 => Ok(Six),
                7 => Ok(Seven),
                8 => Ok(Eight),
                o => Err(D::Error::custom(format_args!("Invalid value {}", o))),
            }
        }
    }
    
    #[derive(Debug, Serialize, Deserialize)]
    pub struct TransceiverSettings {
        pub vid: u16,
        pub pid: u16,
        pub baud_rate: u32,
    
        #[serde(default = "default_data_bits", with = "shim")]
        pub data_bits: serialport::DataBits,
    }
    

    【讨论】:

    • 这是一个绝妙的解决方案!我看过serialize_withdeserialize_with,直到现在我都无法理解它。我现在甚至可以为baud_rate 扩展它,只有选择的值是有效的。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2016-10-16
    • 2014-08-10
    • 2013-09-04
    • 1970-01-01
    • 2020-10-25
    • 1970-01-01
    • 2021-11-30
    • 2021-11-28
    相关资源
    最近更新 更多