-
Notifications
You must be signed in to change notification settings - Fork 183
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
Only load symbols data if pattern requires them. #791
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ | |
use crate::arithmetic; | ||
use crate::date::{DateTimeInput, DateTimeInputWithLocale, LocalizedDateTimeInput}; | ||
use crate::error::DateTimeFormatError as Error; | ||
use crate::fields::{self, FieldLength, FieldSymbol}; | ||
use crate::fields::{self, Field, FieldLength, FieldSymbol}; | ||
use crate::pattern::{Pattern, PatternItem}; | ||
use crate::provider; | ||
use crate::provider::helpers::DateTimeSymbols; | ||
|
@@ -46,7 +46,7 @@ where | |
T: DateTimeInput, | ||
{ | ||
pub(crate) pattern: &'l Pattern, | ||
pub(crate) symbols: &'l provider::gregory::DateSymbolsV1, | ||
pub(crate) symbols: Option<&'l provider::gregory::DateSymbolsV1>, | ||
pub(crate) datetime: &'l T, | ||
pub(crate) locale: &'l Locale, | ||
} | ||
|
@@ -95,7 +95,7 @@ where | |
|
||
pub fn write_pattern<T, W>( | ||
pattern: &crate::pattern::Pattern, | ||
symbols: &provider::gregory::DateSymbolsV1, | ||
symbols: Option<&provider::gregory::DateSymbolsV1>, | ||
datetime: &T, | ||
locale: &Locale, | ||
w: &mut W, | ||
|
@@ -114,10 +114,15 @@ where | |
Ok(()) | ||
} | ||
|
||
// This function assumes that the correct decision has been | ||
// made regarding availability of symbols in the caller. | ||
// | ||
// When modifying the list of fields using symbols, | ||
// update the matching query in `analyze_pattern` function. | ||
pub(super) fn write_field<T, W>( | ||
pattern: &crate::pattern::Pattern, | ||
field: &fields::Field, | ||
symbols: &crate::provider::gregory::DateSymbolsV1, | ||
symbols: Option<&crate::provider::gregory::DateSymbolsV1>, | ||
datetime: &impl LocalizedDateTimeInput<T>, | ||
w: &mut W, | ||
) -> Result<(), Error> | ||
|
@@ -146,16 +151,18 @@ where | |
field.length, | ||
)?, | ||
length => { | ||
let symbol = symbols.get_symbol_for_month( | ||
month, | ||
length, | ||
datetime | ||
.datetime() | ||
.month() | ||
.ok_or(Error::MissingInputField)? | ||
.number as usize | ||
- 1, | ||
); | ||
let symbol = symbols | ||
.expect("Expect symbols to be present") | ||
.get_symbol_for_month( | ||
month, | ||
length, | ||
datetime | ||
.datetime() | ||
.month() | ||
.ok_or(Error::MissingInputField)? | ||
.number as usize | ||
- 1, | ||
); | ||
w.write_str(symbol)? | ||
} | ||
}, | ||
|
@@ -164,7 +171,9 @@ where | |
.datetime() | ||
.iso_weekday() | ||
.ok_or(Error::MissingInputField)?; | ||
let symbol = symbols.get_symbol_for_weekday(weekday, field.length, dow); | ||
let symbol = symbols | ||
.expect("Expect symbols to be present") | ||
.get_symbol_for_weekday(weekday, field.length, dow); | ||
w.write_str(symbol)? | ||
} | ||
FieldSymbol::Day(..) => format_number( | ||
|
@@ -221,23 +230,62 @@ where | |
field.length, | ||
)?, | ||
FieldSymbol::DayPeriod(period) => { | ||
let symbol = symbols.get_symbol_for_day_period( | ||
period, | ||
field.length, | ||
datetime.datetime().hour().ok_or(Error::MissingInputField)?, | ||
arithmetic::is_top_of_hour( | ||
pattern, | ||
datetime.datetime().minute().map(u8::from).unwrap_or(0), | ||
datetime.datetime().second().map(u8::from).unwrap_or(0), | ||
), | ||
); | ||
let symbol = symbols | ||
.expect("Expect symbols to be present") | ||
.get_symbol_for_day_period( | ||
period, | ||
field.length, | ||
datetime.datetime().hour().ok_or(Error::MissingInputField)?, | ||
arithmetic::is_top_of_hour( | ||
pattern, | ||
datetime.datetime().minute().map(u8::from).unwrap_or(0), | ||
datetime.datetime().second().map(u8::from).unwrap_or(0), | ||
), | ||
); | ||
w.write_str(symbol)? | ||
} | ||
field @ FieldSymbol::TimeZone(_) => return Err(Error::UnsupportedField(field)), | ||
}; | ||
Ok(()) | ||
} | ||
|
||
// This function determins whether the struct will load symbols data. | ||
// Keep it in sync with the `write_field` use of symbols. | ||
pub fn analyze_pattern(pattern: &Pattern, supports_time_zones: bool) -> Result<bool, &Field> { | ||
let fields = pattern.items().iter().filter_map(|p| match p { | ||
PatternItem::Field(field) => Some(field), | ||
_ => None, | ||
}); | ||
|
||
let mut requires_symbols = false; | ||
|
||
for field in fields { | ||
if !requires_symbols { | ||
requires_symbols = match field.symbol { | ||
FieldSymbol::Month(_) => { | ||
!matches!(field.length, FieldLength::One | FieldLength::TwoDigit) | ||
} | ||
FieldSymbol::Weekday(_) | FieldSymbol::DayPeriod(_) => true, | ||
_ => false, | ||
} | ||
sffc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
if supports_time_zones { | ||
if requires_symbols { | ||
// If we require time zones, and symbols, we know all | ||
// we need to return already. | ||
break; | ||
} | ||
} else if matches!(field.symbol, FieldSymbol::TimeZone(_)) { | ||
// If we don't support time zones, and encountered a time zone | ||
// field, error out. | ||
return Err(field); | ||
} | ||
Comment on lines
+273
to
+283
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: I don't see the point of this if/elseif. More specifically, I don't think checking There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The value is that we also validate the time zone availability here. If I were to apply the change you're suggesting, assuming I understand it, then we wouldn't error out if we established we need symbols but also the pattern used time zone and was called from non-time-zoned DTF. Am I missing something? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, I didn't catch that you actually wanted to validate something. This is fine then. |
||
} | ||
|
||
Ok(requires_symbols) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
@@ -268,7 +316,7 @@ mod tests { | |
let mut sink = String::new(); | ||
write_pattern( | ||
&pattern, | ||
&data.get(), | ||
Some(&data.get()), | ||
&datetime, | ||
&"und".parse().unwrap(), | ||
&mut sink, | ||
|
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.
Issue: "Keep it in sync" is a noble comment, but the reality is that devs don't obey instructions in code comments unless there is a hard error. Is there a way to make this into more of a hard error? I guess test coverage, to make sure we hit your
.expect()
, but is that all we can do?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 assume it is. I could try to build some more elaborate enum that has to be true here and in the analyze function together, but I think it's overengineering at this point, and I'd prefer to land it as is.