use crate::error::DateTimeFormatterLoadError;
use crate::external_loaders::*;
use crate::fieldsets::enums::CompositeFieldSet;
use crate::format::datetime::try_write_pattern_items;
use crate::input::ExtractedInput;
use crate::pattern::*;
use crate::raw::neo::*;
use crate::scaffold::*;
use crate::scaffold::{
AllInputMarkers, ConvertCalendar, DateDataMarkers, DateInputMarkers, DateTimeMarkers, GetField,
InFixedCalendar, InSameCalendar, TimeMarkers, TypedDateDataMarkers, ZoneMarkers,
};
use crate::size_test_macro::size_test;
use crate::MismatchedCalendarError;
use core::fmt;
use core::marker::PhantomData;
use icu_calendar::any_calendar::IntoAnyCalendar;
use icu_calendar::{AnyCalendar, AnyCalendarPreferences};
use icu_decimal::FixedDecimalFormatterPreferences;
use icu_locale_core::preferences::extensions::unicode::keywords::{
CalendarAlgorithm, HourCycle, NumberingSystem,
};
use icu_locale_core::preferences::{define_preferences, prefs_convert};
use icu_provider::prelude::*;
use writeable::{impl_display_with_writeable, Writeable};
define_preferences!(
[Copy]
DateTimeFormatterPreferences,
{
numbering_system: NumberingSystem,
hour_cycle: HourCycle,
calendar_algorithm: CalendarAlgorithm
}
);
prefs_convert!(
DateTimeFormatterPreferences,
FixedDecimalFormatterPreferences,
{ numbering_system }
);
prefs_convert!(DateTimeFormatterPreferences, AnyCalendarPreferences, {
calendar_algorithm
});
macro_rules! gen_any_buffer_constructors_with_external_loader {
(@runtime_fset, $fset:ident, $compiled_fn:ident, $any_fn:ident, $buffer_fn:ident, $internal_fn:ident) => {
#[doc = icu_provider::gen_any_buffer_unstable_docs!(ANY, Self::$compiled_fn)]
pub fn $any_fn<P>(
provider: &P,
prefs: DateTimeFormatterPreferences,
field_set: $fset,
) -> Result<Self, DateTimeFormatterLoadError>
where
P: AnyProvider + ?Sized,
{
Self::$internal_fn(
&provider.as_downcasting(),
&ExternalLoaderAny(provider),
prefs,
field_set.get_field(),
)
}
#[doc = icu_provider::gen_any_buffer_unstable_docs!(BUFFER, Self::$compiled_fn)]
#[cfg(feature = "serde")]
pub fn $buffer_fn<P>(
provider: &P,
prefs: DateTimeFormatterPreferences,
field_set: $fset,
) -> Result<Self, DateTimeFormatterLoadError>
where
P: BufferProvider + ?Sized,
{
Self::$internal_fn(
&provider.as_deserializing(),
&ExternalLoaderBuffer(provider),
prefs,
field_set.get_field(),
)
}
};
(@compiletime_fset, $fset:ident, $compiled_fn:ident, $any_fn:ident, $buffer_fn:ident, $internal_fn:ident) => {
#[doc = icu_provider::gen_any_buffer_unstable_docs!(ANY, Self::$compiled_fn)]
pub fn $any_fn<P>(
provider: &P,
prefs: DateTimeFormatterPreferences,
field_set: $fset,
) -> Result<Self, DateTimeFormatterLoadError>
where
P: AnyProvider + ?Sized,
{
Self::$internal_fn(
&provider.as_downcasting(),
&ExternalLoaderAny(provider),
prefs,
field_set.get_field(),
)
}
#[doc = icu_provider::gen_any_buffer_unstable_docs!(BUFFER, Self::$compiled_fn)]
#[cfg(feature = "serde")]
pub fn $buffer_fn<P>(
provider: &P,
prefs: DateTimeFormatterPreferences,
field_set: $fset,
) -> Result<Self, DateTimeFormatterLoadError>
where
P: BufferProvider + ?Sized,
{
Self::$internal_fn(
&provider.as_deserializing(),
&ExternalLoaderBuffer(provider),
prefs,
field_set.get_field(),
)
}
};
}
size_test!(FixedCalendarDateTimeFormatter<icu_calendar::Gregorian, crate::fieldsets::YMD>, typed_neo_year_month_day_formatter_size, 344);
#[doc = typed_neo_year_month_day_formatter_size!()]
#[derive(Debug)]
pub struct FixedCalendarDateTimeFormatter<C: CldrCalendar, FSet: DateTimeNamesMarker> {
selection: DateTimeZonePatternSelectionData,
names: RawDateTimeNames<FSet>,
_calendar: PhantomData<C>,
}
impl<C: CldrCalendar, FSet: DateTimeMarkers> FixedCalendarDateTimeFormatter<C, FSet>
where
FSet::D: TypedDateDataMarkers<C>,
FSet::T: TimeMarkers,
FSet::Z: ZoneMarkers,
FSet: GetField<CompositeFieldSet>,
{
#[cfg(feature = "compiled_data")]
pub fn try_new(
prefs: DateTimeFormatterPreferences,
field_set: FSet,
) -> Result<Self, DateTimeFormatterLoadError>
where
crate::provider::Baked: AllFixedCalendarFormattingDataMarkers<C, FSet>,
{
Self::try_new_internal(
&crate::provider::Baked,
&ExternalLoaderCompiledData,
prefs,
field_set.get_field(),
)
}
gen_any_buffer_constructors_with_external_loader!(
@compiletime_fset,
FSet,
try_new,
try_new_with_any_provider,
try_new_with_buffer_provider,
try_new_internal
);
#[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new)]
pub fn try_new_unstable<P>(
provider: &P,
prefs: DateTimeFormatterPreferences,
field_set: FSet,
) -> Result<Self, DateTimeFormatterLoadError>
where
P: ?Sized
+ AllFixedCalendarFormattingDataMarkers<C, FSet>
+ AllFixedCalendarExternalDataMarkers,
{
Self::try_new_internal(
provider,
&ExternalLoaderUnstable(provider),
prefs,
field_set.get_field(),
)
}
}
impl<C: CldrCalendar, FSet: DateTimeMarkers> FixedCalendarDateTimeFormatter<C, FSet>
where
FSet::D: TypedDateDataMarkers<C>,
FSet::T: TimeMarkers,
FSet::Z: ZoneMarkers,
{
fn try_new_internal<P, L>(
provider: &P,
loader: &L,
prefs: DateTimeFormatterPreferences,
field_set: CompositeFieldSet,
) -> Result<Self, DateTimeFormatterLoadError>
where
P: ?Sized + AllFixedCalendarFormattingDataMarkers<C, FSet>,
L: FixedDecimalFormatterLoader,
{
let selection = DateTimeZonePatternSelectionData::try_new_with_skeleton(
&<FSet::D as TypedDateDataMarkers<C>>::DateSkeletonPatternsV1Marker::bind(provider),
&<FSet::T as TimeMarkers>::TimeSkeletonPatternsV1Marker::bind(provider),
&FSet::GluePatternV1Marker::bind(provider),
prefs,
field_set,
)
.map_err(DateTimeFormatterLoadError::Data)?;
let mut names = RawDateTimeNames::new_without_number_formatting();
names
.load_for_pattern(
&<FSet::D as TypedDateDataMarkers<C>>::YearNamesV1Marker::bind(provider),
&<FSet::D as TypedDateDataMarkers<C>>::MonthNamesV1Marker::bind(provider),
&<FSet::D as TypedDateDataMarkers<C>>::WeekdayNamesV1Marker::bind(provider),
&<FSet::T as TimeMarkers>::DayPeriodNamesV1Marker::bind(provider),
&<FSet::Z as ZoneMarkers>::EssentialsV1Marker::bind(provider),
&<FSet::Z as ZoneMarkers>::LocationsV1Marker::bind(provider),
&<FSet::Z as ZoneMarkers>::GenericLongV1Marker::bind(provider),
&<FSet::Z as ZoneMarkers>::GenericShortV1Marker::bind(provider),
&<FSet::Z as ZoneMarkers>::SpecificLongV1Marker::bind(provider),
&<FSet::Z as ZoneMarkers>::SpecificShortV1Marker::bind(provider),
&<FSet::Z as ZoneMarkers>::MetazonePeriodV1Marker::bind(provider),
loader, prefs,
selection.pattern_items_for_data_loading(),
)
.map_err(DateTimeFormatterLoadError::Names)?;
Ok(Self {
selection,
names,
_calendar: PhantomData,
})
}
}
impl<C: CldrCalendar, FSet: DateTimeMarkers> FixedCalendarDateTimeFormatter<C, FSet>
where
FSet::D: DateInputMarkers,
FSet::T: TimeMarkers,
FSet::Z: ZoneMarkers,
{
pub fn format<I>(&self, input: &I) -> FormattedDateTime
where
I: ?Sized + InFixedCalendar<C> + AllInputMarkers<FSet>,
{
let input = ExtractedInput::extract_from_neo_input::<FSet::D, FSet::T, FSet::Z, I>(input);
FormattedDateTime {
pattern: self.selection.select(&input),
input,
names: self.names.as_borrowed(),
}
}
}
size_test!(
DateTimeFormatter<crate::fieldsets::YMD>,
neo_year_month_day_formatter_size,
400
);
#[doc = neo_year_month_day_formatter_size!()]
#[derive(Debug)]
pub struct DateTimeFormatter<FSet: DateTimeNamesMarker> {
selection: DateTimeZonePatternSelectionData,
names: RawDateTimeNames<FSet>,
calendar: AnyCalendar,
}
impl<FSet: DateTimeMarkers> DateTimeFormatter<FSet>
where
FSet::D: DateDataMarkers,
FSet::T: TimeMarkers,
FSet::Z: ZoneMarkers,
FSet: GetField<CompositeFieldSet>,
{
#[inline(never)]
#[cfg(feature = "compiled_data")]
pub fn try_new(
prefs: DateTimeFormatterPreferences,
field_set: FSet,
) -> Result<Self, DateTimeFormatterLoadError>
where
crate::provider::Baked: AllAnyCalendarFormattingDataMarkers<FSet>,
{
Self::try_new_internal(
&crate::provider::Baked,
&ExternalLoaderCompiledData,
prefs,
field_set.get_field(),
)
}
gen_any_buffer_constructors_with_external_loader!(
@compiletime_fset,
FSet,
try_new,
try_new_with_any_provider,
try_new_with_buffer_provider,
try_new_internal
);
#[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new)]
pub fn try_new_unstable<P>(
provider: &P,
prefs: DateTimeFormatterPreferences,
field_set: FSet,
) -> Result<Self, DateTimeFormatterLoadError>
where
P: ?Sized + AllAnyCalendarFormattingDataMarkers<FSet> + AllAnyCalendarExternalDataMarkers,
{
Self::try_new_internal(
provider,
&ExternalLoaderUnstable(provider),
prefs,
field_set.get_field(),
)
}
}
impl<FSet: DateTimeMarkers> DateTimeFormatter<FSet>
where
FSet::D: DateDataMarkers,
FSet::T: TimeMarkers,
FSet::Z: ZoneMarkers,
{
fn try_new_internal<P, L>(
provider: &P,
loader: &L,
prefs: DateTimeFormatterPreferences,
field_set: CompositeFieldSet,
) -> Result<Self, DateTimeFormatterLoadError>
where
P: ?Sized + AllAnyCalendarFormattingDataMarkers<FSet>,
L: FixedDecimalFormatterLoader + AnyCalendarLoader,
{
let calendar = AnyCalendarLoader::load(loader, (&prefs).into())
.map_err(DateTimeFormatterLoadError::Data)?;
let kind = calendar.kind();
let selection = DateTimeZonePatternSelectionData::try_new_with_skeleton(
&AnyCalendarProvider::<<FSet::D as DateDataMarkers>::Skel, _>::new(provider, kind),
&<FSet::T as TimeMarkers>::TimeSkeletonPatternsV1Marker::bind(provider),
&FSet::GluePatternV1Marker::bind(provider),
prefs,
field_set,
)
.map_err(DateTimeFormatterLoadError::Data)?;
let mut names = RawDateTimeNames::new_without_number_formatting();
names
.load_for_pattern(
&AnyCalendarProvider::<<FSet::D as DateDataMarkers>::Year, _>::new(provider, kind),
&AnyCalendarProvider::<<FSet::D as DateDataMarkers>::Month, _>::new(provider, kind),
&<FSet::D as DateDataMarkers>::WeekdayNamesV1Marker::bind(provider),
&<FSet::T as TimeMarkers>::DayPeriodNamesV1Marker::bind(provider),
&<FSet::Z as ZoneMarkers>::EssentialsV1Marker::bind(provider),
&<FSet::Z as ZoneMarkers>::LocationsV1Marker::bind(provider),
&<FSet::Z as ZoneMarkers>::GenericLongV1Marker::bind(provider),
&<FSet::Z as ZoneMarkers>::GenericShortV1Marker::bind(provider),
&<FSet::Z as ZoneMarkers>::SpecificLongV1Marker::bind(provider),
&<FSet::Z as ZoneMarkers>::SpecificShortV1Marker::bind(provider),
&<FSet::Z as ZoneMarkers>::MetazonePeriodV1Marker::bind(provider),
loader, prefs,
selection.pattern_items_for_data_loading(),
)
.map_err(DateTimeFormatterLoadError::Names)?;
Ok(Self {
selection,
names,
calendar,
})
}
}
impl<FSet: DateTimeMarkers> DateTimeFormatter<FSet>
where
FSet::D: DateInputMarkers,
FSet::T: TimeMarkers,
FSet::Z: ZoneMarkers,
{
pub fn format_same_calendar<I>(
&self,
datetime: &I,
) -> Result<FormattedDateTime, crate::MismatchedCalendarError>
where
I: ?Sized + InSameCalendar + AllInputMarkers<FSet>,
{
datetime.check_any_calendar_kind(self.calendar.kind())?;
let datetime =
ExtractedInput::extract_from_neo_input::<FSet::D, FSet::T, FSet::Z, I>(datetime);
Ok(FormattedDateTime {
pattern: self.selection.select(&datetime),
input: datetime,
names: self.names.as_borrowed(),
})
}
pub fn format_any_calendar<'a, I>(&'a self, datetime: &I) -> FormattedDateTime<'a>
where
I: ?Sized + ConvertCalendar,
I::Converted<'a>: Sized + AllInputMarkers<FSet>,
{
let datetime = datetime.to_calendar(&self.calendar);
let datetime =
ExtractedInput::extract_from_neo_input::<FSet::D, FSet::T, FSet::Z, I::Converted<'a>>(
&datetime,
);
FormattedDateTime {
pattern: self.selection.select(&datetime),
input: datetime,
names: self.names.as_borrowed(),
}
}
}
impl<C: CldrCalendar, FSet: DateTimeMarkers> FixedCalendarDateTimeFormatter<C, FSet> {
pub fn into_formatter(self, calendar: C) -> DateTimeFormatter<FSet>
where
C: IntoAnyCalendar,
{
DateTimeFormatter {
selection: self.selection,
names: self.names,
calendar: calendar.to_any(),
}
}
}
impl<FSet: DateTimeMarkers> DateTimeFormatter<FSet> {
pub fn try_into_typed_formatter<C>(
self,
) -> Result<FixedCalendarDateTimeFormatter<C, FSet>, MismatchedCalendarError>
where
C: CldrCalendar + IntoAnyCalendar,
{
if let Err(cal) = C::from_any(self.calendar) {
return Err(MismatchedCalendarError {
this_kind: cal.kind(),
date_kind: None,
});
}
Ok(FixedCalendarDateTimeFormatter {
selection: self.selection,
names: self.names,
_calendar: PhantomData,
})
}
}
pub type TimeFormatter<FSet> = FixedCalendarDateTimeFormatter<(), FSet>;
#[derive(Debug)]
pub struct FormattedDateTime<'a> {
pattern: DateTimeZonePatternDataBorrowed<'a>,
input: ExtractedInput,
names: RawDateTimeNamesBorrowed<'a>,
}
impl Writeable for FormattedDateTime<'_> {
fn write_to_parts<S: writeable::PartsWrite + ?Sized>(
&self,
sink: &mut S,
) -> Result<(), fmt::Error> {
let result = try_write_pattern_items(
self.pattern.metadata(),
self.pattern.iter_items(),
&self.input,
&self.names,
self.names.fixed_decimal_formatter,
sink,
);
match result {
Ok(Ok(())) => Ok(()),
Err(fmt::Error) => Err(fmt::Error),
Ok(Err(e)) => {
debug_assert!(false, "unexpected error in FormattedDateTime: {e:?}");
Ok(())
}
}
}
}
impl_display_with_writeable!(FormattedDateTime<'_>);
impl FormattedDateTime<'_> {
pub fn pattern(&self) -> DateTimePattern {
self.pattern.to_pattern()
}
}