如何将远程 crate 的枚举序列化和反序列化为数字?
Posted
技术标签:
【中文标题】如何将远程 crate 的枚举序列化和反序列化为数字?【英文标题】:How do I serialize and deserialize a remote crate's enum as a number? 【发布时间】: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
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
documentation 中的一个给定示例似乎与我的案例相关,但我还没有设法让它与我的设置一起使用。
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,
【问题讨论】:
【参考方案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_with
和deserialize_with
,直到现在我都无法理解它。我现在甚至可以为baud_rate
扩展它,只有选择的值是有效的。谢谢!以上是关于如何将远程 crate 的枚举序列化和反序列化为数字?的主要内容,如果未能解决你的问题,请参考以下文章