#serde #enums #untagged #deserializer #deserializing #visitor #de

无 std serde-untagged

为未标记枚举反序列化实现 Serde Visitor

7 个版本

0.1.6 2024年5月14日
0.1.5 2024年1月2日
0.1.4 2023年12月25日
0.1.1 2023年8月28日
0.0.0 2023年8月27日

#249 in 编码

Download history 31769/week @ 2024-05-03 31238/week @ 2024-05-10 31861/week @ 2024-05-17 32212/week @ 2024-05-24 30828/week @ 2024-05-31 33457/week @ 2024-06-07 34361/week @ 2024-06-14 33501/week @ 2024-06-21 35996/week @ 2024-06-28 38196/week @ 2024-07-05 40567/week @ 2024-07-12 41133/week @ 2024-07-19 45000/week @ 2024-07-26 44774/week @ 2024-08-02 50271/week @ 2024-08-09 47129/week @ 2024-08-16

194,379 每月下载量
125 个 crate 中使用 (9 直接使用)

MIT/Apache

58KB
1K SLoC

serde-untagged

github crates.io docs.rs build status

此 crate 提供了一个 Serde Visitor 实现,用于反序列化未标记枚举。

[dependencies]
serde-untagged = "0.1"

未标记枚举 Deserialize 实现看起来像这样

use serde::de::{Deserialize, Deserializer};
use serde_untagged::UntaggedEnumVisitor;

impl<'de> Deserialize<'de> for $MyType {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        UntaggedEnumVisitor::new()
            /*
             *
             */
            .deserialize(deserializer)
    }
}

/* ... */ 中,我们列出未标记枚举需要支持反序列化的每个类型,提供一个闭包将输入转换为 $MyType。以下类型被支持

  • bool
  • i8, i16, i32, i64, i128, u8, u16, u32, u64, u128
  • f32
  • f64
  • char
  • string
  • borrowed_str
  • bytes
  • borrowed_bytes
  • byte_buf
  • unit
  • seq
  • map

示例:字符串或结构体

Cargo 的 http.ssl-version 配置支持从以下两种表示形式反序列化

[http]
ssl-version = "tlsv1.3"
[http]
ssl-version.min = "tlsv1.2"
ssl-version.max = "tlsv1.3"
use serde::de::{Deserialize, Deserializer};
use serde_derive::Deserialize;
use serde_untagged::UntaggedEnumVisitor;

pub enum SslVersionConfig {
    Single(String),
    Range(SslVersionConfigRange),
}

impl<'de> Deserialize<'de> for SslVersionConfig {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        UntaggedEnumVisitor::new()
            .string(|single| Ok(SslVersionConfig::Single(single.to_owned())))
            .map(|map| map.deserialize().map(SslVersionConfig::Range))
            .deserialize(deserializer)
    }
}

#[derive(Deserialize)]
pub struct SslVersionConfigRange {
    pub min: Option<String>,
    pub max: Option<String>,
}

示例:单元变体或布尔值

Cargo 配置文件中的 LTO 设置支持以下 5 个值 falsetrue"fat""thin",和 "off"

[profile.release]
lto = "thin"
use serde::de::{Deserialize, Deserializer, IntoDeserializer};
use serde_derive::Deserialize;
use serde_untagged::UntaggedEnumVisitor;

pub enum LinkTimeOptimization {
    Enabled(bool),
    Enum(LinkTimeOptimizationString),
}

impl<'de> Deserialize<'de> for LinkTimeOptimization {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        UntaggedEnumVisitor::new()
            .bool(|b| Ok(LinkTimeOptimization::Enabled(b)))
            .string(|string| {
                let de = string.into_deserializer();
                LinkTimeOptimizationString::deserialize(de).map(LinkTimeOptimization::Enum)
            })
            .deserialize(deserializer)
    }
}

#[derive(Deserialize)]
#[serde(rename = "lowercase")]
pub enum LinkTimeOptimizationString {
    Fat,
    Thin,
    Off,
}

由于对 Cargo 来说 lto = truelto = "fat" 的意思相同,实际上只有 4 个不同的选项。此类型可以按以下方式实现

use serde::de::{Deserialize, Deserializer, Unexpected};
use serde_untagged::UntaggedEnumVisitor;

pub enum LinkTimeOptimization {
    ThinLocal,  // false
    Fat,        // true or "fat"
    Thin,       // "thin"
    Off,        // "off"
}

impl<'de> Deserialize<'de> for LinkTimeOptimization {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        UntaggedEnumVisitor::new()
            .bool(|b| match b {
                false => Ok(LinkTimeOptimization::ThinLocal),
                true => Ok(LinkTimeOptimization::Fat),
            })
            .string(|string| match string {
                "fat" => Ok(LinkTimeOptimization::Fat),
                "thin" => Ok(LinkTimeOptimization::Thin),
                "off" => Ok(LinkTimeOptimization::Off),
                _ => Err(serde::de::Error::invalid_value(
                    Unexpected::Str(string),
                    &r#""fat" or "thin" or "off""#,
                )),
            })
            .deserialize(deserializer)
    }
}

许可证

根据您的选择,此代码受 Apache 许可证 2.0 版MIT 许可证 许可。
除非您明确表示,否则您提交的任何贡献,根据 Apache-2.0 许可证的定义,都应按上述方式双重许可,不附加任何额外的条款或条件。

依赖项

~260–495KB
~11K SLoC