Skip to content

Commit 4dd2fb5

Browse files
committed
WIP
1 parent bd08ec0 commit 4dd2fb5

File tree

5 files changed

+22
-16
lines changed

5 files changed

+22
-16
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

serde_with/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ hashbrown_0_15 = { package = "hashbrown", version = "0.15.0", optional = true, d
136136
hex = { version = "0.4.3", optional = true, default-features = false }
137137
indexmap_1 = { package = "indexmap", version = "1.8", optional = true, default-features = false, features = ["serde-1"] }
138138
indexmap_2 = { package = "indexmap", version = "2.0", optional = true, default-features = false, features = ["serde"] }
139+
num-traits = { version = "0.2.19", features = ["std"] }
139140
schemars_0_8 = { package = "schemars", version = "0.8.16", optional = true, default-features = false }
140141
serde = { version = "1.0.152", default-features = false }
141142
serde_derive = "1.0.152"

serde_with/src/chrono_0_4.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ fn unix_epoch_naive() -> NaiveDateTime {
6262
#[cfg(feature = "std")]
6363
pub mod datetime_utc_ts_seconds_from_any {
6464
use super::*;
65+
use num_traits::ToPrimitive as _;
6566

6667
/// Deserialize a Unix timestamp with optional subsecond precision into a `DateTime<Utc>`.
6768
pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime<Utc>, D::Error>
@@ -110,9 +111,12 @@ pub mod datetime_utc_ts_seconds_from_any {
110111
where
111112
E: DeError,
112113
{
113-
let seconds = value.trunc() as i64;
114-
let nsecs = (value.fract() * 1_000_000_000_f64).abs() as u32;
115-
DateTime::from_timestamp(seconds, nsecs).ok_or_else(|| {
114+
fn f64_to_value(value: f64) -> Option<DateTime<Utc>> {
115+
let seconds = value.trunc().to_i64()?;
116+
let nsecs = (value.fract() * 1_000_000_000_f64).abs().to_u32()?;
117+
DateTime::from_timestamp(seconds, nsecs)
118+
}
119+
f64_to_value(value).ok_or_else(|| {
116120
DeError::custom(format_args!(
117121
"a timestamp which can be represented in a DateTime but received '{value}'"
118122
))

serde_with/src/utils.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pub(crate) mod duration;
22

33
use crate::prelude::*;
4+
use num_traits::ToPrimitive as _;
45

56
/// Re-Implementation of `serde::private::de::size_hint::cautious`
67
#[cfg(feature = "alloc")]
@@ -40,7 +41,10 @@ pub(crate) const NANOS_PER_SEC_F64: f64 = 1_000_000_000.0;
4041
// pub(crate) const NANOS_PER_MICRO: u32 = 1_000;
4142
// pub(crate) const MILLIS_PER_SEC: u64 = 1_000;
4243
// pub(crate) const MICROS_PER_SEC: u64 = 1_000_000;
44+
#[expect(clippy::as_conversions)]
4345
pub(crate) const U64_MAX: u128 = u64::MAX as u128;
46+
#[expect(clippy::as_conversions)]
47+
pub(crate) const U64_MAX_FLOAT: f64 = u64::MAX as f64;
4448

4549
pub(crate) struct MapIter<'de, A, K, V> {
4650
pub(crate) access: A,
@@ -115,27 +119,22 @@ where
115119
}
116120
}
117121

118-
pub(crate) fn duration_signed_from_secs_f64(secs: f64) -> Result<DurationSigned, &'static str> {
119-
const MAX_NANOS_F64: f64 = ((U64_MAX + 1) * NANOS_PER_SEC) as f64;
120-
// TODO why are the seconds converted to nanoseconds first?
121-
// Does it make sense to just truncate the value?
122-
let mut nanos = secs * NANOS_PER_SEC_F64;
123-
if !nanos.is_finite() {
122+
pub(crate) fn duration_signed_from_secs_f64(mut secs: f64) -> Result<DurationSigned, &'static str> {
123+
if !secs.is_finite() {
124124
return Err("got non-finite value when converting float to duration");
125125
}
126-
if nanos >= MAX_NANOS_F64 {
126+
if secs.trunc() > U64_MAX_FLOAT {
127127
return Err("overflow when converting float to duration");
128128
}
129129
let mut sign = Sign::Positive;
130-
if nanos < 0.0 {
131-
nanos = -nanos;
130+
if secs < 0.0 {
131+
secs = -secs;
132132
sign = Sign::Negative;
133133
}
134-
let nanos = nanos as u128;
135134
Ok(DurationSigned::new(
136135
sign,
137-
(nanos / NANOS_PER_SEC) as u64,
138-
(nanos % NANOS_PER_SEC) as u32,
136+
secs.trunc() as u64,
137+
(secs.fract() * NANOS_PER_SEC_F64) as u32,
139138
))
140139
}
141140

serde_with/src/utils/duration.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::{
99
formats::{Flexible, Format, Strict, Strictness},
1010
prelude::*,
1111
};
12+
use num_traits::ToPrimitive as _;
1213

1314
#[derive(Copy, Clone, PartialEq, Eq)]
1415
#[cfg_attr(test, derive(Debug))]
@@ -212,7 +213,7 @@ where
212213
where
213214
S: Serializer,
214215
{
215-
let mut secs = source
216+
let mut secs: i64 = source
216217
.sign
217218
.apply_i64(i64::try_from(source.duration.as_secs()).map_err(|_| {
218219
SerError::custom("The Duration of Timestamp is outside the supported range.")

0 commit comments

Comments
 (0)