//! Untagged serialization/deserialization support for Option>. //! //! `Either` uses default, externally-tagged representation. //! However, sometimes it is useful to support several alternative types. //! For example, we may have a field which is generally Map //! but in typical cases Vec would suffice, too. //! //! ```rust //! # fn main() -> Result<(), Box> { //! use either::Either; //! use std::collections::HashMap; //! //! #[derive(serde::Serialize, serde::Deserialize, Debug)] //! #[serde(transparent)] //! struct IntOrString { //! #[serde(with = "either::serde_untagged_optional")] //! inner: Option, HashMap>> //! }; //! //! // serialization //! let data = IntOrString { //! inner: Some(Either::Left(vec!["Hello".to_string()])) //! }; //! // notice: no tags are emitted. //! assert_eq!(serde_json::to_string(&data)?, r#"["Hello"]"#); //! //! // deserialization //! let data: IntOrString = serde_json::from_str( //! r#"{"a": 0, "b": 14}"# //! )?; //! println!("found {:?}", data); //! # Ok(()) //! # } //! ``` use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[derive(Serialize, Deserialize)] #[serde(untagged)] enum Either { Left(L), Right(R), } pub fn serialize( this: &Option>, serializer: S, ) -> Result where S: Serializer, L: Serialize, R: Serialize, { let untagged = match this { Some(super::Either::Left(left)) => Some(Either::Left(left)), Some(super::Either::Right(right)) => Some(Either::Right(right)), None => None, }; untagged.serialize(serializer) } pub fn deserialize<'de, L, R, D>(deserializer: D) -> Result>, D::Error> where D: Deserializer<'de>, L: Deserialize<'de>, R: Deserialize<'de>, { match Option::deserialize(deserializer) { Ok(Some(Either::Left(left))) => Ok(Some(super::Either::Left(left))), Ok(Some(Either::Right(right))) => Ok(Some(super::Either::Right(right))), Ok(None) => Ok(None), Err(error) => Err(error), } }