From 5e112ec5bc0e0153c6cfc5b583c01eefbdc1cf32 Mon Sep 17 00:00:00 2001 From: Yury Yarashevich Date: Thu, 4 Jan 2024 12:10:10 +0100 Subject: [PATCH] Deserialize numbers from string --- src/api.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/api.rs b/src/api.rs index ad1b006..8e065f7 100644 --- a/src/api.rs +++ b/src/api.rs @@ -63,6 +63,7 @@ pub enum ConstraintExpression { #[cfg_attr(feature = "strict", serde(deny_unknown_fields))] pub struct Variant { pub name: String, + #[serde(deserialize_with = "deserialize_number_from_string")] pub weight: u16, pub payload: Option>, pub overrides: Option>, @@ -137,6 +138,25 @@ pub struct MetricsBucket { pub toggles: HashMap, } +fn deserialize_number_from_string<'de, T, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, + T: std::str::FromStr + serde::Deserialize<'de>, + ::Err: std::fmt::Display, +{ + #[derive(Deserialize)] + #[serde(untagged)] + enum StringOrInt { + String(String), + Number(T), + } + + match StringOrInt::::deserialize(deserializer)? { + StringOrInt::String(s) => s.parse::().map_err(serde::de::Error::custom), + StringOrInt::Number(i) => Ok(i), + } +} + #[cfg(test)] mod tests { use super::Registration; @@ -249,6 +269,16 @@ mod tests { Ok(()) } + #[test] + fn test_parse_variant_with_str_weight() -> Result<(), serde_json::Error> { + let data = r#" + {"name":"Foo","weight":"50","payload":{"type":"string","value":"bar"}} + "#; + let parsed: super::Variant = serde_json::from_str(data)?; + assert_eq!(50, parsed.weight); + Ok(()) + } + #[test] fn test_registration_customisation() { Registration {