Skip to content
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

Add with_fset fns to datetime types #5942

Merged
merged 4 commits into from
Dec 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions components/datetime/src/neo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,55 @@ impl<C: CldrCalendar, FSet: DateTimeMarkers> FixedCalendarDateTimeFormatter<C, F
calendar: calendar.to_any(),
}
}

/// Maps a [`FixedCalendarDateTimeFormatter`] of a specific `FSet` to a more general `FSet`.
///
/// For example, this can transform a formatter for [`YMD`] to one for [`DateFieldSet`].
///
/// [`YMD`]: crate::fieldsets::YMD
/// [`DateFieldSet`]: crate::fieldsets::enums::DateFieldSet
///
/// # Examples
///
/// ```
/// use icu::calendar::Gregorian;
/// use icu::calendar::DateTime;
/// use icu::datetime::FixedCalendarDateTimeFormatter;
/// use icu::datetime::fieldsets::{YMD, enums::DateFieldSet};
/// use icu::locale::locale;
/// use writeable::assert_writeable_eq;
///
/// let specific_formatter = FixedCalendarDateTimeFormatter::try_new(
/// locale!("fr").into(),
/// YMD::medium(),
/// )
/// .unwrap();
///
/// // Test that the specific formatter works:
/// let datetime = DateTime::try_new_gregorian(2024, 12, 20, 14, 30, 0).unwrap();
/// assert_writeable_eq!(
/// specific_formatter.format(&datetime),
/// "20 déc. 2024"
/// );
///
/// // Make a more general formatter:
/// let general_formatter = specific_formatter.with_fset::<DateFieldSet>();
///
/// // Test that it still works:
/// assert_writeable_eq!(
/// general_formatter.format(&datetime),
/// "20 déc. 2024"
/// );
/// ```
pub fn with_fset<FSet2: DateTimeNamesFrom<FSet>>(
self,
) -> FixedCalendarDateTimeFormatter<C, FSet2> {
FixedCalendarDateTimeFormatter {
selection: self.selection,
names: self.names.with_fset(),
_calendar: PhantomData,
}
}
}

impl<FSet: DateTimeMarkers> DateTimeFormatter<FSet> {
Expand Down Expand Up @@ -772,6 +821,53 @@ impl<FSet: DateTimeMarkers> DateTimeFormatter<FSet> {
})
}

/// Maps a [`DateTimeFormatter`] of a specific `FSet` to a more general `FSet`.
///
/// For example, this can transform a formatter for [`YMD`] to one for [`DateFieldSet`].
///
/// [`YMD`]: crate::fieldsets::YMD
/// [`DateFieldSet`]: crate::fieldsets::enums::DateFieldSet
///
/// # Examples
///
/// ```
/// use icu::calendar::Gregorian;
/// use icu::calendar::DateTime;
/// use icu::datetime::DateTimeFormatter;
/// use icu::datetime::fieldsets::{YMD, enums::DateFieldSet};
/// use icu::locale::locale;
/// use writeable::assert_writeable_eq;
///
/// let specific_formatter = DateTimeFormatter::try_new(
/// locale!("fr").into(),
/// YMD::medium(),
/// )
/// .unwrap();
///
/// // Test that the specific formatter works:
/// let datetime = DateTime::try_new_gregorian(2024, 12, 20, 14, 30, 0).unwrap();
/// assert_writeable_eq!(
/// specific_formatter.format_any_calendar(&datetime),
/// "20 déc. 2024"
/// );
///
/// // Make a more general formatter:
/// let general_formatter = specific_formatter.with_fset::<DateFieldSet>();
///
/// // Test that it still works:
/// assert_writeable_eq!(
/// general_formatter.format_any_calendar(&datetime),
/// "20 déc. 2024"
/// );
/// ```
pub fn with_fset<FSet2: DateTimeNamesFrom<FSet>>(self) -> DateTimeFormatter<FSet2> {
DateTimeFormatter {
selection: self.selection,
names: self.names.with_fset(),
calendar: self.calendar,
}
}

/// Returns the calendar system used in this formatter.
///
/// # Examples
Expand Down
197 changes: 152 additions & 45 deletions components/datetime/src/pattern/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,41 +228,30 @@ pub struct TypedDateTimeNames<
}

