Skip to content

Commit

Permalink
Merge branch 'main' into normalizerdata
Browse files Browse the repository at this point in the history
  • Loading branch information
hsivonen authored Dec 17, 2024
2 parents b23c598 + 4bad030 commit abf8b9c
Show file tree
Hide file tree
Showing 76 changed files with 1,142 additions and 836 deletions.
6 changes: 6 additions & 0 deletions components/datetime/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ pub enum DateTimeFormatterLoadError {
Data(DataError),
}

impl From<DataError> for DateTimeFormatterLoadError {
fn from(error: DataError) -> Self {
Self::Data(error)
}
}

/// An error from mixing calendar types in a formatter.
#[derive(Display, Debug, Copy, Clone, PartialEq)]
#[displaydoc("DateTimeFormatter for {this_kind} calendar was given a {date_kind:?} calendar")]
Expand Down
32 changes: 31 additions & 1 deletion components/datetime/src/neo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::MismatchedCalendarError;
use core::fmt;
use core::marker::PhantomData;
use icu_calendar::any_calendar::IntoAnyCalendar;
use icu_calendar::{AnyCalendar, AnyCalendarPreferences};
use icu_calendar::{AnyCalendar, AnyCalendarKind, AnyCalendarPreferences};
use icu_decimal::FixedDecimalFormatterPreferences;
use icu_locale_core::preferences::extensions::unicode::keywords::{
CalendarAlgorithm, HourCycle, NumberingSystem,
Expand Down Expand Up @@ -765,6 +765,36 @@ impl<FSet: DateTimeMarkers> DateTimeFormatter<FSet> {
_calendar: PhantomData,
})
}

/// Returns the calendar system used in this formatter.
///
/// # Examples
///
/// ```
/// use icu::calendar::AnyCalendarKind;
/// use icu::calendar::Date;
/// use icu::datetime::fieldsets::YMD;
/// use icu::datetime::DateTimeFormatter;
/// use icu::locale::locale;
/// use writeable::assert_writeable_eq;
///
/// let formatter = DateTimeFormatter::try_new(
/// locale!("th").into(),
/// YMD::long(),
/// )
/// .unwrap();
///
/// assert_writeable_eq!(
/// formatter.format_any_calendar(&Date::try_new_iso(2024, 12, 16).unwrap()),
/// "16 ธันวาคม 2567"
/// );
///
/// assert_eq!(formatter.calendar_kind(), AnyCalendarKind::Buddhist);
/// assert_eq!(formatter.calendar_kind().as_bcp47_string(), "buddhist");
/// ```
pub fn calendar_kind(&self) -> AnyCalendarKind {
self.calendar.kind()
}
}

/// A formatter optimized for time and time zone formatting.
Expand Down
44 changes: 44 additions & 0 deletions components/decimal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ pub use format::FormattedFixedDecimal;

use alloc::string::String;
use fixed_decimal::SignedFixedDecimal;
use icu_locale_core::extensions::unicode::Value;
use icu_locale_core::locale;
use icu_locale_core::preferences::{
define_preferences, extensions::unicode::keywords::NumberingSystem,
Expand Down Expand Up @@ -214,4 +215,47 @@ impl FixedDecimalFormatter {
pub fn format_to_string(&self, value: &SignedFixedDecimal) -> String {
self.format(value).write_to_string().into_owned()
}

/// Gets the resolved numbering system identifier of this formatter.
///
/// # Examples
///
/// ```
/// use icu::decimal::FixedDecimalFormatter;
/// use icu::locale::locale;
///
/// let fmt_en = FixedDecimalFormatter::try_new(
/// locale!("en").into(),
/// Default::default()
/// )
/// .unwrap();
///
/// let fmt_bn = FixedDecimalFormatter::try_new(
/// locale!("bn").into(),
/// Default::default()
/// )
/// .unwrap();
///
/// let fmt_zh_nu = FixedDecimalFormatter::try_new(
/// locale!("zh-u-nu-hanidec").into(),
/// Default::default()
/// )
/// .unwrap();
///
/// assert_eq!(fmt_en.numbering_system(), "latn");
/// assert_eq!(fmt_bn.numbering_system(), "beng");
/// assert_eq!(fmt_zh_nu.numbering_system(), "hanidec");
/// ```
pub fn numbering_system(&self) -> Value {
match Value::try_from_str(self.symbols.get().numsys()) {
Ok(v) => v,
Err(e) => {
debug_assert!(
false,
"Problem converting numbering system ID to Value: {e}"
);
Value::new_empty()
}
}
}
}
13 changes: 13 additions & 0 deletions components/locale_core/src/extensions/unicode/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,19 @@ impl Value {
self.0.len()
}

/// Creates an empty [`Value`], which corresponds to a "true" value.
///
/// # Examples
///
/// ```
/// use icu::locale::extensions::unicode::{value, Value};
///
/// assert_eq!(value!("true"), Value::new_empty());
/// ```
pub const fn new_empty() -> Self {
Self(ShortBoxSlice::new())
}

/// Returns `true` if the Value has no subtags.
///
/// # Examples
Expand Down
141 changes: 111 additions & 30 deletions components/pattern/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).

