// Serialization of large numbers can result in overflows // The time calculations are prone to this, so lint here extra // https://github.com/jonasbb/serde_with/issues/771 #![warn(clippy::as_conversions)]
usecrate::{
formats::{Flexible, Format, Strict, Strictness},
prelude::*,
};
impl<STRICTNESS> SerializeAs<DurationSigned> for DurationSeconds<u64, STRICTNESS> where
STRICTNESS: Strictness,
{ fn serialize_as<S>(source: &DurationSigned, serializer: S) -> Result<S::Ok, S::Error> where
S: Serializer,
{ if source.sign.is_negative() { return Err(SerError::custom( "cannot serialize a negative Duration as u64",
));
}
letmut secs = source.duration.as_secs();
// Properly round the value if source.duration.subsec_millis() >= 500 { if source.sign.is_positive() {
secs += 1;
} else {
secs -= 1;
}
}
secs.serialize(serializer)
}
}
impl<STRICTNESS> SerializeAs<DurationSigned> for DurationSeconds<i64, STRICTNESS> where
STRICTNESS: Strictness,
{ fn serialize_as<S>(source: &DurationSigned, serializer: S) -> Result<S::Ok, S::Error> where
S: Serializer,
{ letmut secs = source
.sign
.apply_i64(i64::try_from(source.duration.as_secs()).map_err(|_| {
SerError::custom("The Duration of Timestamp is outside the supported range.")
})?)
.ok_or_else(|| {
S::Error::custom("The Duration of Timestamp is outside the supported range.")
})?;
// Properly round the value // TODO check for overflows BUG771 if source.duration.subsec_millis() >= 500 { if source.sign.is_positive() {
secs += 1;
} else {
secs -= 1;
}
}
secs.serialize(serializer)
}
}
impl<STRICTNESS> SerializeAs<DurationSigned> for DurationSeconds<f64, STRICTNESS> where
STRICTNESS: Strictness,
{ fn serialize_as<S>(source: &DurationSigned, serializer: S) -> Result<S::Ok, S::Error> where
S: Serializer,
{ // as conversions are necessary for floats #[allow(clippy::as_conversions)] letmut secs = source.sign.apply_f64(source.duration.as_secs() as f64);
// Properly round the value if source.duration.subsec_millis() >= 500 { if source.sign.is_positive() {
secs += 1.;
} else {
secs -= 1.;
}
}
secs.serialize(serializer)
}
}
#[cfg(feature = "alloc")] impl<STRICTNESS> SerializeAs<DurationSigned> for DurationSeconds<String, STRICTNESS> where
STRICTNESS: Strictness,
{ fn serialize_as<S>(source: &DurationSigned, serializer: S) -> Result<S::Ok, S::Error> where
S: Serializer,
{ letmut secs = source
.sign
.apply_i64(i64::try_from(source.duration.as_secs()).map_err(|_| {
SerError::custom("The Duration of Timestamp is outside the supported range.")
})?)
.ok_or_else(|| {
S::Error::custom("The Duration of Timestamp is outside the supported range.")
})?;
// Properly round the value if source.duration.subsec_millis() >= 500 { if source.sign.is_positive() {
secs += 1;
} else {
secs -= 1;
}
}
secs.to_string().serialize(serializer)
}
}
impl<STRICTNESS> SerializeAs<DurationSigned> for DurationSecondsWithFrac<f64, STRICTNESS> where
STRICTNESS: Strictness,
{ fn serialize_as<S>(source: &DurationSigned, serializer: S) -> Result<S::Ok, S::Error> where
S: Serializer,
{
source
.sign
.apply_f64(source.duration.as_secs_f64())
.serialize(serializer)
}
}
impl<FORMAT, STRICTNESS> SerializeAs<DurationSigned> for $outer<FORMAT, STRICTNESS> where
FORMAT: Format,
STRICTNESS: Strictness,
$inner<FORMAT, STRICTNESS>: SerializeAs<DurationSigned>
{ fn serialize_as<S>(source: &DurationSigned, serializer: S) -> Result<S::Ok, S::Error> where
S: Serializer,
{ let value = source.checked_mul($factor).ok_or_else(|| S::Error::custom("Failed to serialize value as the value cannot be represented."))?;
$inner::<FORMAT, STRICTNESS>::serialize_as(&value, serializer)
}
}
impl<'de, FORMAT, STRICTNESS> DeserializeAs<'de, DurationSigned> for $outer<FORMAT, STRICTNESS> where
FORMAT: Format,
STRICTNESS: Strictness,
$inner<FORMAT, STRICTNESS>: DeserializeAs<'de, DurationSigned>,
{ fn deserialize_as<D>(deserializer: D) -> Result<DurationSigned, D::Error> where
D: Deserializer<'de>,
{ let dur = $inner::<FORMAT, STRICTNESS>::deserialize_as(deserializer)?; let dur = dur.checked_div($factor).ok_or_else(|| D::Error::custom("Failed to deserialize value as the value cannot be represented."))?;
Ok(dur)
}
}
impl<'de> DeserializeAs<'de, DurationSigned> for DurationSeconds<i64, Strict> { fn deserialize_as<D>(deserializer: D) -> Result<DurationSigned, D::Error> where
D: Deserializer<'de>,
{
i64::deserialize(deserializer).map(|secs: i64| { let sign = match secs.is_negative() { true => Sign::Negative, false => Sign::Positive,
};
DurationSigned::new(sign, secs.abs_diff(0), 0)
})
}
}
// round() only works on std #[cfg(feature = "std")] impl<'de> DeserializeAs<'de, DurationSigned> for DurationSeconds<f64, Strict> { fn deserialize_as<D>(deserializer: D) -> Result<DurationSigned, D::Error> where
D: Deserializer<'de>,
{ let val = f64::deserialize(deserializer)?.round();
utils::duration_signed_from_secs_f64(val).map_err(DeError::custom)
}
}
fn parse_float_into_time_parts(mut value: &str) -> Result<(Sign, u64, u32), ParseFloatError> { let sign = match value.chars().next() { // Advance by the size of the parsed char
Some('+') => {
value = &value[1..];
Sign::Positive
}
Some('-') => {
value = &value[1..];
Sign::Negative
}
_ => Sign::Positive,
};
let partslen = value.split('.').count(); letmut parts = value.split('.'); match partslen { 1 => { let seconds = parts.next().expect("Float contains exactly one part"); iflet Ok(seconds) = seconds.parse() {
Ok((sign, seconds, 0))
} else {
Err(ParseFloatError::InvalidValue)
}
} 2 => { let seconds = parts.next().expect("Float contains exactly one part"); iflet Ok(seconds) = seconds.parse() { let subseconds = parts.next().expect("Float contains exactly one part"); let subseclen = u32::try_from(subseconds.chars().count()).map_err(|_| { #[cfg(feature = "alloc")] return ParseFloatError::Custom(alloc::format!( "Duration and Timestamps with no more than 9 digits precision, but '{value}' has more"
)); #[cfg(not(feature = "alloc"))] return ParseFloatError::Custom( "Duration and Timestamps with no more than 9 digits precision",
);
})?; if subseclen > 9 { #[cfg(feature = "alloc")] return Err(ParseFloatError::Custom(alloc::format!( "Duration and Timestamps with no more than 9 digits precision, but '{value}' has more"
))); #[cfg(not(feature = "alloc"))] return Err(ParseFloatError::Custom( "Duration and Timestamps with no more than 9 digits precision",
));
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.