either/
serde_untagged_optional.rs

1//! Untagged serialization/deserialization support for Option<Either<L, R>>.
2//!
3//! `Either` uses default, externally-tagged representation.
4//! However, sometimes it is useful to support several alternative types.
5//! For example, we may have a field which is generally Map<String, i32>
6//! but in typical cases Vec<String> would suffice, too.
7//!
8//! ```rust
9//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
10//! use either::Either;
11//! use std::collections::HashMap;
12//!
13//! #[derive(serde::Serialize, serde::Deserialize, Debug)]
14//! #[serde(transparent)]
15//! struct IntOrString {
16//!     #[serde(with = "either::serde_untagged_optional")]
17//!     inner: Option<Either<Vec<String>, HashMap<String, i32>>>
18//! };
19//!
20//! // serialization
21//! let data = IntOrString {
22//!     inner: Some(Either::Left(vec!["Hello".to_string()]))
23//! };
24//! // notice: no tags are emitted.
25//! assert_eq!(serde_json::to_string(&data)?, r#"["Hello"]"#);
26//!
27//! // deserialization
28//! let data: IntOrString = serde_json::from_str(
29//!     r#"{"a": 0, "b": 14}"#
30//! )?;
31//! println!("found {:?}", data);
32//! # Ok(())
33//! # }
34//! ```
35
36use serde::{Deserialize, Deserializer, Serialize, Serializer};
37
38#[derive(Serialize, Deserialize)]
39#[serde(untagged)]
40enum Either<L, R> {
41    Left(L),
42    Right(R),
43}
44
45pub fn serialize<L, R, S>(
46    this: &Option<super::Either<L, R>>,
47    serializer: S,
48) -> Result<S::Ok, S::Error>
49where
50    S: Serializer,
51    L: Serialize,
52    R: Serialize,
53{
54    let untagged = match this {
55        Some(super::Either::Left(left)) => Some(Either::Left(left)),
56        Some(super::Either::Right(right)) => Some(Either::Right(right)),
57        None => None,
58    };
59    untagged.serialize(serializer)
60}
61
62pub fn deserialize<'de, L, R, D>(deserializer: D) -> Result<Option<super::Either<L, R>>, D::Error>
63where
64    D: Deserializer<'de>,
65    L: Deserialize<'de>,
66    R: Deserialize<'de>,
67{
68    match Option::deserialize(deserializer) {
69        Ok(Some(Either::Left(left))) => Ok(Some(super::Either::Left(left))),
70        Ok(Some(Either::Right(right))) => Ok(Some(super::Either::Right(right))),
71        Ok(None) => Ok(None),
72        Err(error) => Err(error),
73    }
74}