use serde::{Deserialize, Deserializer};
use serde_json::Value as JsonValue;
pub fn from_null_to_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de> + Default,
{
let value = Option::<T>::deserialize(deserializer)?;
Ok(value.unwrap_or_default())
}
pub fn string_to_f64<'de, D>(deserializer: D) -> Result<f64, D::Error>
where
D: serde::Deserializer<'de>,
{
let v = JsonValue::deserialize(deserializer)?;
match v {
JsonValue::Number(n) => n
.as_f64()
.ok_or_else(|| serde::de::Error::custom("invalid number for f64")),
JsonValue::String(s) => {
let t = s.trim();
if t.is_empty() || t == "-" {
Ok(0.0)
} else {
s.parse::<f64>().map_err(serde::de::Error::custom)
}
}
JsonValue::Null => Ok(0.0),
other => Err(serde::de::Error::custom(format!(
"unexpected type for f64 deserialization: {:?}",
other
))),
}
}
pub fn string_to_u64<'de, D>(deserializer: D) -> Result<u64, D::Error>
where
D: serde::Deserializer<'de>,
{
let v = JsonValue::deserialize(deserializer)?;
match v {
JsonValue::Number(n) => n
.as_u64()
.ok_or_else(|| serde::de::Error::custom("invalid number for u64")),
JsonValue::String(s) => {
let t = s.trim();
if t.is_empty() || t == "-" {
Ok(0)
} else {
s.parse::<u64>().map_err(serde::de::Error::custom)
}
}
JsonValue::Null => Ok(0),
other => Err(serde::de::Error::custom(format!(
"unexpected type for u64 deserialization: {:?}",
other
))),
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde::Deserialize;
use serde_json::{self, json};
#[derive(Deserialize, Debug, PartialEq)]
struct TestData<T>
where
T: for<'a> Deserialize<'a> + PartialEq + Default,
{
#[serde(deserialize_with = "from_null_to_default")]
value: T,
}
#[derive(Deserialize, Debug, PartialEq, Default)]
enum TestEnum {
One,
#[default]
Two,
Tree,
}
#[test]
fn test_i64_from_null() {
let data = json!({ "value": null });
let result: TestData<i64> = serde_json::from_value(data).unwrap();
assert_eq!(result.value, 0);
}
#[test]
fn test_i64_from_number() {
let data = json!({ "value": 123 });
let result: TestData<i64> = serde_json::from_value(data).unwrap();
assert_eq!(result.value, 123);
}
#[test]
fn test_f64_from_null() {
let data = json!({ "value": null });
let result: TestData<f64> = serde_json::from_value(data).unwrap();
assert_eq!(result.value, 0.0);
}
#[test]
fn test_f64_from_number() {
let data = json!({ "value": 45.67 });
let result: TestData<f64> = serde_json::from_value(data).unwrap();
assert_eq!(result.value, 45.67);
}
#[test]
fn test_bool_from_null() {
let data = json!({ "value": null });
let result: TestData<bool> = serde_json::from_value(data).unwrap();
assert!(!result.value);
}
#[test]
fn test_string_from_string() {
let data = json!({ "value": "String" });
let result: TestData<String> = serde_json::from_value(data).unwrap();
assert_eq!(result.value, "String");
}
#[test]
fn test_string_from_null() {
let data = json!({ "value": null });
let result: TestData<String> = serde_json::from_value(data).unwrap();
assert_eq!(result.value, "");
}
#[test]
fn test_enum_from_value() {
let data = json!({ "value": "One" });
let result: TestData<TestEnum> = serde_json::from_value(data).unwrap();
assert_eq!(result.value, TestEnum::One);
}
#[test]
fn test_enum_from_null() {
let data = json!({ "value": null });
let result: TestData<TestEnum> = serde_json::from_value(data).unwrap();
assert_eq!(result.value, TestEnum::Two);
}
}