From e3dcbd3d017fc8af420cee8c1c04bde964fda767 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Mon, 10 Mar 2025 04:58:58 -0400 Subject: [PATCH 01/10] Pull floored division algorithm from stdlib --- time/src/internal_macros.rs | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/time/src/internal_macros.rs b/time/src/internal_macros.rs index dd5c96897..1d8495e62 100644 --- a/time/src/internal_macros.rs +++ b/time/src/internal_macros.rs @@ -51,18 +51,27 @@ macro_rules! impl_div_assign { /// Division of integers, rounding the resulting value towards negative infinity. macro_rules! div_floor { - ($a:expr, $b:expr) => {{ - let _a = $a; - let _b = $b; - - let (_quotient, _remainder) = (_a / _b, _a % _b); - - if (_remainder > 0 && _b < 0) || (_remainder < 0 && _b > 0) { - _quotient - 1 - } else { - _quotient + ($self:expr, $rhs:expr) => { + match ($self, $rhs) { + (this, rhs) => { + let d = this / rhs; + let r = this % rhs; + + // If the remainder is non-zero, we need to subtract one if the + // signs of self and rhs differ, as this means we rounded upwards + // instead of downwards. We do this branchlessly by creating a mask + // which is all-ones iff the signs differ, and 0 otherwise. Then by + // adding this mask (which corresponds to the signed value -1), we + // get our correction. + let correction = (this ^ rhs) >> (::core::mem::size_of_val(&this) * 8 - 1); + if r != 0 { + d + correction + } else { + d + } + } } - }}; + }; } /// Cascade an out-of-bounds value. From b2b602a9a5ba457748c9fce1b8394820ffb87459 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Mon, 10 Mar 2025 06:13:39 -0400 Subject: [PATCH 02/10] Permit visibility in `serde::format_description!` --- tests/serde/macros.rs | 36 ++++---- time-macros/src/lib.rs | 92 ++++++++++++--------- time-macros/src/serde_format_description.rs | 10 ++- 3 files changed, 83 insertions(+), 55 deletions(-) diff --git a/tests/serde/macros.rs b/tests/serde/macros.rs index 2bbea1698..b08229741 100644 --- a/tests/serde/macros.rs +++ b/tests/serde/macros.rs @@ -20,18 +20,24 @@ time::serde::format_description!( Iso8601::<{ iso8601::Config::DEFAULT.encode() }> ); -serde::format_description!( - offset_dt_format, - OffsetDateTime, - "custom format: [year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \ - sign:mandatory]:[offset_minute]" -); -serde::format_description!( - primitive_dt_format, - PrimitiveDateTime, - "custom format: [year]-[month]-[day] [hour]:[minute]:[second]" -); -serde::format_description!(time_format, Time, "custom format: [minute]:[second]"); +mod nested { + time::serde::format_description!( + pub(super) offset_dt_format, + OffsetDateTime, + "custom format: [year]-[month]-[day] [hour]:[minute]:[second] [offset_hour \ + sign:mandatory]:[offset_minute]" + ); + time::serde::format_description!( + pub primitive_dt_format, + PrimitiveDateTime, + "custom format: [year]-[month]-[day] [hour]:[minute]:[second]" + ); + time::serde::format_description!( + pub(in crate::serde::macros) time_format, + Time, + "custom format: [minute]:[second]" + ); +} serde::format_description!(date_format, Date, "custom format: [year]-[month]-[day]"); serde::format_description!( offset_format, @@ -50,13 +56,13 @@ serde::format_description!( #[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] struct TestCustomFormat { - #[serde(with = "offset_dt_format")] + #[serde(with = "nested::offset_dt_format")] offset_dt: OffsetDateTime, - #[serde(with = "primitive_dt_format::option")] + #[serde(with = "nested::primitive_dt_format::option")] primitive_dt: Option, #[serde(with = "date_format")] date: Date, - #[serde(with = "time_format::option")] + #[serde(with = "nested::time_format::option")] time: Option