serde-untagged

github crates.io docs.rs build status

This crate provides a Serde Visitor implementation that is useful for deserializing untagged enums.

toml [dependencies] serde-untagged = "0.1"


Untagged enum Deserialize impls look like this:

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

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

Inside the /* ... */, we list each type that the untagged enum needs to support deserializing from, giving a closure that turns the input into $MyType. The following types are supported:

Example: string or struct

Cargo's http.ssl-version configuration supports deserialization from the following two representations:

toml [http] ssl-version = "tlsv1.3"

toml [http] ssl-version.min = "tlsv1.2" ssl-version.max = "tlsv1.3"

```rust use serde::de::{Deserialize, Deserializer}; use serdederive::Deserialize; use serdeuntagged::UntaggedEnumVisitor;

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

impl<'de> Deserialize<'de> for SslVersionConfig { fn deserialize(deserializer: D) -> Result 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, pub max: Option, } ```

Example: unit variant or bool

Cargo's LTO setting in profiles supports the 5 values false, true, "fat", "thin", and "off".

toml [profile.release] lto = "thin"

```rust use serde::de::{Deserialize, Deserializer, IntoDeserializer}; use serdederive::Deserialize; use serdeuntagged::UntaggedEnumVisitor;

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

impl<'de> Deserialize<'de> for LinkTimeOptimization { fn deserialize(deserializer: D) -> Result 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, } ```

Since lto = true means the same thing as lto = "fat" to Cargo, there are really only 4 distinct options. This type could be implemented alternatively as:

```rust 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(deserializer: D) -> Result 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) } } ```


License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.


Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.