简体   繁体   中英

How do I serialize and deserialize a remote crate's enum as a number?

I have been trying to setup the following configuration for the serialport crate in Rust with serde , so I can intuitively supply 7 in my config for data_bits , but it will be deserialized as serialport::DataBits::Seven . Unfortunately, it seemingly fails the moment I want it to be a number ( 7 ) and not a string ( seven ).

Test case

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"

The following results in the error:

6:16: Expected identifier

main.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),
    }
}

Oddly enough, writing 7 as seven succeeds and returns:

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

main.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

One of the given examples in the serde documentation seems relevant to my case, but I haven't managed to get it working with my setup.

Serialize enum as number
The serde_repr crate provides alternative derive macros that derive the same Serialize and Deserialize traits but delegate to the underlying representation of a C-like enum. This allows C-like enums to be formatted as integers rather than strings in JSON

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

Support for #[serde(remote)] is not present in serde_repr 0.1.5. You will need to submit a pull request or issue to add support for it.

Instead, follow the advice in How to transform fields during deserialization using Serde? and 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,
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM