1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
//! Untagged serialization/deserialization support for Option<Either<L, R>>. //! //! `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<String, i32> //! but in typical cases Vec<String> would suffice, too. //! //! ```rust //! #[macro_use] //! extern crate serde; //! // or `use serde::{Serialize, Deserialize};` in newer rust versions. //! //! # fn main() -> Result<(), Box<dyn std::error::Error>> { //! use either::Either; //! use std::collections::HashMap; //! //! #[derive(Serialize, Deserialize, Debug)] //! #[serde(transparent)] //! struct IntOrString { //! #[serde(with = "either::serde_untagged_optional")] //! inner: Option<Either<Vec<String>, HashMap<String, i32>>> //! }; //! //! // 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<L, R> { Left(L), Right(R), } pub fn serialize<L, R, S>( this: &Option<super::Either<L, R>>, serializer: S, ) -> Result<S::Ok, S::Error> where S: Serializer, L: Serialize, R: Serialize, { let untagged = match this { &Some(super::Either::Left(ref left)) => Some(Either::Left(left)), &Some(super::Either::Right(ref right)) => Some(Either::Right(right)), &None => None, }; untagged.serialize(serializer) } pub fn deserialize<'de, L, R, D>(deserializer: D) -> Result<Option<super::Either<L, R>>, 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), } }