Как сериализовать и десериализовать перечисление удаленного ящика как число? - PullRequest
3 голосов
/ 05 февраля 2020

Я пытался настроить следующую конфигурацию для serialport ящика в Rust с serde, поэтому я могу интуитивно предоставить 7 в моей конфигурации для data_bits, но он будет десериализован как serialport::DataBits::Seven. К сожалению, это кажется неудачным, когда я хочу, чтобы это было число (7), а не строка (seven).

Тестовый пример

car go .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

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

Как ни странно , запись 7 как seven завершается успешно и возвращается:

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

Один из приведенные примеры в serde документации кажутся актуальными для моего случая, но мне не удалось заставить его работать с моей настройкой.

Сериализация enum как число
Ящик serde_repr предоставляет альтернативные макросы производных, которые получают те же черты Serialize и Deserialize, но делегируют базовому представлению перечисления, подобного C. Это позволяет C -подобным перечислениям форматироваться как целые числа, а не как строки в JSON

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

1 Ответ

4 голосов
/ 05 февраля 2020

Поддержка #[serde(remote)] отсутствует в serde_repr 0.1.5. Вам нужно будет отправить запрос или проблему, чтобы добавить поддержку для него.

Вместо этого следуйте советам в Как преобразовать поля при десериализации с помощью Serde? и Как преобразовать поля при сериализации с использованием 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,
}
...