pub(crate) struct RawDateTimeNames<FSet: DateTimeNamesMarker> {
year_names:
<FSet::YearNames as DateTimeNamesHolderTrait<YearNamesV1Marker>>::Container<FieldLength>,
month_names: <FSet::MonthNames as DateTimeNamesHolderTrait<MonthNamesV1Marker>>::Container<(
fields::Month,
FieldLength,
)>,
weekday_names:
<FSet::WeekdayNames as DateTimeNamesHolderTrait<WeekdayNamesV1Marker>>::Container<(
fields::Weekday,
FieldLength,
)>,
year_names: <FSet::YearNames as NamesContainer<YearNamesV1Marker, FieldLength>>::Container,
month_names: <FSet::MonthNames as NamesContainer<
MonthNamesV1Marker,
(fields::Month, FieldLength),
>>::Container,
weekday_names: <FSet::WeekdayNames as NamesContainer<
WeekdayNamesV1Marker,
(fields::Weekday, FieldLength),
>>::Container,
dayperiod_names:
<FSet::DayPeriodNames as DateTimeNamesHolderTrait<DayPeriodNamesV1Marker>>::Container<
FieldLength,
>,
<FSet::DayPeriodNames as NamesContainer<DayPeriodNamesV1Marker, FieldLength>>::Container,
zone_essentials:
<FSet::ZoneEssentials as DateTimeNamesHolderTrait<tz::EssentialsV1Marker>>::Container<()>,
locations_root:
<FSet::ZoneLocations as DateTimeNamesHolderTrait<tz::LocationsV1Marker>>::Container<()>,
locations:
<FSet::ZoneLocations as DateTimeNamesHolderTrait<tz::LocationsV1Marker>>::Container<()>,
mz_generic_long: <FSet::ZoneGenericLong as DateTimeNamesHolderTrait<
tz::MzGenericLongV1Marker,
>>::Container<()>,
mz_generic_short: <FSet::ZoneGenericShort as DateTimeNamesHolderTrait<
tz::MzGenericShortV1Marker,
>>::Container<()>,
mz_specific_long: <FSet::ZoneSpecificLong as DateTimeNamesHolderTrait<
tz::MzSpecificLongV1Marker,
>>::Container<()>,
mz_specific_short: <FSet::ZoneSpecificShort as DateTimeNamesHolderTrait<
tz::MzSpecificShortV1Marker,
>>::Container<()>,
mz_periods:
<FSet::MetazoneLookup as DateTimeNamesHolderTrait<tz::MzPeriodV1Marker>>::Container<()>,
<FSet::ZoneEssentials as NamesContainer<tz::EssentialsV1Marker, ()>>::Container,
locations_root: <FSet::ZoneLocations as NamesContainer<tz::LocationsV1Marker, ()>>::Container,
locations: <FSet::ZoneLocations as NamesContainer<tz::LocationsV1Marker, ()>>::Container,
mz_generic_long:
<FSet::ZoneGenericLong as NamesContainer<tz::MzGenericLongV1Marker, ()>>::Container,
mz_generic_short:
<FSet::ZoneGenericShort as NamesContainer<tz::MzGenericShortV1Marker, ()>>::Container,
mz_specific_long:
<FSet::ZoneSpecificLong as NamesContainer<tz::MzSpecificLongV1Marker, ()>>::Container,
mz_specific_short:
<FSet::ZoneSpecificShort as NamesContainer<tz::MzSpecificShortV1Marker, ()>>::Container,
mz_periods: <FSet::MetazoneLookup as NamesContainer<tz::MzPeriodV1Marker, ()>>::Container,
// TODO(#4340): Make the FixedDecimalFormatter optional
fixed_decimal_formatter: Option<FixedDecimalFormatter>,
_marker: PhantomData<FSet>,
Expand All @@ -287,6 +276,27 @@ impl<FSet: DateTimeNamesMarker> fmt::Debug for RawDateTimeNames<FSet> {
}
}

