-
Notifications
You must be signed in to change notification settings - Fork 542
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
0.5: Converting the API to return Results (part 2): Mdf
type
#1444
Conversation
src/format/parsed.rs
Outdated
@@ -390,7 +390,7 @@ impl Parsed { | |||
let (verified, parsed_date) = match (given_year, given_isoyear, self) { | |||
(Some(year), _, &Parsed { month: Some(month), day: Some(day), .. }) => { | |||
// year, month, day | |||
let date = NaiveDate::from_ymd_opt(year, month, day).ok_or(OUT_OF_RANGE)?; | |||
let date = NaiveDate::from_ymd_opt(year, month, day).map_err(|_| OUT_OF_RANGE)?; |
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.
This could be a proper mapping between the variants of Error
and ParsedResult
.
Because this will be one of the first places to touch when converting the parsing code (where it will become just ?
), and because that code is still getting the preparations before we can convert it to Result
s, I'd like to wait with it until that time.
9de6309
to
359c524
Compare
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## 0.5.x #1444 +/- ##
==========================================
- Coverage 94.15% 94.15% -0.01%
==========================================
Files 37 37
Lines 16696 16701 +5
==========================================
+ Hits 15720 15724 +4
- Misses 976 977 +1 ☔ View full report in Codecov by Sentry. |
359c524
to
d0d929f
Compare
I may have forgotten the doc tests (among things) in the enthusiasm 😊. Sorry CI. |
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 very fine from what I see. I suggested a minor change to the -1/0/XX mapping.
@@ -129,20 +129,20 @@ | |||
//! # fn doctest() -> Option<()> { |
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.
Last time I immediately changed the return type to Result<(), chrono::Error>
so that I could make use of the ?
as soon as possible. The rat tail is bigger than unwrapping intermediate results in the doctests, so I guess this works better for now and we have to clean up the tests once all functions return a Result.
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 do you mean with 'rat tail'?
I don't look how the doctests are starting to look, but trust we can clean them up nicely after converting some more parts of the API.
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.
Returning a result in this doctest requires too many changes at this point in time because most *_opt() functions still return an Option. "Rat tail" is a local saying for having to deal with too many consequences for a certain action.
@@ -134,46 +136,47 @@ const MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1; | |||
|
|||
// The next table are adjustment values to convert a date encoded as month-day-leapyear to | |||
// ordinal-leapyear. OL = MDL - adjustment. | |||
// Dates that do not exist are encoded as `XX`. | |||
// Error cases are encoded as `-1` and `XX` (`0`). For a quick check all positive values are | |||
// adjustments, `XX` indicates a date does not exist, and negative values are for invalid input. | |||
const XX: i8 = 0; |
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 would be more coherent to either create a placeholder for both or neither. E.g.
const XX: i8 = 0;
const IV: i8 = -1;
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.
Actually I did just that but switched to this. It felt a bit confusing, looking like Roman numerals. I don't mind how we encode it. Maybe @djc has a preference?
match MDL_TO_OL[mdl as usize] { | ||
XX => None, | ||
v => Some((mdl - v as u8 as u32) >> 1), | ||
let adjustment = MDL_TO_OL[mdl as usize]; |
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.
Would it be possible to keep the matching? That way the adjustment variable has a tighter scope.
Secondly x < 0
is not always the same as x == -1
. Currently there is no other value than -1
, but it is slightly more future proof to immediately detect -2
as a different error. A more suitable error would probably be Error::Undefined
, but it is out of range in this case.
match MDL_TO_OL[mdl as usize] {
adjustment if adjustment > 0 => Ok((mdl - adjustment as u8 as u32) >> 1),
adjustment if adjustment == 0 => Err(Error::DoesNotExist),
adjustment if adjustment == -1 => Err(Error::InvalidArgument),
_ => Err(Error::OutOfRange),
}
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 first attempt used cmp(&0)
, but that didn't work in const context. I expect making the match more precise instead of positive/0/negative would effect the performance a bit. (Can't run a reliable benchmark on the device I am working on right now.)
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.
Can we write it like this?
match adjustment {
1.. => Ok((mdl - adjustment as u8 as u32) >> 1),
0 => Err(Error::DoesNotExist),
_ => Err(Error::InvalidArgument),
}
Seems nice.
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.
Very nice!
match MDL_TO_OL[mdl as usize] { | ||
XX => None, | ||
v => Some((mdl - v as u8 as u32) >> 1), | ||
let adjustment = MDL_TO_OL[mdl as usize]; |
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.
Can we write it like this?
match adjustment {
1.. => Ok((mdl - adjustment as u8 as u32) >> 1),
0 => Err(Error::DoesNotExist),
_ => Err(Error::InvalidArgument),
}
Seems nice.
if year < MIN_YEAR || year > MAX_YEAR { | ||
return None; // Out-of-range | ||
return Err(Error::OutOfRange); |
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.
So from the perspective of this function, why isn't this InvalidArgument
?
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 seems to me a day that is 32 or a month that is 13 is just plain invalid. It is not allowed by the calendar system.
There is nothing particularly invalid about a year that is very far into the future. It is a limitation that Chrono has where we are hitting the (very reasonable) range of our types.
d0d929f
to
00a73b1
Compare
🎉 Nice. @Zomtir If you want to help out the time has come. Drop a note if you start something so I'll steer clear 😄. It seems good to do the conversion with only one method or a very small number of methods per commit. And starting with methods in the Converting |
I started with NaiveDate and got it to compile: 5d476d3 Docs are not updated yet. |
Nice! That requires surprising little changes. I hope you can split it up in smaller commits. Could you skip the We should also have a discussion around the |
🎉
This and #1436 are the last ingredients before we can convert a good portion of the
naive
module to returnResult
s.In the first commit I adjusted four methods on
Mdf
to return aResult
.To ensure we correctly return either
InvalidParameter
orDoesNotExist
on error, theMDL_TO_OL
lookup table can now encode a second error case. We had 128 unused negative values available to do so, and it doesn't cost us any performance (compared to always returning the same variant).The second commit changes
NaiveDate::from_ymd_opt
to return aResult
to have something to benchmark against.Benchmark
Compared to returning an
Option
this is a slight regression of 8% withmain
, and compared to 0.4.24 a regression of ca. 5%. In my opinion it stays in the right ballpark, and seems to be unavoidable.Alternative
As an alternative I tried what happens if
Mdf
returns anOption
, and we map it to an error in the callers. That brings ca. 20% overhead compared tomain
, and is a lot less nice to work with. Better to returnResult
s everywhere.cc @Zomtir