use crate::Error;
use writeable::{Part, TryWriteable};
use writeable::{TryWriteable, Writeable};

#[cfg(feature = "alloc")]
use alloc::{borrow::Cow, boxed::Box};
Expand Down Expand Up @@ -110,56 +110,137 @@ pub trait PatternBackend: crate::private::Sealed + 'static + core::fmt::Debug {
fn empty() -> &'static Self::Store;
}

/// Default annotation for the literal portion of a pattern.
/// Trait implemented on collections that can produce [`TryWriteable`]s for interpolation.
///
/// For more information, see [`PlaceholderValueProvider`]. For an example, see [`Pattern`].
/// This trait can add [`Part`]s for individual literals or placeholders. The implementations
/// of this trait on standard types do not add any [`Part`]s.
///
/// [`Pattern`]: crate::Pattern
pub const PATTERN_LITERAL_PART: Part = Part {
category: "pattern",
value: "literal",
};

/// Default annotation for the placeholder portion of a pattern.
/// # Examples
///
/// For more information, see [`PlaceholderValueProvider`]. For an example, see [`Pattern`].
/// A custom implementation that adds parts:
///
/// [`Pattern`]: crate::Pattern
pub const PATTERN_PLACEHOLDER_PART: Part = Part {
category: "pattern",
value: "placeholder",
};