impl<FSet: DateTimeNamesMarker> RawDateTimeNames<FSet> {
pub(crate) fn with_fset<FSet2: DateTimeNamesFrom<FSet>>(self) -> RawDateTimeNames<FSet2> {
RawDateTimeNames {
year_names: FSet2::map_year_names(self.year_names),
month_names: FSet2::map_month_names(self.month_names),
weekday_names: FSet2::map_weekday_names(self.weekday_names),
dayperiod_names: FSet2::map_day_period_names(self.dayperiod_names),
zone_essentials: FSet2::map_zone_essentials(self.zone_essentials),
locations_root: FSet2::map_zone_locations(self.locations_root),
locations: FSet2::map_zone_locations(self.locations),
mz_generic_long: FSet2::map_zone_generic_long(self.mz_generic_long),
mz_generic_short: FSet2::map_zone_generic_short(self.mz_generic_short),
mz_specific_long: FSet2::map_zone_specific_long(self.mz_specific_long),
mz_specific_short: FSet2::map_zone_specific_short(self.mz_specific_short),
mz_periods: FSet2::map_metazone_lookup(self.mz_periods),
fixed_decimal_formatter: self.fixed_decimal_formatter,
_marker: PhantomData,
}
}
}

#[derive(Debug, Copy, Clone)]
pub(crate) struct RawDateTimeNamesBorrowed<'l> {
year_names: OptionalNames<FieldLength, &'l YearNamesV1<'l>>,
Expand Down Expand Up @@ -1310,23 +1320,120 @@ impl<C: CldrCalendar, FSet: DateTimeNamesMarker> TypedDateTimeNames<C, FSet> {
self.inner.as_borrowed(),
))
}

/// Maps a [`TypedDateTimeNames`] of a specific `FSet` to a more general `FSet`.
///
/// For example, this can transform a formatter for [`DateFieldSet`] to one for
/// [`CompositeDateTimeFieldSet`].
///
/// [`DateFieldSet`]: crate::fieldsets::enums::DateFieldSet
/// [`CompositeDateTimeFieldSet`]: crate::fieldsets::enums::CompositeDateTimeFieldSet
///
/// # Examples
///
/// ```
/// use icu::calendar::Gregorian;
/// use icu::calendar::DateTime;
/// use icu::datetime::pattern::TypedDateTimeNames;
/// use icu::datetime::fields::FieldLength;
/// use icu::datetime::fields;
/// use icu::datetime::fieldsets::enums::{DateFieldSet, CompositeDateTimeFieldSet};
/// use icu::datetime::pattern::DateTimePattern;
/// use icu::locale::locale;
/// use writeable::assert_try_writeable_eq;
///
/// // Create an instance that can format abbreviated month names:
/// let mut names: TypedDateTimeNames<Gregorian, DateFieldSet> =
/// TypedDateTimeNames::try_new(locale!("uk").into()).unwrap();
/// names
/// .include_month_names(fields::Month::Format, FieldLength::Three)
/// .unwrap();
///
/// // Test it with a pattern:
/// let pattern_str = "MMM d y";
/// let pattern: DateTimePattern = pattern_str.parse().unwrap();
/// let datetime = DateTime::try_new_gregorian(2023, 11, 20, 12, 35, 3).unwrap();
/// assert_try_writeable_eq!(names.with_pattern_unchecked(&pattern).format(&datetime), "лист. 20 2023");
///
/// // Convert the field set to `CompositeDateTimeFieldSet`:
/// let composite_names = names.with_fset::<CompositeDateTimeFieldSet>();
///
/// // It should still work:
/// assert_try_writeable_eq!(composite_names.with_pattern_unchecked(&pattern).format(&datetime), "лист. 20 2023");
/// ```
///
/// Converting into a narrower type is not supported:
///
/// ```compile_fail,E0277
/// use icu::calendar::Gregorian;
/// use icu::datetime::pattern::TypedDateTimeNames;
/// use icu::datetime::fieldsets::enums::{DateFieldSet, CompositeDateTimeFieldSet};
///
/// let composite_names: TypedDateTimeNames<Gregorian, CompositeDateTimeFieldSet> = todo!();
///
/// // error[E0277]: the trait bound `(): From<DataPayloadWithVariables<DayPeriodNamesV1Marker, FieldLength>>` is not satisfied
/// let narrow_names = composite_names.with_fset::<DateFieldSet>();
/// ```
pub fn with_fset<FSet2: DateTimeNamesFrom<FSet>>(self) -> TypedDateTimeNames<C, FSet2> {
TypedDateTimeNames {
prefs: self.prefs,
inner: self.inner.with_fset(),
_calendar: PhantomData,
}
}
}

