pub fn datetime_utc_from_epoch_duration(
duration: std::time::Duration,
) -> chrono::DateTime<chrono::Utc> {
chrono::DateTime::<chrono::Utc>::from(std::time::UNIX_EPOCH + duration)
}
pub fn de_str<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: serde::de::Deserializer<'de>,
T: std::str::FromStr,
T::Err: std::fmt::Display,
{
let data: &str = serde::de::Deserialize::deserialize(deserializer)?;
data.parse::<T>().map_err(serde::de::Error::custom)
}
pub fn de_u64_epoch_ms_as_datetime_utc<'de, D>(
deserializer: D,
) -> Result<chrono::DateTime<chrono::Utc>, D::Error>
where
D: serde::de::Deserializer<'de>,
{
serde::de::Deserialize::deserialize(deserializer).map(|epoch_ms| {
datetime_utc_from_epoch_duration(std::time::Duration::from_millis(epoch_ms))
})
}
pub fn de_str_u64_epoch_ms_as_datetime_utc<'de, D>(
deserializer: D,
) -> Result<chrono::DateTime<chrono::Utc>, D::Error>
where
D: serde::de::Deserializer<'de>,
{
de_str(deserializer).map(|epoch_ms| {
datetime_utc_from_epoch_duration(std::time::Duration::from_millis(epoch_ms))
})
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
pub fn de_str_f64_epoch_ms_as_datetime_utc<'de, D>(
deserializer: D,
) -> Result<chrono::DateTime<chrono::Utc>, D::Error>
where
D: serde::de::Deserializer<'de>,
{
de_str(deserializer).and_then(|epoch_ms: f64| {
if !epoch_ms.is_finite() || epoch_ms < 0.0 {
return Err(serde::de::Error::custom(format!(
"invalid epoch_ms: {epoch_ms}"
)));
}
Ok(datetime_utc_from_epoch_duration(
std::time::Duration::from_millis(epoch_ms as u64),
))
})
}
pub fn de_str_f64_epoch_s_as_datetime_utc<'de, D>(
deserializer: D,
) -> Result<chrono::DateTime<chrono::Utc>, D::Error>
where
D: serde::de::Deserializer<'de>,
{
de_str(deserializer).and_then(|epoch_s: f64| {
if !epoch_s.is_finite() || epoch_s < 0.0 {
return Err(serde::de::Error::custom(format!(
"invalid epoch_s: {epoch_s}"
)));
}
Ok(datetime_utc_from_epoch_duration(
std::time::Duration::from_secs_f64(epoch_s),
))
})
}
pub fn extract_next<'de, SeqAccessor, Target>(
sequence: &mut SeqAccessor,
name: &'static str,
) -> Result<Target, SeqAccessor::Error>
where
SeqAccessor: serde::de::SeqAccess<'de>,
Target: serde::de::DeserializeOwned,
{
sequence
.next_element::<Target>()?
.ok_or_else(|| serde::de::Error::missing_field(name))
}