Files
tuliprox/shared/src/utils/serde_utils.rs
T
2025-06-24 11:25:42 +02:00

86 lines
2.4 KiB
Rust

use serde::{Deserialize, Deserializer,};
use serde::de::DeserializeOwned;
use serde_json::Value;
fn value_to_string_array(value: &[Value]) -> Vec<String> {
value.iter().filter_map(value_to_string).collect()
}
fn value_to_string(v: &Value) -> Option<String> {
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<Option<String>, 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<String, D::Error>
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<Option<Vec<String>>, 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<Option<T>, 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<U> {
// if it can be parsed as Option<T>, it will be
Value(Option<U>),
// otherwise try parsing as a string
NumberString(String),
}
// deserialize into local enum
let value: MaybeNumber<T> = 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::<T>(string.as_str()).map_or_else(|_| Ok(None), |val| Ok(Some(val)))
}
}
}