impl<FSet: DateTimeNamesMarker> RawDateTimeNames<FSet> {
pub(crate) fn new_without_number_formatting() -> Self {
Self {
year_names: <FSet::YearNames as DateTimeNamesHolderTrait<YearNamesV1Marker>>::Container::<_>::new_empty(),
month_names: <FSet::MonthNames as DateTimeNamesHolderTrait<MonthNamesV1Marker>>::Container::<_>::new_empty(),
weekday_names: <FSet::WeekdayNames as DateTimeNamesHolderTrait<WeekdayNamesV1Marker>>::Container::<_>::new_empty(),
dayperiod_names: <FSet::DayPeriodNames as DateTimeNamesHolderTrait<DayPeriodNamesV1Marker>>::Container::<_>::new_empty(),
zone_essentials: <FSet::ZoneEssentials as DateTimeNamesHolderTrait<tz::EssentialsV1Marker>>::Container::<_>::new_empty(),
locations_root: <FSet::ZoneLocations as DateTimeNamesHolderTrait<tz::LocationsV1Marker>>::Container::<_>::new_empty(),
locations: <FSet::ZoneLocations as DateTimeNamesHolderTrait<tz::LocationsV1Marker>>::Container::<_>::new_empty(),
mz_generic_long: <FSet::ZoneGenericLong as DateTimeNamesHolderTrait<tz::MzGenericLongV1Marker>>::Container::<_>::new_empty(),
mz_generic_short: <FSet::ZoneGenericShort as DateTimeNamesHolderTrait<tz::MzGenericShortV1Marker>>::Container::<_>::new_empty(),
mz_specific_long: <FSet::ZoneSpecificLong as DateTimeNamesHolderTrait<tz::MzSpecificLongV1Marker>>::Container::<_>::new_empty(),
mz_specific_short: <FSet::ZoneSpecificShort as DateTimeNamesHolderTrait<tz::MzSpecificShortV1Marker>>::Container::<_>::new_empty(),
mz_periods: <FSet::MetazoneLookup as DateTimeNamesHolderTrait<tz::MzPeriodV1Marker>>::Container::<_>::new_empty(),
year_names: <FSet::YearNames as NamesContainer<
YearNamesV1Marker,
FieldLength,
>>::Container::new_empty(),
month_names: <FSet::MonthNames as NamesContainer<
MonthNamesV1Marker,
(fields::Month, FieldLength),
>>::Container::new_empty(),
weekday_names: <FSet::WeekdayNames as NamesContainer<
WeekdayNamesV1Marker,
(fields::Weekday, FieldLength),
>>::Container::new_empty(),
dayperiod_names: <FSet::DayPeriodNames as NamesContainer<
DayPeriodNamesV1Marker,
FieldLength,
>>::Container::new_empty(),
zone_essentials: <FSet::ZoneEssentials as NamesContainer<
tz::EssentialsV1Marker,
(),
>>::Container::new_empty(),
locations_root: <FSet::ZoneLocations as NamesContainer<
tz::LocationsV1Marker,
(),
>>::Container::new_empty(),
locations: <FSet::ZoneLocations as NamesContainer<
tz::LocationsV1Marker,
(),
>>::Container::new_empty(),
mz_generic_long: <FSet::ZoneGenericLong as NamesContainer<
tz::MzGenericLongV1Marker,
(),
>>::Container::new_empty(),
mz_generic_short: <FSet::ZoneGenericShort as NamesContainer<
tz::MzGenericShortV1Marker,
(),
>>::Container::new_empty(),
mz_specific_long: <FSet::ZoneSpecificLong as NamesContainer<
tz::MzSpecificLongV1Marker,
(),
>>::Container::new_empty(),
mz_specific_short: <FSet::ZoneSpecificShort as NamesContainer<
tz::MzSpecificShortV1Marker,
(),
>>::Container::new_empty(),
mz_periods: <FSet::MetazoneLookup as NamesContainer<
tz::MzPeriodV1Marker,
(),
>>::Container::new_empty(),
fixed_decimal_formatter: None,
_marker: PhantomData,
}
Expand Down
3 changes: 2 additions & 1 deletion components/datetime/src/scaffold/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ pub use get_field::GetField;

pub use names_storage::DataPayloadWithVariables;
pub use names_storage::DataPayloadWithVariablesBorrowed;
pub use names_storage::DateTimeNamesHolderTrait;
pub use names_storage::DateTimeNamesFrom;
pub use names_storage::DateTimeNamesMarker;
pub use names_storage::MaybePayload;
pub use names_storage::MaybePayloadError;
pub use names_storage::NamesContainer;
pub(crate) use names_storage::OptionalNames;

/// Trait marking other traits that are considered unstable and should not generally be
Expand Down
Loading
Loading