use std::fmt::Display;
use std::str::FromStr;
#[cfg(feature = "chrono")]
use serde::de::Error;
use serde::{Deserialize, Deserializer};
#[inline]
pub fn bool_true() -> bool {
true
}
#[inline]
pub const fn default_u16<const V: u16>() -> u16 {
V
}
#[inline]
pub const fn default_u32<const V: u32>() -> u32 {
V
}
#[inline]
pub const fn default_u64<const V: u64>() -> u64 {
V
}
#[inline]
pub const fn default_i16<const V: i16>() -> i16 {
V
}
#[inline]
pub const fn default_i32<const V: i32>() -> i32 {
V
}
#[inline]
pub const fn default_i64<const V: i64>() -> i64 {
V
}
#[cfg(feature = "chrono")]
pub fn deserialize_datetime_utc_from_milliseconds<'de, D>(
deserializer: D,
) -> Result<chrono::DateTime<chrono::Utc>, D::Error>
where
D: Deserializer<'de>,
{
use chrono::prelude::*;
let millis = deserialize_number_from_string::<i64, D>(deserializer)?;
DateTime::<Utc>::from_timestamp_millis(millis)
.ok_or_else(|| D::Error::custom("Couldn't parse the timestamp"))
}
#[cfg(feature = "chrono")]
pub fn deserialize_datetime_utc_from_seconds<'de, D>(
deserializer: D,
) -> Result<chrono::DateTime<chrono::Utc>, D::Error>
where
D: Deserializer<'de>,
{
use chrono::prelude::*;
let seconds = deserialize_number_from_string::<i64, D>(deserializer)?;
DateTime::<Utc>::from_timestamp(seconds, 0)
.ok_or_else(|| D::Error::custom("Couldn't parse the timestamp"))
}
pub fn deserialize_number_from_string<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: FromStr + Deserialize<'de>,
<T as FromStr>::Err: Display,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum StringOrInt<T> {
String(String),
Number(T),
}
match StringOrInt::<T>::deserialize(deserializer)? {
StringOrInt::String(s) => s.parse::<T>().map_err(serde::de::Error::custom),
StringOrInt::Number(i) => Ok(i),
}
}
pub fn deserialize_option_number_from_string<'de, T, D>(
deserializer: D,
) -> Result<Option<T>, D::Error>
where
D: Deserializer<'de>,
T: FromStr + Deserialize<'de>,
<T as FromStr>::Err: Display,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum NumericOrNull<'a, T> {
Str(&'a str),
String(String),
FromStr(T),
Null,
}
match NumericOrNull::<T>::deserialize(deserializer)? {
NumericOrNull::Str(s) => match s {
"" => Ok(None),
_ => T::from_str(s).map(Some).map_err(serde::de::Error::custom),
},
NumericOrNull::String(s) => match s.as_str() {
"" => Ok(None),
_ => T::from_str(&s).map(Some).map_err(serde::de::Error::custom),
},
NumericOrNull::FromStr(i) => Ok(Some(i)),
NumericOrNull::Null => Ok(None),
}
}
macro_rules! wrap_option_number_from_string_fn {
(
$(#[doc = $doc:tt])*
$func:ident,
$res:ty
) => {
$(#[doc = $doc])*
pub fn $func<'de, T, D>(deserializer: D) -> Result<$res, D::Error>
where
D: Deserializer<'de>,
T: FromStr + Deserialize<'de>,
<T as FromStr>::Err: Display,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum NumericOrNull<'a, T> {
Str(&'a str),
String(String),
FromStr(T),
Null,
}
match NumericOrNull::<T>::deserialize(deserializer)? {
NumericOrNull::Str(s) => match s {
"" => Ok(None.into()),
_ => T::from_str(s)
.map(|i| Some(i).into())
.map_err(serde::de::Error::custom),
},
NumericOrNull::String(s) => match s.as_str() {
"" => Ok(None.into()),
_ => T::from_str(&s)
.map(|i| Some(i).into())
.map_err(serde::de::Error::custom),
},
NumericOrNull::FromStr(i) => Ok(Some(i).into()),
NumericOrNull::Null => Ok(None.into()),
}
}
};
}
wrap_option_number_from_string_fn!(
deserialize_cell_option_number_from_string,
std::cell::Cell<Option<T>>
);
wrap_option_number_from_string_fn!(
deserialize_ref_cell_option_number_from_string,
std::cell::RefCell<Option<T>>
);
wrap_option_number_from_string_fn!(
deserialize_mutex_option_number_from_string,
std::sync::Mutex<Option<T>>
);
wrap_option_number_from_string_fn!(
deserialize_rw_lock_option_number_from_string,
std::sync::RwLock<Option<T>>
);
pub fn deserialize_bool_from_anything<'de, D>(deserializer: D) -> Result<bool, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum AnythingOrBool {
String(String),
Int(i64),
Float(f64),
Boolean(bool),
}
match AnythingOrBool::deserialize(deserializer)? {
AnythingOrBool::Boolean(b) => Ok(b),
AnythingOrBool::Int(i) => match i {
1 => Ok(true),
0 => Ok(false),
_ => Err(serde::de::Error::custom("The number is neither 1 nor 0")),
},
AnythingOrBool::Float(f) => {
if (f - 1.0f64).abs() < f64::EPSILON {
Ok(true)
} else if f == 0.0f64 {
Ok(false)
} else {
Err(serde::de::Error::custom(
"The number is neither 1.0 nor 0.0",
))
}
}
AnythingOrBool::String(string) => {
if let Ok(b) = string.to_lowercase().parse::<bool>() {
Ok(b)
} else if let Ok(i) = string.parse::<i64>() {
match i {
1 => Ok(true),
0 => Ok(false),
_ => Err(serde::de::Error::custom("The number is neither 1 nor 0")),
}
} else if let Ok(f) = string.parse::<f64>() {
if (f - 1.0f64).abs() < f64::EPSILON {
Ok(true)
} else if f == 0.0f64 {
Ok(false)
} else {
Err(serde::de::Error::custom(
"The number is neither 1.0 nor 0.0",
))
}
} else {
Err(serde::de::Error::custom(format!(
"Could not parse boolean from a string: {}",
string
)))
}
}
}
}
pub fn deserialize_string_from_number<'de, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum StringOrNumber {
String(String),
Number(i64),
Float(f64),
}
match StringOrNumber::deserialize(deserializer)? {
StringOrNumber::String(s) => Ok(s),
StringOrNumber::Number(i) => Ok(i.to_string()),
StringOrNumber::Float(f) => Ok(f.to_string()),
}
}
pub fn deserialize_default_from_null<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de> + Default,
{
Ok(Option::deserialize(deserializer)?.unwrap_or_default())
}
pub fn deserialize_default_from_empty_object<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de> + Default,
{
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct EmptyObject {}
#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum EmptyOrNot<Y> {
NonEmpty(Y),
Empty(EmptyObject),
Null,
}
let empty_or_not: EmptyOrNot<T> = EmptyOrNot::deserialize(deserializer)?;
match empty_or_not {
EmptyOrNot::NonEmpty(e) => Ok(e),
_ => Ok(T::default()),
}
}
pub fn deserialize_vec_from_string_or_vec<'de, T, D>(deserializer: D) -> Result<Vec<T>, D::Error>
where
D: Deserializer<'de>,
T: FromStr + Deserialize<'de> + 'static,
<T as FromStr>::Err: std::fmt::Display,
{
StringOrVecToVec::default().into_deserializer()(deserializer)
}
pub fn deserialize_to_type_or_fallback<'de, D, T, F>(
deserializer: D,
) -> Result<Result<T, F>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
F: Deserialize<'de>,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum DeEither<T, F> {
Type(T),
Fallback(F),
}
DeEither::<T, F>::deserialize(deserializer).map(|de| match de {
DeEither::Type(t) => Ok(t),
DeEither::Fallback(f) => Err(f),
})
}
pub fn deserialize_to_type_or_none<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: Deserializer<'de>,
Option<T>: Deserialize<'de>,
{
Option::<T>::deserialize(deserializer).or_else(|_| Ok(None))
}
pub fn deserialize_to_type_or_string_lossy<'de, D, T>(
deserializer: D,
) -> Result<Result<T, String>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
let value = serde_value::Value::deserialize(deserializer)?;
Ok(T::deserialize(value.clone()).map_err(|_| match value {
serde_value::Value::Bool(b) => b.to_string(),
serde_value::Value::U8(u) => u.to_string(),
serde_value::Value::U16(u) => u.to_string(),
serde_value::Value::U32(u) => u.to_string(),
serde_value::Value::U64(u) => u.to_string(),
serde_value::Value::I8(i) => i.to_string(),
serde_value::Value::I16(i) => i.to_string(),
serde_value::Value::I32(i) => i.to_string(),
serde_value::Value::I64(i) => i.to_string(),
serde_value::Value::F32(f) => f.to_string(),
serde_value::Value::F64(f) => f.to_string(),
serde_value::Value::Char(c) => c.to_string(),
serde_value::Value::String(s) => s,
serde_value::Value::Unit => String::new(),
serde_value::Value::Option(opt) => {
format!("{:?}", opt)
}
serde_value::Value::Newtype(nt) => {
format!("{:?}", nt)
}
serde_value::Value::Seq(seq) => format!("{:?}", seq),
serde_value::Value::Map(map) => format!("{:?}", map),
serde_value::Value::Bytes(v) => String::from_utf8_lossy(&v).into_owned(),
}))
}
#[macro_export]
macro_rules! StringOrVecToVecParser {
($name:ident, $separator:expr, $skip_empty:expr) => {
fn $name<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
where
D: serde::Deserializer<'de>,
T: FromStr + serde::Deserialize<'de> + 'static,
<T as FromStr>::Err: std::fmt::Display,
{
let mut parser = $crate::field_attributes::StringOrVecToVec::with_separator($separator);
parser.skip_empty($skip_empty);
parser.into_deserializer()(deserializer)
}
};
($t:ty, $name:ident, $pattern:expr, $converter:expr, $skip_empty:expr) => {
fn $name<'de, D>(deserializer: D) -> Result<Vec<$t>, D::Error>
where
D: serde::Deserializer<'de>,
{
$crate::field_attributes::StringOrVecToVec::new($pattern, $converter, $skip_empty)
.into_deserializer()(deserializer)
}
};
}
pub struct StringOrVecToVec<'a, T, E> {
separator: Pattern<'a>,
parser: Box<StringOrVecParser<T, E>>,
skip_empty: bool,
}
pub type StringOrVecParser<T, E> = dyn FnMut(&str) -> Result<T, E>;
pub enum Pattern<'a> {
Char(char),
Str(&'a str),
Pred(Box<dyn Fn(char) -> bool>),
Multiple(Vec<Pattern<'a>>),
}
impl From<char> for Pattern<'_> {
fn from(c: char) -> Self {
Pattern::Char(c)
}
}
impl<'a> From<&'a str> for Pattern<'a> {
fn from(s: &'a str) -> Self {
Pattern::Str(s)
}
}
impl<'a> From<Vec<Pattern<'a>>> for Pattern<'a> {
fn from(patterns: Vec<Pattern<'a>>) -> Self {
Pattern::Multiple(patterns)
}
}
impl<'a> std::iter::FromIterator<Pattern<'a>> for Pattern<'a> {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = Pattern<'a>>,
{
Pattern::Multiple(iter.into_iter().collect())
}
}
impl std::iter::FromIterator<char> for Pattern<'_> {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = char>,
{
Pattern::Multiple(iter.into_iter().map(Pattern::from).collect())
}
}
impl<'a> std::iter::FromIterator<&'a str> for Pattern<'a> {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = &'a str>,
{
Pattern::Multiple(iter.into_iter().map(Pattern::from).collect())
}
}
impl<P> From<P> for Pattern<'_>
where
P: Fn(char) -> bool + 'static,
{
fn from(pred: P) -> Self {
Pattern::Pred(Box::new(pred))
}
}
impl<'de, T> Default for StringOrVecToVec<'_, T, T::Err>
where
T: FromStr + Deserialize<'de> + 'static,
<T as FromStr>::Err: std::fmt::Display,
{
fn default() -> Self {
Self::new(|c| c == ',', T::from_str, false)
}
}
impl<'a, 'de, T> StringOrVecToVec<'a, T, T::Err>
where
T: FromStr + Deserialize<'de> + 'static,
<T as FromStr>::Err: std::fmt::Display,
{
pub fn with_separator(separator: impl Into<Pattern<'a>>) -> Self {
Self::new(separator, T::from_str, false)
}
pub fn skip_empty(&mut self, skip_empty: bool) -> &mut Self {
self.skip_empty = skip_empty;
self
}
}
impl<'a, T, E> StringOrVecToVec<'a, T, E> {
pub fn new(
separator: impl Into<Pattern<'a>>,
parser: impl FnMut(&str) -> Result<T, E> + 'static,
skip_empty: bool,
) -> Self {
Self {
separator: separator.into(),
parser: Box::new(parser),
skip_empty,
}
}
pub fn with_parser(parser: impl FnMut(&str) -> Result<T, E> + 'static) -> Self {
Self::new(|c| c == ',', parser, false)
}
pub fn into_deserializer<'de, D>(
self,
) -> impl FnMut(D) -> Result<Vec<T>, <D as Deserializer<'de>>::Error>
where
'a: 'de,
D: Deserializer<'de>,
T: Deserialize<'de>,
E: std::fmt::Display,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum StringOrVec<T> {
String(String),
Vec(Vec<T>),
}
let StringOrVecToVec {
mut parser,
separator,
skip_empty,
} = self;
move |deserializer| match StringOrVec::<T>::deserialize(deserializer)? {
StringOrVec::String(s) => Ok(separator
.split(&s)
.into_iter()
.filter(|s| {
if skip_empty && s.is_empty() {
return false;
}
true
})
.map(&mut parser)
.collect::<Result<Vec<_>, _>>()
.map_err(serde::de::Error::custom)?),
StringOrVec::Vec(v) => Ok(v),
}
}
}
impl Pattern<'_> {
fn split<'b>(&self, input: &'b str) -> Vec<&'b str> {
match self {
Pattern::Char(c) => input.split(*c).collect(),
Pattern::Str(s) => input.split(s).collect(),
Pattern::Pred(p) => input.split(p).collect(),
Pattern::Multiple(patterns) => {
let mut split = vec![input];
for pattern in patterns {
let delete_until = split.len();
let mut new_split = Vec::new();
for s in &split {
new_split.append(&mut pattern.split(s));
}
if !new_split.is_empty() {
split = split.split_off(delete_until);
}
split.append(&mut new_split);
}
split
}
}
}
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
use std::{
cell::{Cell, RefCell},
sync::{Mutex, RwLock},
};
#[derive(Debug, serde::Deserialize)]
struct MyStruct {
#[serde(
default,
deserialize_with = "deserialize_cell_option_number_from_string"
)]
cell: Cell<Option<f32>>,
#[serde(
default,
deserialize_with = "deserialize_ref_cell_option_number_from_string"
)]
ref_cell: RefCell<Option<f32>>,
#[serde(
default,
deserialize_with = "deserialize_mutex_option_number_from_string"
)]
mutex: Mutex<Option<f32>>,
#[serde(
default,
deserialize_with = "deserialize_rw_lock_option_number_from_string"
)]
rw_lock: RwLock<Option<f32>>,
}
macro_rules! serde_qs_eq {
($s:literal, $result:expr) => {
let a: MyStruct = serde_qs::from_str($s).unwrap();
assert_eq!(a.cell, Cell::new($result));
assert_eq!(a.ref_cell, RefCell::new($result));
assert_eq!(*a.mutex.lock().unwrap(), $result);
assert_eq!(*a.rw_lock.read().unwrap(), $result);
};
}
macro_rules! serde_qs_err {
($rest:literal) => {
assert!(serde_qs::from_str::<MyStruct>(concat!("cell", $rest)).is_err());
assert!(serde_qs::from_str::<MyStruct>(concat!("ref_cell", $rest)).is_err());
assert!(serde_qs::from_str::<MyStruct>(concat!("mutex", $rest)).is_err());
assert!(serde_qs::from_str::<MyStruct>(concat!("rw_lock", $rest)).is_err());
};
}
macro_rules! serde_json_eq {
($s:literal, $result:expr) => {
let a: MyStruct = serde_json::from_str($s).unwrap();
assert_eq!(a.cell, Cell::new($result));
assert_eq!(a.ref_cell, RefCell::new($result));
assert_eq!(*a.mutex.lock().unwrap(), $result);
assert_eq!(*a.rw_lock.read().unwrap(), $result);
};
}
macro_rules! serde_json_err {
($v:tt) => {
assert!(serde_json::from_str::<MyStruct>(r#" { "cell": $v } "#).is_err());
assert!(serde_json::from_str::<MyStruct>(r#" { "ref_cell": $v } "#).is_err());
assert!(serde_json::from_str::<MyStruct>(r#" { "mutex": $v } "#).is_err());
assert!(serde_json::from_str::<MyStruct>(r#" { "rw_lock": $v } "#).is_err());
};
}
#[test]
fn test_deserialize_wrap_option_number_from_string() {
serde_qs_eq!("cell=1&ref_cell=1&mutex=1&rw_lock=1", Some(1.0));
serde_qs_eq!("cell=-1&ref_cell=-1&mutex=-1&rw_lock=-1", Some(-1.0));
serde_qs_eq!("cell=0.1&ref_cell=0.1&mutex=0.1&rw_lock=0.1", Some(0.1));
serde_qs_eq!(
"cell=-0.1&ref_cell=-0.1&mutex=-0.1&rw_lock=-0.1",
Some(-0.1)
);
serde_qs_eq!("cell=&ref_cell=&mutex=&rw_lock=", None);
serde_qs_eq!("cell&ref_cell&mutex&rw_lock", None);
serde_qs_err!("=true");
serde_qs_err!("=a");
serde_qs_err!("[a]=");
serde_qs_err!("[]=");
serde_json_eq!(
r#" { "cell":"1","ref_cell":"1","mutex":"1","rw_lock":"1" } "#,
Some(1.0)
);
serde_json_eq!(
r#" { "cell":"-1","ref_cell":"-1","mutex":"-1","rw_lock":"-1" } "#,
Some(-1.0)
);
serde_json_eq!(
r#" { "cell":"0.1","ref_cell":"0.1","mutex":"0.1","rw_lock":"0.1" } "#,
Some(0.1)
);
serde_json_eq!(
r#" { "cell":"-0.1","ref_cell":"-0.1","mutex":"-0.1","rw_lock":"-0.1" } "#,
Some(-0.1)
);
serde_json_eq!(
r#" { "cell":1,"ref_cell":1,"mutex":1,"rw_lock":1 } "#,
Some(1.0)
);
serde_json_eq!(
r#" { "cell":-1,"ref_cell":-1,"mutex":-1,"rw_lock":-1 } "#,
Some(-1.0)
);
serde_json_eq!(
r#" { "cell":0.1,"ref_cell":0.1,"mutex":0.1,"rw_lock":0.1 } "#,
Some(0.1)
);
serde_json_eq!(
r#" { "cell":-0.1,"ref_cell":-0.1,"mutex":-0.1,"rw_lock":-0.1 } "#,
Some(-0.1)
);
serde_json_eq!(
r#" { "cell":"","ref_cell":"","mutex":"","rw_lock":"" } "#,
None
);
serde_json_eq!(
r#" { "cell":null,"ref_cell":null,"mutex":null,"rw_lock":null } "#,
None
);
serde_json_err!(true);
serde_json_err!("a");
serde_json_err!({});
serde_json_err!([]);
}
#[derive(Debug, serde::Deserialize)]
struct TestStruct {
#[serde(default, deserialize_with = "deserialize_option_number_from_string")]
value: Option<f32>,
}
#[test]
fn deserialize_string_variant_valid_number() {
let json = r#"{"value": "4\u0032.5"}"#;
let result: TestStruct = serde_json::from_str(json).unwrap();
assert_eq!(result.value, Some(42.5));
}
}