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}