Skip to content

Commit

Permalink
Implement SignedFixedDecimal and UnsignedFixedDecimal (#5667)
Browse files Browse the repository at this point in the history
  • Loading branch information
younies authored Nov 26, 2024
1 parent 9cb01e4 commit d518671
Show file tree
Hide file tree
Showing 102 changed files with 7,729 additions and 3,888 deletions.
39 changes: 24 additions & 15 deletions components/datetime/src/format/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::provider::pattern::runtime::PatternMetadata;
use crate::provider::pattern::PatternItem;

use core::fmt::{self, Write};
use fixed_decimal::FixedDecimal;
use fixed_decimal::SignedFixedDecimal;
use icu_calendar::types::{DayOfWeekInMonth, IsoWeekday};
use icu_decimal::FixedDecimalFormatter;
use writeable::{Part, Writeable};
Expand All @@ -20,7 +20,7 @@ use writeable::{Part, Writeable};
fn try_write_number<W>(
result: &mut W,
fixed_decimal_format: Option<&FixedDecimalFormatter>,
mut num: FixedDecimal,
mut num: SignedFixedDecimal,
length: FieldLength,
) -> Result<Result<(), DateTimeWriteError>, fmt::Error>
where
Expand Down Expand Up @@ -115,7 +115,7 @@ where
}
(FieldSymbol::Year(Year::Calendar), l) => {
input!(year = input.year);
let mut year = FixedDecimal::from(year.era_year_or_extended());
let mut year = SignedFixedDecimal::from(year.era_year_or_extended());
if matches!(l, FieldLength::Two) {
// 'yy' and 'YY' truncate
year.set_max_position(2);
Expand Down Expand Up @@ -157,9 +157,12 @@ where
input!(related_iso = year.related_iso());

// Always in latin digits according to spec
FixedDecimal::from(related_iso)
.padded_start(l.to_len() as i16)
.write_to(w)?;
{
let mut num = SignedFixedDecimal::from(related_iso);
num.pad_start(l.to_len() as i16);
num
}
.write_to(w)?;
Ok(())
}
(FieldSymbol::Month(_), l @ (FieldLength::One | FieldLength::Two)) => {
Expand All @@ -180,17 +183,20 @@ where
Ok(MonthPlaceholderValue::NumericPattern(substitution_pattern)) => {
debug_assert!(l == FieldLength::One);
if let Some(fdf) = fdf {
let mut num = SignedFixedDecimal::from(month.ordinal);
num.pad_start(l.to_len() as i16);
substitution_pattern
.interpolate([fdf.format(
&FixedDecimal::from(month.ordinal).padded_start(l.to_len() as i16),
)])
.interpolate([fdf.format(&num)])
.write_to(w)?;
Ok(())
} else {
w.with_part(Part::ERROR, |w| {
substitution_pattern
.interpolate([FixedDecimal::from(month.ordinal)
.padded_start(l.to_len() as i16)])
.interpolate([{
let mut num = SignedFixedDecimal::from(month.ordinal);
num.pad_start(l.to_len() as i16);
num
}])
.write_to(w)
})?;
Err(DateTimeWriteError::FixedDecimalFormatterNotLoaded)
Expand Down Expand Up @@ -295,9 +301,12 @@ where
input!(nanosecond = input.nanosecond);

// Formatting with fractional seconds
let mut s = FixedDecimal::from(second.number());
let _infallible =
s.concatenate_end(FixedDecimal::from(nanosecond.number()).multiplied_pow10(-9));
let mut s = SignedFixedDecimal::from(second.number());
let _infallible = s.concatenate_end(
SignedFixedDecimal::from(nanosecond.number())
.absolute
.multiplied_pow10(-9),
);
debug_assert!(_infallible.is_ok());
let position = -(decimal_second as i16);
s.trunc(position);
Expand Down Expand Up @@ -514,7 +523,7 @@ mod tests {
try_write_number(
&mut writeable::adapters::CoreWriteAsPartsWrite(&mut s),
Some(&fixed_decimal_format),
FixedDecimal::from(*value),
SignedFixedDecimal::from(*value),
*length,
)
.unwrap()
Expand Down
66 changes: 38 additions & 28 deletions components/datetime/src/format/time_zone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::pattern::TimeZoneDataPayloadsBorrowed;
use crate::provider::time_zones::MetazoneId;
use crate::{fields::FieldLength, input::ExtractedInput};
use core::fmt;
use fixed_decimal::FixedDecimal;
use fixed_decimal::SignedFixedDecimal;
use icu_calendar::{Date, Iso, Time};
use icu_decimal::FixedDecimalFormatter;
use icu_timezone::provider::EPOCH;
Expand Down Expand Up @@ -241,33 +241,34 @@ impl FormatTimeZone for LocalizedOffsetFormat {
&self,
sink: &mut S,
) -> fmt::Result {
self.fdf
.format(
&FixedDecimal::from(self.offset.hours_part())
.with_sign_display(fixed_decimal::SignDisplay::Always)
.padded_start(if self.length == FieldLength::Four {
2
} else {
0
}),
)
.write_to(sink)?;
let fd = {
let mut fd = SignedFixedDecimal::from(self.offset.hours_part())
.with_sign_display(fixed_decimal::SignDisplay::Always);
fd.pad_start(if self.length == FieldLength::Four {
2
} else {
0
});
fd
};
self.fdf.format(&fd).write_to(sink)?;

if self.length == FieldLength::Four
|| self.offset.minutes_part() != 0
|| self.offset.seconds_part() != 0
{
let mut signed_fdf = SignedFixedDecimal::from(self.offset.minutes_part());
signed_fdf.absolute.pad_start(2);
sink.write_str(self.separator)?;
self.fdf
.format(&FixedDecimal::from(self.offset.minutes_part()).padded_start(2))
.write_to(sink)?;
self.fdf.format(&signed_fdf).write_to(sink)?;
}

if self.offset.seconds_part() != 0 {
sink.write_str(self.separator)?;
self.fdf
.format(&FixedDecimal::from(self.offset.seconds_part()).padded_start(2))
.write_to(sink)?;

let mut signed_fdf = SignedFixedDecimal::from(self.offset.seconds_part());
signed_fdf.absolute.pad_start(2);
self.fdf.format(&signed_fdf).write_to(sink)?;
}

Ok(())
Expand Down Expand Up @@ -579,29 +580,38 @@ impl Iso8601Format {
}

// Always in latin digits according to spec
FixedDecimal::from(offset.hours_part())
.padded_start(2)
.with_sign_display(fixed_decimal::SignDisplay::Always)
.write_to(sink)?;
{
let mut fd = SignedFixedDecimal::from(offset.hours_part())
.with_sign_display(fixed_decimal::SignDisplay::Always);
fd.pad_start(2);
fd
}
.write_to(sink)?;

if self.minutes == IsoMinutes::Required
|| (self.minutes == IsoMinutes::Optional && offset.minutes_part() != 0)
{
if self.extended {
sink.write_char(':')?;
}
FixedDecimal::from(offset.minutes_part())
.padded_start(2)
.write_to(sink)?;
{
let mut fd = SignedFixedDecimal::from(offset.minutes_part());
fd.pad_start(2);
fd
}
.write_to(sink)?;
}

if self.seconds == IsoSeconds::Optional && offset.seconds_part() != 0 {
if self.extended {
sink.write_char(':')?;
}
FixedDecimal::from(offset.seconds_part())
.padded_start(2)
.write_to(sink)?;
{
let mut fd = SignedFixedDecimal::from(offset.seconds_part());
fd.pad_start(2);
fd
}
.write_to(sink)?;
}

Ok(())
Expand Down
16 changes: 10 additions & 6 deletions components/decimal/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions components/decimal/benches/fixed_decimal_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rand_pcg::Lcg64Xsh32;

use criterion::{black_box, criterion_group, criterion_main, Criterion};

use fixed_decimal::FixedDecimal;
use fixed_decimal::SignedFixedDecimal;
use icu_decimal::{FixedDecimalFormatter, FixedDecimalFormatterPreferences};
use icu_locale_core::locale;

Expand All @@ -34,7 +34,7 @@ fn overview_bench(c: &mut Criterion) {
// ranging from -1e9 to 1e9.
let fdf = FixedDecimalFormatter::try_new(prefs, options).unwrap();
for &num in &nums {
let fd = FixedDecimal::from(black_box(num));
let fd = SignedFixedDecimal::from(black_box(num));
fdf.format_to_string(&fd);
}
});
Expand Down
6 changes: 3 additions & 3 deletions components/decimal/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
use crate::grouper;
use crate::options::*;
use crate::provider::*;
use fixed_decimal::FixedDecimal;
use fixed_decimal::Sign;
use fixed_decimal::SignedFixedDecimal;
use writeable::Writeable;

/// An intermediate structure returned by [`FixedDecimalFormatter`](crate::FixedDecimalFormatter).
/// Use [`Writeable`][Writeable] to render the formatted decimal to a string or buffer.
#[derive(Debug, PartialEq, Clone)]
pub struct FormattedFixedDecimal<'l> {
pub(crate) value: &'l FixedDecimal,
pub(crate) value: &'l SignedFixedDecimal,
pub(crate) options: &'l FixedDecimalFormatterOptions,
pub(crate) symbols: &'l DecimalSymbolsV2<'l>,
pub(crate) digits: &'l DecimalDigitsV1,
Expand All @@ -41,7 +41,7 @@ impl Writeable for FormattedFixedDecimal<'_> {
if let Some(affixes) = affixes {
sink.write_str(affixes.0)?;
}
let range = self.value.magnitude_range();
let range = self.value.absolute.magnitude_range();
let upper_magnitude = *range.end();
for m in range.rev() {
if m == -1 {
Expand Down
8 changes: 6 additions & 2 deletions components/decimal/src/grouper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ fn test_grouper() {
use crate::options;
use crate::provider::*;
use crate::FixedDecimalFormatter;
use fixed_decimal::FixedDecimal;
use fixed_decimal::SignedFixedDecimal;
use icu_provider::prelude::*;
use icu_provider_adapters::fixed::FixedProvider;
use icu_provider_adapters::fork::ForkByMarkerProvider;
Expand Down Expand Up @@ -154,7 +154,11 @@ fn test_grouper() {
];
for cas in &cases {
for i in 0..4 {
let dec = FixedDecimal::from(1).multiplied_pow10((i as i16) + 3);
let dec = {
let mut dec = SignedFixedDecimal::from(1);
dec.multiply_pow10((i as i16) + 3);
dec
};
let provider_symbols = FixedProvider::<DecimalSymbolsV2Marker>::from_owned(
crate::provider::DecimalSymbolsV2 {
grouping_sizes: cas.sizes,
Expand Down
Loading

0 comments on commit d518671

Please sign in to comment.