/// Trait implemented on collections that can produce [`TryWriteable`]s for interpolation.
/// ```
/// use core::str::FromStr;
/// use icu_pattern::Pattern;
/// use icu_pattern::DoublePlaceholder;
/// use icu_pattern::DoublePlaceholderKey;
/// use icu_pattern::PlaceholderValueProvider;
/// use writeable::adapters::WithPart;
/// use writeable::adapters::WriteableAsTryWriteableInfallible;
/// use writeable::assert_writeable_parts_eq;
/// use writeable::Part;
/// use writeable::Writeable;
///
/// let pattern = Pattern::<DoublePlaceholder>::try_from_str(
/// "Hello, {0} and {1}!",
/// Default::default(),
/// )
/// .unwrap();
///
/// struct ValuesWithParts<'a>(&'a str, &'a str);
///
/// const PART_PLACEHOLDER_0: Part = Part {
/// category: "custom",
/// value: "placeholder0",
/// };
/// const PART_PLACEHOLDER_1: Part = Part {
/// category: "custom",
/// value: "placeholder1",
/// };
/// const PART_LITERAL: Part = Part {
/// category: "custom",
/// value: "literal",
/// };
///
/// impl PlaceholderValueProvider<DoublePlaceholderKey> for ValuesWithParts<'_> {
/// type Error = core::convert::Infallible;
///
/// type W<'a> = WriteableAsTryWriteableInfallible<WithPart<&'a str>>
/// where
/// Self: 'a;
///
/// type L<'a, 'l> = WithPart<&'l str>
/// where
/// Self: 'a;
///
/// #[inline]
/// fn value_for(&self, key: DoublePlaceholderKey) -> Self::W<'_> {
/// let writeable = match key {
/// DoublePlaceholderKey::Place0 => WithPart {
/// writeable: self.0,
/// part: PART_PLACEHOLDER_0,
/// },
/// DoublePlaceholderKey::Place1 => WithPart {
/// writeable: self.1,
/// part: PART_PLACEHOLDER_1,
/// },
/// };
/// WriteableAsTryWriteableInfallible(writeable)
/// }
///
/// #[inline]
/// fn map_literal<'a, 'l>(&'a self, literal: &'l str) -> Self::L<'a, 'l> {
/// WithPart {
/// writeable: literal,
/// part: PART_LITERAL,
/// }
/// }
/// }
///
/// This trait determines the [`Part`]s produced by the writeable. In this crate, implementations
/// of this trait default to using [`PATTERN_LITERAL_PART`] and [`PATTERN_PLACEHOLDER_PART`].
/// assert_writeable_parts_eq!(
/// pattern.interpolate(ValuesWithParts("Alice", "Bob")),
/// "Hello, Alice and Bob!",
/// [
/// (0, 7, PART_LITERAL),
/// (7, 12, PART_PLACEHOLDER_0),
/// (12, 17, PART_LITERAL),
/// (17, 20, PART_PLACEHOLDER_1),
/// (20, 21, PART_LITERAL),
/// ]
/// );
/// ```
///
/// [`Part`]: writeable::Part
pub trait PlaceholderValueProvider<K> {
type Error;

type W<'a>: TryWriteable<Error = Self::Error>
where
Self: 'a;

const LITERAL_PART: Part;
type L<'a, 'l>: Writeable
where
Self: 'a;

/// Returns the [`TryWriteable`] to substitute for the given placeholder
/// and the [`Part`] representing it.
fn value_for(&self, key: K) -> (Self::W<'_>, Part);
/// Returns the [`TryWriteable`] to substitute for the given placeholder.
///
/// See [`PatternItem::Placeholder`]
fn value_for(&self, key: K) -> Self::W<'_>;

/// Maps a literal string to a [`Writeable`] that could contain parts.
///
/// See [`PatternItem::Literal`]
fn map_literal<'a, 'l>(&'a self, literal: &'l str) -> Self::L<'a, 'l>;
}

impl<'b, K, T> PlaceholderValueProvider<K> for &'b T
where
T: PlaceholderValueProvider<K> + ?Sized,
{
type Error = T::Error;
type W<'a>
= T::W<'a>

type W<'a> = T::W<'a>
where
T: 'a,
'b: 'a;
const LITERAL_PART: Part = T::LITERAL_PART;
fn value_for(&self, key: K) -> (Self::W<'_>, Part) {
Self: 'a;

type L<'a, 'l> = T::L<'a, 'l>
where
Self: 'a;

fn value_for(&self, key: K) -> Self::W<'_> {
(*self).value_for(key)
}
fn map_literal<'a, 'l>(&'a self, literal: &'l str) -> Self::L<'a, 'l> {
(*self).map_literal(literal)
}
}
47 changes: 28 additions & 19 deletions components/pattern/src/double.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,22 +75,26 @@ where
W1: Writeable,
{
type Error = Infallible;
type W<'a>
= WriteableAsTryWriteableInfallible<Either<&'a W0, &'a W1>>

type W<'a> = WriteableAsTryWriteableInfallible<Either<&'a W0, &'a W1>>
where
Self: 'a;

type L<'a, 'l> = &'l str
where
W0: 'a,
W1: 'a;
const LITERAL_PART: writeable::Part = crate::PATTERN_LITERAL_PART;
Self: 'a;

#[inline]
fn value_for(&self, key: DoublePlaceholderKey) -> (Self::W<'_>, writeable::Part) {
fn value_for(&self, key: DoublePlaceholderKey) -> Self::W<'_> {
let writeable = match key {
DoublePlaceholderKey::Place0 => Either::Left(&self.0),
DoublePlaceholderKey::Place1 => Either::Right(&self.1),
};
(
WriteableAsTryWriteableInfallible(writeable),
crate::PATTERN_PLACEHOLDER_PART,
)
WriteableAsTryWriteableInfallible(writeable)
}
#[inline]
fn map_literal<'a, 'l>(&'a self, literal: &'l str) -> Self::L<'a, 'l> {
literal
}
}

Expand All @@ -99,22 +103,27 @@ where
W: Writeable,
{
type Error = Infallible;
type W<'a>
= WriteableAsTryWriteableInfallible<&'a W>

type W<'a> = WriteableAsTryWriteableInfallible<&'a W>
where
Self: 'a;

type L<'a, 'l> = &'l str
where
W: 'a;
const LITERAL_PART: writeable::Part = crate::PATTERN_LITERAL_PART;
Self: 'a;

#[inline]
fn value_for(&self, key: DoublePlaceholderKey) -> (Self::W<'_>, writeable::Part) {
fn value_for(&self, key: DoublePlaceholderKey) -> Self::W<'_> {
let [item0, item1] = self;
let writeable = match key {
DoublePlaceholderKey::Place0 => item0,
DoublePlaceholderKey::Place1 => item1,
};
(
WriteableAsTryWriteableInfallible(writeable),
crate::PATTERN_PLACEHOLDER_PART,
)
WriteableAsTryWriteableInfallible(writeable)
}
#[inline]
fn map_literal<'a, 'l>(&'a self, literal: &'l str) -> Self::L<'a, 'l> {
literal
}
}

Expand Down
Loading

0 comments on commit abf8b9c

Please sign in to comment.