#[cfg(feature = "serde")]
pub mod duration_as_secs_f64 {
use serde::{self, Deserialize, Deserializer, Serializer};
use std::time::Duration;
pub fn serialize<S>(dur: &Option<Duration>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match dur {
Some(d) => serializer.serialize_some(&d.as_secs_f64()),
None => serializer.serialize_none(),
}
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Duration>, D::Error>
where
D: Deserializer<'de>,
{
let opt: Option<f64> = Option::deserialize(deserializer)?;
match opt {
Some(secs) if secs.is_finite() && secs >= 0.0 => {
Ok(Duration::try_from_secs_f64(secs).ok())
}
Some(_) => {
Ok(None)
}
None => Ok(None),
}
}
}
#[cfg(feature = "serde")]
pub mod bytes_as_base64 {
use base64::{Engine, engine::general_purpose::STANDARD};
use serde::{self, Deserializer, Serializer};
pub fn serialize<S>(bytes: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let encoded = STANDARD.encode(bytes);
serializer.serialize_str(&encoded)
}
const MAX_BASE64_LEN: usize = 128 * 1024 * 1024;
struct Base64Visitor;
impl<'de> serde::de::Visitor<'de> for Base64Visitor {
type Value = Vec<u8>;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str("a base64-encoded string")
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
check_and_decode(v)
}
fn visit_borrowed_str<E: serde::de::Error>(self, v: &'de str) -> Result<Self::Value, E> {
check_and_decode(v)
}
fn visit_string<E: serde::de::Error>(self, v: String) -> Result<Self::Value, E> {
check_and_decode(&v)
}
}
fn check_and_decode<E: serde::de::Error>(s: &str) -> Result<Vec<u8>, E> {
if s.len() > MAX_BASE64_LEN {
return Err(E::custom(format!(
"base64 string too large: {} bytes exceeds {} byte limit",
s.len(),
MAX_BASE64_LEN
)));
}
STANDARD
.decode(s)
.map_err(|e| E::custom(format!("invalid base64: {}", e)))
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(Base64Visitor)
}
}