use serde::{Deserialize, Deserializer,}; use serde::de::DeserializeOwned; use serde_json::Value; fn value_to_string_array(value: &[Value]) -> Vec { value.iter().filter_map(value_to_string).collect() } fn value_to_string(v: &Value) -> Option { match v { Value::Bool(value) => Some(value.to_string()), Value::Number(value) => Some(value.to_string()), Value::String(value) => Some(value.to_string()), _ => None, } } pub fn deserialize_as_option_rc_string<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { let value: Value = Deserialize::deserialize(deserializer)?; match &value { Value::String(s) => Ok(Some(s.to_owned())), Value::Number(s) => Ok(Some(s.to_string())), _ => Ok(None), } } pub fn deserialize_as_rc_string<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let value: Value = Deserialize::deserialize(deserializer)?; match &value { Value::String(s) => Ok(s.to_string()), Value::Null => Ok(String::new()), _ => Ok(value.to_string()), } } pub fn deserialize_as_string_array<'de, D>(deserializer: D) -> Result>, D::Error> where D: Deserializer<'de>, { Value::deserialize(deserializer).map(|v| match v { Value::String(value) => Some(vec![value]), Value::Array(value) => Some(value_to_string_array(&value)), _ => None, }) } pub fn deserialize_number_from_string<'de, D, T: DeserializeOwned>( deserializer: D, ) -> Result, D::Error> where D: Deserializer<'de>, { // we define a local enum type inside of the function // because it is untagged, serde will deserialize as the first variant // that it can #[derive(Deserialize)] #[serde(untagged)] enum MaybeNumber { // if it can be parsed as Option, it will be Value(Option), // otherwise try parsing as a string NumberString(String), } // deserialize into local enum let value: MaybeNumber = Deserialize::deserialize(deserializer)?; match value { // if parsed as T or None, return that MaybeNumber::Value(value) => Ok(value), // (if it is any other string) MaybeNumber::NumberString(string) => { serde_json::from_str::(string.as_str()).map_or_else(|_| Ok(None), |val| Ok(Some(val))) } } }