-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update duration rounding to new algorithms #65
Conversation
This PR should definitely wait until after #66 is merged so it can be rebased to remove the custom traits, but it is essentially ready for review outside of that impending rebase There are a couple things to note:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! I have some suggestions on some APIs that we can improve.
009faf9
to
e34d24b
Compare
src/options.rs
Outdated
pub(crate) fn from_diff_settings( | ||
options: DifferenceSettings, | ||
operation: DifferenceOperation, | ||
fallback_largest: TemporalUnit, | ||
fallback_smallest: TemporalUnit, | ||
) -> TemporalResult<(f64, Self)> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thought: Maybe we could return NonZeroDurationSign
here? It would be more consistent to use a single type for the signs instead of having a mix of i8
, f64
, Sign
and NonZeroDurationSign
everywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to a Sign
value.
src/components/duration/time.rs
Outdated
@@ -365,6 +370,69 @@ impl TimeDuration { | |||
// ==== TimeDuration method impls ==== | |||
|
|||
impl TimeDuration { | |||
// TODO: Maybe move to `NormalizedTimeDuration` | |||
pub fn round_v2( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be replacing the original round
? I think we decided to remove the original rounding functions instead of having a v2
for them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went to remove it, but there's still a dependency on the original round. I was going to follow up on this in a different PR.
EDIT: Went through and cleaned it up.
src/components/time.rs
Outdated
@@ -30,9 +32,28 @@ impl Time { | |||
self.iso.is_valid() | |||
} | |||
|
|||
/// Specification equivalent to `AddTime` | |||
pub(crate) fn add_norm(&self, norm: NormalizedTimeDuration) -> (i32, Self) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: probably use the full name of add_normalized_time_duration
. add_norm
is a bit more confusing because it has a different meaning mathematically.
#[derive(Debug, Clone, Copy)] | ||
pub(crate) struct ResolvedRoundingOptions { | ||
pub(crate) largest_unit: TemporalUnit, | ||
pub(crate) smallest_unit: TemporalUnit, | ||
pub(crate) increment: RoundingIncrement, | ||
pub(crate) rounding_mode: TemporalRoundingMode, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Praise: Loving this new API! I think it really makes sense to have an options struct that resolves all the Option
s in RoundingOptions
, instead of having to unwrap
everywhere.
src/components/duration.rs
Outdated
#[repr(i8)] | ||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] | ||
pub enum DurationSign { | ||
Positive = 1, | ||
Zero = 0, | ||
Negative = -1, | ||
} | ||
|
||
impl From<Ordering> for DurationSign { | ||
fn from(value: Ordering) -> Self { | ||
match value { | ||
Ordering::Greater => Self::Positive, | ||
Ordering::Equal => Self::Zero, | ||
Ordering::Less => Self::Negative, | ||
} | ||
} | ||
} | ||
|
||
#[repr(i8)] | ||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] | ||
pub(crate) enum NonZeroDurationSign { | ||
Positive = 1, | ||
Negative = -1, | ||
} | ||
|
||
impl From<DurationSign> for NonZeroDurationSign { | ||
fn from(value: DurationSign) -> Self { | ||
if matches!(value, DurationSign::Negative) { | ||
return Self::Negative; | ||
} | ||
Self::Positive | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After seeing how NonZeroDurationSign
basically optimizes the same as DurationSign
, I don't think it's worth it anymore. Having just DurationSign
should be okay, IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going back and forth with DurationSign
vs. Sign
. 😕 Updated to Sign
this time around.
src/components/duration.rs
Outdated
impl From<Ordering> for DurationSign { | ||
fn from(value: Ordering) -> Self { | ||
match value { | ||
Ordering::Greater => Self::Positive, | ||
Ordering::Equal => Self::Zero, | ||
Ordering::Less => Self::Negative, | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, I don't know if it makes much sense to have a conversion from these enums. Ordering
is a completely different concept than DurationSign
, and things like DurationSign::from(zero.cmp(&target))
don't make much sense if you think about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's a bit awkward. I wasn't super in love with it. Maybe just a From<i8>
pub(crate) fn norm(&self) -> NormalizedTimeDuration { | ||
self.norm | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same suggestion of using the full name.
src/lib.rs
Outdated
pub(crate) fn as_non_zero(&self) -> Self { | ||
if matches!(self, Self::Zero) { | ||
return Self::Positive; | ||
} | ||
*self | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is to multiply a duration with the sign, what about having an as_sign_multiplier
function instead that returns 1i8
for zero and positive, and -1i8
for negative?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is. It's specifically a nonzero variant in these rounding methods vs. the regular multiplication that occurs elsewhere. I'm fine with as_sign_multiplier
though. Better than anything I'm coming up with in this instance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really impressive work! Pretty much perfect IMO :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
As @jedel said this looks great, big improvement
Currently a WIP.This closes #19 outside of anything related to ZonedDateTime, which I'd prefer to consider separately due to the reliance on time zones.
This PR updates duration rounding to the new duration rounding algorithms.
As it's a bit of a larger PR, I thought I would create a draft in case anyone wants to take a look early.
Overall, this draft is fairly close to complete, but there are still at least a couple bugs around the actually rounding that I'm working through.