diff options
Diffstat (limited to 'src/serde_untagged.rs')
-rw-r--r-- | src/serde_untagged.rs | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/src/serde_untagged.rs b/src/serde_untagged.rs new file mode 100644 index 0000000..20de074 --- /dev/null +++ b/src/serde_untagged.rs @@ -0,0 +1,73 @@ +//! Untagged serialization/deserialization support for 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")] +//! inner: Either<Vec<String>, HashMap<String, i32>> +//! }; +//! +//! // serialization +//! let data = IntOrString { +//! inner: 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: &super::Either<L, R>, serializer: S) -> Result<S::Ok, S::Error> +where + S: Serializer, + L: Serialize, + R: Serialize, +{ + let untagged = match this { + &super::Either::Left(ref left) => Either::Left(left), + &super::Either::Right(ref right) => Either::Right(right), + }; + untagged.serialize(serializer) +} + +pub fn deserialize<'de, L, R, D>(deserializer: D) -> Result<super::Either<L, R>, D::Error> +where + D: Deserializer<'de>, + L: Deserialize<'de>, + R: Deserialize<'de>, +{ + match Either::deserialize(deserializer) { + Ok(Either::Left(left)) => Ok(super::Either::Left(left)), + Ok(Either::Right(right)) => Ok(super::Either::Right(right)), + Err(error) => Err(error), + } +} |