232 lines
6.2 KiB
Rust
232 lines
6.2 KiB
Rust
#![allow(unused)]
|
|
|
|
use std::collections::{BTreeMap, HashMap};
|
|
|
|
use chrono::{serde::ts_nanoseconds::deserialize, DateTime, NaiveDateTime, Utc};
|
|
use serde::de::{Deserialize, Deserializer, Error, Unexpected, Visitor};
|
|
|
|
pub(crate) fn empty_string_is_none<'de, D>(deserializer: D) -> Result<Option<&'de str>, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
let s: &str = Deserialize::deserialize(deserializer)?;
|
|
if s.is_empty() {
|
|
Ok(None)
|
|
} else {
|
|
Ok(Some(s))
|
|
}
|
|
}
|
|
|
|
pub(crate) fn string_is_long<'de, D>(deserializer: D) -> Result<Option<i64>, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
let s = String::deserialize(deserializer)?;
|
|
if s.is_empty() {
|
|
Ok(None)
|
|
} else {
|
|
s.parse()
|
|
.map(Some)
|
|
.map_err(|_e| Error::invalid_type(Unexpected::Str(&s), &"i64"))
|
|
}
|
|
}
|
|
|
|
pub(crate) fn zero_date_is_none<'de, D>(deserializer: D) -> Result<Option<DateTime<Utc>>, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
let i = i64::deserialize(deserializer)?;
|
|
if i == 0 {
|
|
Ok(None)
|
|
} else {
|
|
let naive = NaiveDateTime::from_timestamp_opt(i, 0)
|
|
.ok_or_else(|| D::Error::invalid_value(Unexpected::Signed(i), &"Epoch timestamp"))?;
|
|
Ok(Some(DateTime::from_utc(naive, Utc)))
|
|
}
|
|
}
|
|
|
|
pub(crate) fn int_is_bool<'de, D>(deserializer: D) -> Result<bool, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
let i = i64::deserialize(deserializer)?;
|
|
|
|
match i {
|
|
0 => Ok(false),
|
|
1 => Ok(true),
|
|
x => Err(Error::invalid_value(Unexpected::Signed(x), &"0 or 1")),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn empty_string_int_option<'de, D>(deserializer: D) -> Result<Option<i32>, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
struct DumbVisitor;
|
|
|
|
impl<'de> Visitor<'de> for DumbVisitor {
|
|
type Value = Option<i32>;
|
|
|
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(formatter, "Empty string or integer")
|
|
}
|
|
|
|
// serde_json will treat all unsigned integers as u64
|
|
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
|
|
where
|
|
E: Error,
|
|
{
|
|
Ok(Some(v as i32))
|
|
}
|
|
|
|
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
|
|
where
|
|
E: Error,
|
|
{
|
|
if v.is_empty() {
|
|
Ok(None)
|
|
} else {
|
|
Err(E::invalid_value(Unexpected::Str(v), &self))
|
|
}
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_any(DumbVisitor)
|
|
}
|
|
|
|
pub(crate) fn datetime_map<'de, D>(
|
|
deserializer: D,
|
|
) -> Result<BTreeMap<i32, chrono::DateTime<chrono::Utc>>, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
#[derive(serde::Deserialize)]
|
|
struct UnixTimestamp(
|
|
#[serde(with = "chrono::serde::ts_seconds")] chrono::DateTime<chrono::Utc>,
|
|
);
|
|
|
|
struct MapVisitor;
|
|
|
|
impl<'de> Visitor<'de> for MapVisitor {
|
|
type Value = BTreeMap<i32, chrono::DateTime<chrono::Utc>>;
|
|
|
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(formatter, "map of unix timestamps")
|
|
}
|
|
|
|
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
|
where
|
|
A: serde::de::MapAccess<'de>,
|
|
{
|
|
let mut result = BTreeMap::new();
|
|
while let Some(key) = map.next_key::<&'de str>()? {
|
|
let id = key
|
|
.parse()
|
|
.map_err(|_e| A::Error::invalid_value(Unexpected::Str(key), &"integer"))?;
|
|
|
|
let ts: UnixTimestamp = map.next_value()?;
|
|
result.insert(id, ts.0);
|
|
}
|
|
|
|
Ok(result)
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_map(MapVisitor)
|
|
}
|
|
|
|
pub(crate) fn empty_dict_is_empty_array<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
T: Deserialize<'de>,
|
|
{
|
|
struct ArrayVisitor<T>(std::marker::PhantomData<T>);
|
|
|
|
impl<'de, T> Visitor<'de> for ArrayVisitor<T>
|
|
where
|
|
T: Deserialize<'de>,
|
|
{
|
|
type Value = Vec<T>;
|
|
|
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(formatter, "vec or empty object")
|
|
}
|
|
|
|
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
|
|
where
|
|
A: serde::de::MapAccess<'de>,
|
|
{
|
|
match map.size_hint() {
|
|
Some(0) | None => Ok(Vec::default()),
|
|
Some(len) => Err(A::Error::invalid_length(len, &"empty dict")),
|
|
}
|
|
}
|
|
|
|
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
|
where
|
|
A: serde::de::SeqAccess<'de>,
|
|
{
|
|
let mut result = match seq.size_hint() {
|
|
Some(len) => Vec::with_capacity(len),
|
|
None => Vec::default(),
|
|
};
|
|
|
|
while let Some(element) = seq.next_element()? {
|
|
result.push(element);
|
|
}
|
|
|
|
Ok(result)
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_any(ArrayVisitor(std::marker::PhantomData))
|
|
}
|
|
|
|
pub(crate) fn null_is_empty_dict<'de, D, K, V>(deserializer: D) -> Result<HashMap<K, V>, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
K: std::hash::Hash + std::cmp::Eq + Deserialize<'de>,
|
|
V: Deserialize<'de>,
|
|
{
|
|
Ok(Option::deserialize(deserializer)?.unwrap_or_default())
|
|
}
|
|
|
|
#[cfg(feature = "decimal")]
|
|
pub(crate) fn string_or_decimal<'de, D>(deserializer: D) -> Result<rust_decimal::Decimal, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
struct DumbVisitor;
|
|
|
|
impl<'de> Visitor<'de> for DumbVisitor {
|
|
type Value = rust_decimal::Decimal;
|
|
|
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(formatter, "integer or float as string")
|
|
}
|
|
|
|
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
|
|
where
|
|
E: Error,
|
|
{
|
|
Ok(v.into())
|
|
}
|
|
|
|
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
|
where
|
|
E: Error,
|
|
{
|
|
Ok(v.into())
|
|
}
|
|
|
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
|
where
|
|
E: Error,
|
|
{
|
|
rust_decimal::Decimal::from_str_exact(v).map_err(E::custom)
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_any(DumbVisitor)
|
|
}
|