-
Notifications
You must be signed in to change notification settings - Fork 533
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
Month::overflowing_add/sub #753
Month::overflowing_add/sub #753
Conversation
If this is looking like a good API, I'll add some more documentation prior to this being merged |
I still need to do the |
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.
In principle I'm open to the modularization of moving some of diff_months()
's internals into public API on Month
, but I'm not sure this API is really natural/otherwise useful.
}; | ||
let year = self.year() + years; |
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.
No more overflow/underflow checking for the years?
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.
Accidentally removed too much from the function. I've added it back as:
if year < MIN_YEAR || year > MAX_YEAR {
return None;
}
Or do you mean the self.year() + years
overflowing/underflowing the i32
?
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.
Both...
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.
will add the check on i32
as well
fn diff_months(self, months: Months, forwards: bool) -> Option<Self> { | ||
// safe as .month() returns [1..12] | ||
// can be further improved when .month() returns a Month | ||
let month: crate::Month = num_traits::FromPrimitive::from_u32(self.month()).unwrap(); |
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 don't see the point of using num_traits::FromPrimitive
and using unwrap()
if we can just use as
here.
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 need the actual Month
type here as that's what overflowing_add/sub
take as the &self
parameter. This will be able to be cleaned up later if/when we fix #727
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.
FromPrimitive
is just too opaque to me, IMO something lower-level is easier to reason about.
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 don't think it is possible to go from u32
to an enumeration thought?
src/month.rs
Outdated
@@ -195,8 +223,23 @@ pub struct Months(pub(crate) u32); | |||
|
|||
impl Months { | |||
/// Construct a new `Months` from a number of months | |||
pub fn new_opt(num: u32) -> Option<Self> { | |||
if num <= core::i32::MAX as u32 { |
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 not really a fan of this as the constraint ends up not being expressed in the type system, so we have to lean on convention/remembering/understanding. IMO it's better just to it as u32
(which also makes the initialization API simple) and check the range in usage context.
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.
My thinking with this is that if the Months
is invalid, its better for this to show up when creating the months rather than adding it, but admittedly most Months
will be made and added as part of the same expression. Perhaps another option is taking i32
here but returning None
on negative values? Or else removing new_opt
and having the check be done inside overflowing_add/sub
. This also forces months to have one less possible value on the sub side due to i32::MAX != abs(i32::MIN)
, but potentially this is acceptable as it is erring on the side of allowing a slightly smaller maximum subtraction?
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.
But that's just the point: a Months::new(u32::MAX)
is not invalid by itself -- it's conceptually perfectly valid. It's only invalid in the context of what checked_add_months()
/checked_sub_months()
are trying to do, as such IMO the burden of validation should fall on the context, not the type itself.
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.
Makes sense, will move the checks there
src/naive/date.rs
Outdated
@@ -2153,26 +2125,13 @@ mod tests { | |||
use std::{i32, u32}; | |||
|
|||
#[test] | |||
fn diff_months() { | |||
fn test_diff_months() { |
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.
What does the test_
prefix buy us? This seems like an unrelated change.
|
||
// Clamp original day in case new month is shorter | ||
|
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'd prefer to keep the empty line here
With regard to the API, I agree that it is debatable if it is generally useful. A couple of potential use cases are:
Alternatively if you like this but don't think think the public API is useful, it could be made private? |
3f2a6db
to
49d7d07
Compare
I think this is only good if the public API is useful. Otherwise the indirection makes the code harder to understand and I'd prefer to keep it as I had it in my original PR. It sounds to me like we don't yet have a very convincing use case in mind for exposing this publicly, so in that case I think we should leave this for now and keep this in mind as a potential direction for future evolution. |
(Sorry, closed it accidentally.) |
remove wayward debug fix formatting, add better docs, improve impl, check for valid years move months validity checks to checked_add/sub
49d7d07
to
66a2a29
Compare
Add an overflowing_add/sub similar to the equivalents for
NaiveTime
, which are useful forNaiveDate
+Months
Also change
Months
constructor to only acceptu32 <= i32::MAX
and add atry_new