diff --git a/Cargo.lock b/Cargo.lock index b40e4038..ea076fc1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -886,6 +886,7 @@ dependencies = [ "indexmap 2.1.0", "jsonschema", "mime", + "num-traits", "pretty_assertions", "regex", "rmp-serde", diff --git a/Cargo.toml b/Cargo.toml index 1d361228..e713ec95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ explicit_auto_deref = "allow" manual-unwrap-or-default = "allow" # alloc_instead_of_core = "warn" -# as_conversions = "warn" +as_conversions = "warn" # arithmetic_side_effects = "warn" # Checks for usage of `cloned()` on an `Iterator` or `Option` where `copied()` could be used instead. cloned_instead_of_copied = "warn" diff --git a/serde_with/Cargo.toml b/serde_with/Cargo.toml index c8427997..9ae8aee2 100644 --- a/serde_with/Cargo.toml +++ b/serde_with/Cargo.toml @@ -129,6 +129,7 @@ hashbrown_0_14 = {package = "hashbrown", version = "0.14.0", optional = true, de hex = {version = "0.4.3", optional = true, default-features = false} indexmap_1 = {package = "indexmap", version = "1.8", optional = true, default-features = false, features = ["serde-1"]} indexmap_2 = {package = "indexmap", version = "2.0", optional = true, default-features = false, features = ["serde"]} +num-traits = { version = "0.2.19", features = ["std"] } schemars_0_8 = {package = "schemars", version = "0.8.16", optional = true, default-features = false} serde = {version = "1.0.152", default-features = false} serde_derive = "1.0.152" diff --git a/serde_with/src/chrono_0_4.rs b/serde_with/src/chrono_0_4.rs index df34f2b8..d80009d0 100644 --- a/serde_with/src/chrono_0_4.rs +++ b/serde_with/src/chrono_0_4.rs @@ -57,6 +57,7 @@ fn unix_epoch_naive() -> NaiveDateTime { #[cfg(feature = "std")] pub mod datetime_utc_ts_seconds_from_any { use super::*; + use num_traits::ToPrimitive as _; /// Deserialize a Unix timestamp with optional subsecond precision into a `DateTime`. pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> @@ -87,20 +88,26 @@ pub mod datetime_utc_ts_seconds_from_any { where E: DeError, { - DateTime::from_timestamp(value as i64, 0).ok_or_else(|| { - DeError::custom(format_args!( + i64::try_from(value) + .ok() + .and_then(|value| DateTime::from_timestamp(value, 0)) + .ok_or_else(|| { + DeError::custom(format_args!( "a timestamp which can be represented in a DateTime but received '{value}'" )) - }) + }) } fn visit_f64(self, value: f64) -> Result where E: DeError, { - let seconds = value.trunc() as i64; - let nsecs = (value.fract() * 1_000_000_000_f64).abs() as u32; - DateTime::from_timestamp(seconds, nsecs).ok_or_else(|| { + fn f64_to_value(value: f64) -> Option> { + let seconds = value.trunc().to_i64()?; + let nsecs = (value.fract() * 1_000_000_000_f64).abs().to_u32()?; + DateTime::from_timestamp(seconds, nsecs) + } + f64_to_value(value).ok_or_else(|| { DeError::custom(format_args!( "a timestamp which can be represented in a DateTime but received '{value}'" ))