aboutsummaryrefslogtreecommitdiff
path: root/src/serde_untagged.rs
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2021-03-17 01:04:41 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2021-03-17 01:04:41 +0000
commitd595141447ba52ab96402fff33bbfb886a60c71e (patch)
tree7676eda0875eaa77883d8e8cbe9abbb90650bbc6 /src/serde_untagged.rs
parent86fc0929ff3919d702b5a8e4ecf1fac030135bbc (diff)
parent85f89ad7f8c24ceea85c180d8af64fd01679399b (diff)
downloadeither-d595141447ba52ab96402fff33bbfb886a60c71e.tar.gz
Snap for 7213262 from 85f89ad7f8c24ceea85c180d8af64fd01679399b to sc-release
Change-Id: Id69838a283aa1574b669b4f199a8e68853db7360
Diffstat (limited to 'src/serde_untagged.rs')
-rw-r--r--src/serde_untagged.rs73
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),
+ }
+}