Skip to content

Commit 40b418c

Browse files
authored
(icu_datagen 1.4.1) Remove fraction dep from icu_datagen (unicode-org#4472)
Backports unicode-org#4459 and unicode-org#4458 Backport approved in unicode-org#4458 Unlike that PR, this makes these deps dev-deps since they're not yet used by an experimental feature
1 parent cd9cf17 commit 40b418c

File tree

5 files changed

+74
-90
lines changed

5 files changed

+74
-90
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## icu4x 1.4.x
4+
- [Remove icu_datagen's dep on `fractional`](https://github.com/unicode-org/icu4x/pull/4472)
5+
6+
37
## icu4x 1.4 (Nov 16, 2023)
48

59
- General

Cargo.lock

Lines changed: 2 additions & 35 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

provider/datagen/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ edition.workspace = true
2626
homepage.workspace = true
2727
repository.workspace = true
2828
rust-version.workspace = true
29-
version.workspace = true
29+
version = "1.4.1"
3030

3131
[package.metadata.docs.rs]
3232
all-features = true
@@ -87,8 +87,6 @@ zip = { version = ">=0.5, <0.7", default-features = false, features = ["deflate"
8787
rayon = { version = "1.5", optional = true }
8888
ureq = { version = "2", optional = true }
8989

90-
fraction = {version = "0.14.0", default-features = false }
91-
num-bigint = { version = "0.4.4", default-features = false }
9290

9391

9492
# Dependencies for "bin" feature
@@ -102,6 +100,8 @@ crlify = { path = "../../utils/crlify" }
102100
icu = { path = "../../components/icu" }
103101
postcard = "1"
104102
simple_logger = { version = "4.1.0", default-features = false }
103+
num-bigint = { version = "0.4.4", default-features = false }
104+
num-rational = { version = "0.4", default-features = false }
105105

106106
# Pre-experimental components with limited data generation
107107
icu_singlenumberformatter = { path = "../../experimental/singlenumberformatter", features = ["datagen"] }

provider/datagen/src/transform/cldr/units/helpers.rs

Lines changed: 59 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ use core::ops::{Div, Mul};
66
use core::str::FromStr;
77
use std::collections::{BTreeMap, VecDeque};
88

9-
use fraction::GenericFraction;
109
use icu_provider::DataError;
1110
use icu_unitsconversion::provider::{ConversionInfo, Exactness, Sign};
12-
use num_bigint::BigUint;
11+
use num_bigint::BigInt;
12+
use num_rational::Ratio;
1313

1414
use crate::transform::cldr::cldr_serde::units::units_constants::Constant;
1515

@@ -273,9 +273,7 @@ pub fn process_constants<'a>(
273273
/// - " 1.5 E -2 " is converted to 15/1000
274274
/// - " 1.5 E - 2" is an invalid scientific notation number
275275
/// - "1.5E-2.5" is an invalid scientific notation number
276-
pub fn convert_scientific_notation_to_fraction(
277-
number: &str,
278-
) -> Result<GenericFraction<BigUint>, DataError> {
276+
pub fn convert_scientific_notation_to_fraction(number: &str) -> Result<Ratio<BigInt>, DataError> {
279277
let mut parts = number.split('E');
280278
let base = parts.next().unwrap_or("1").trim();
281279
let exponent = parts.next().unwrap_or("0").trim();
@@ -285,51 +283,70 @@ pub fn convert_scientific_notation_to_fraction(
285283
));
286284
}
287285

288-
let base = GenericFraction::<BigUint>::from_str(base)
289-
.map_err(|_| DataError::custom("the base is not a valid decimal number"))?;
286+
let mut split = base.split('.');
287+
let base_whole = split.next().ok_or(DataError::custom("the base is empty"))?;
288+
let base_whole = if base_whole.is_empty() {
289+
BigInt::from(0)
290+
} else {
291+
BigInt::from_str(base_whole).map_err(|_| {
292+
DataError::custom("the whole part of the base is not a valid whole number")
293+
})?
294+
};
295+
296+
let base_dec = if let Some(dec_str) = split.next() {
297+
let dec = BigInt::from_str(dec_str).map_err(|_| {
298+
DataError::custom("the decimal part of the base is not a valid whole number")
299+
})?;
300+
let exp = dec_str.chars().filter(char::is_ascii_digit).count();
301+
Ratio::new(dec, BigInt::from(10u32).pow(exp as u32))
302+
} else {
303+
Ratio::new(BigInt::from(0), BigInt::from(1))
304+
};
305+
306+
let base = base_dec + base_whole;
307+
290308
let exponent = i32::from_str(exponent)
291309
.map_err(|_| DataError::custom("the exponent is not a valid integer"))?;
292310

293311
let result = if exponent >= 0 {
294-
base.mul(GenericFraction::new(
295-
BigUint::from(10u32).pow(exponent as u32),
296-
BigUint::from(1u32),
312+
base.mul(Ratio::new(
313+
BigInt::from(10u32).pow(exponent as u32),
314+
BigInt::from(1u32),
297315
))
298316
} else {
299-
base.div(GenericFraction::new(
300-
BigUint::from(10u32).pow((-exponent) as u32),
301-
BigUint::from(1u32),
317+
base.div(Ratio::new(
318+
BigInt::from(10u32).pow((-exponent) as u32),
319+
BigInt::from(1u32),
302320
))
303321
};
304-
305322
Ok(result)
306323
}
307324

308325
// TODO: move this to the comment above.
309326
#[test]
310327
fn test_convert_scientific_notation_to_fraction() {
311328
let input = "1E2";
312-
let expected = GenericFraction::<BigUint>::new(BigUint::from(100u32), BigUint::from(1u32));
329+
let expected = Ratio::<BigInt>::new(BigInt::from(100u32), BigInt::from(1u32));
313330
let actual = convert_scientific_notation_to_fraction(input).unwrap();
314331
assert_eq!(expected, actual);
315332

316333
let input = "1E-2";
317-
let expected = GenericFraction::<BigUint>::new(BigUint::from(1u32), BigUint::from(100u32));
334+
let expected = Ratio::<BigInt>::new(BigInt::from(1u32), BigInt::from(100u32));
318335
let actual = convert_scientific_notation_to_fraction(input).unwrap();
319336
assert_eq!(expected, actual);
320337

321338
let input = "1.5E2";
322-
let expected = GenericFraction::<BigUint>::new(BigUint::from(150u32), BigUint::from(1u32));
339+
let expected = Ratio::<BigInt>::new(BigInt::from(150u32), BigInt::from(1u32));
323340
let actual = convert_scientific_notation_to_fraction(input).unwrap();
324341
assert_eq!(expected, actual);
325342

326343
let input = "1.5E-2";
327-
let expected = GenericFraction::<BigUint>::new(BigUint::from(15u32), BigUint::from(1000u32));
344+
let expected = Ratio::<BigInt>::new(BigInt::from(15u32), BigInt::from(1000u32));
328345
let actual = convert_scientific_notation_to_fraction(input).unwrap();
329346
assert_eq!(expected, actual);
330347

331348
let input = " 1.5 E -2 ";
332-
let expected = GenericFraction::<BigUint>::new(BigUint::from(15u32), BigUint::from(1000u32));
349+
let expected = Ratio::<BigInt>::new(BigInt::from(15u32), BigInt::from(1000u32));
333350
let actual = convert_scientific_notation_to_fraction(input).unwrap();
334351
assert_eq!(expected, actual);
335352

@@ -340,6 +357,11 @@ fn test_convert_scientific_notation_to_fraction() {
340357
let input = "1.5E-2.5";
341358
let actual = convert_scientific_notation_to_fraction(input);
342359
assert!(actual.is_err());
360+
361+
let input = "0.308";
362+
let expected = Ratio::<BigInt>::new(BigInt::from(308), BigInt::from(1000u32));
363+
let actual = convert_scientific_notation_to_fraction(input).unwrap();
364+
assert_eq!(expected, actual);
343365
}
344366

345367
/// Determines if a string contains any alphabetic characters.
@@ -390,28 +412,19 @@ pub fn is_scientific_number(s: &str) -> bool {
390412
}
391413

392414
/// Transforms a fractional number into byte numerators, byte denominators, and a sign.
393-
pub fn flatten_fraction(
394-
fraction: GenericFraction<BigUint>,
395-
) -> Result<(Vec<u8>, Vec<u8>, Sign), DataError> {
396-
let numerator = match fraction.numer() {
397-
Some(numerator) => numerator.to_bytes_le(),
398-
None => return Err(DataError::custom("the numerator is too large")),
399-
};
400-
401-
let denominator = match fraction.denom() {
402-
Some(denominator) => denominator.to_bytes_le(),
403-
None => return Err(DataError::custom("the denominator is too large")),
404-
};
405-
406-
let sign = match fraction.sign() {
407-
Some(fraction::Sign::Plus) => Sign::Positive,
408-
Some(fraction::Sign::Minus) => Sign::Negative,
409-
None => {
410-
return Err(DataError::custom("the sign is not defined"));
411-
}
415+
pub fn flatten_fraction(fraction: Ratio<BigInt>) -> Result<(Vec<u8>, Vec<u8>, Sign), DataError> {
416+
let (n_sign, numer) = fraction.numer().to_bytes_le();
417+
let (d_sign, denom) = fraction.denom().to_bytes_le();
418+
419+
// Ratio's constructor sets denom > 0 but it's worth
420+
// checking in case we decide to switch to new_raw() to avoid reducing
421+
let sign = if n_sign * d_sign == num_bigint::Sign::Minus {
422+
Sign::Negative
423+
} else {
424+
Sign::Positive
412425
};
413426

414-
Ok((numerator, denominator, sign))
427+
Ok((numer, denom, sign))
415428
}
416429

417430
/// Converts slices of numerator and denominator strings to a fraction.
@@ -425,8 +438,8 @@ pub fn flatten_fraction(
425438
pub fn convert_slices_to_fraction(
426439
numerator_strings: &[&str],
427440
denominator_strings: &[&str],
428-
) -> Result<GenericFraction<BigUint>, DataError> {
429-
let mut fraction = GenericFraction::new(BigUint::from(1u32), BigUint::from(1u32));
441+
) -> Result<Ratio<BigInt>, DataError> {
442+
let mut fraction = Ratio::new(BigInt::from(1u32), BigInt::from(1u32));
430443

431444
for numerator in numerator_strings {
432445
let num_fraction = convert_scientific_notation_to_fraction(numerator)?;
@@ -446,19 +459,19 @@ pub fn convert_slices_to_fraction(
446459
fn test_convert_array_of_strings_to_fraction() {
447460
let numerator: Vec<&str> = vec!["1"];
448461
let denominator: Vec<&str> = vec!["2"];
449-
let expected = GenericFraction::new(BigUint::from(1u32), BigUint::from(2u32));
462+
let expected = Ratio::new(BigInt::from(1i32), BigInt::from(2i32));
450463
let actual = convert_slices_to_fraction(&numerator, &denominator).unwrap();
451464
assert_eq!(expected, actual);
452465

453466
let numerator = vec!["1", "2"];
454467
let denominator = vec!["3", "1E2"];
455-
let expected = GenericFraction::new(BigUint::from(2u32), BigUint::from(300u32));
468+
let expected = Ratio::new(BigInt::from(2i32), BigInt::from(300i32));
456469
let actual = convert_slices_to_fraction(&numerator, &denominator).unwrap();
457470
assert_eq!(expected, actual);
458471

459472
let numerator = vec!["1", "2"];
460473
let denominator = vec!["3", "1E-2"];
461-
let expected = GenericFraction::new(BigUint::from(200u32), BigUint::from(3u32));
474+
let expected = Ratio::new(BigInt::from(200i32), BigInt::from(3i32));
462475
let actual = convert_slices_to_fraction(&numerator, &denominator).unwrap();
463476
assert_eq!(expected, actual);
464477

@@ -469,13 +482,13 @@ fn test_convert_array_of_strings_to_fraction() {
469482

470483
let numerator = vec!["1E2"];
471484
let denominator = vec!["2"];
472-
let expected = GenericFraction::new(BigUint::from(50u32), BigUint::from(1u32));
485+
let expected = Ratio::new(BigInt::from(50i32), BigInt::from(1i32));
473486
let actual = convert_slices_to_fraction(&numerator, &denominator).unwrap();
474487
assert_eq!(expected, actual);
475488

476489
let numerator = vec!["1E2", "2"];
477490
let denominator = vec!["3", "1E2"];
478-
let expected = GenericFraction::new(BigUint::from(2u32), BigUint::from(3u32));
491+
let expected = Ratio::new(BigInt::from(2i32), BigInt::from(3i32));
479492
let actual = convert_slices_to_fraction(&numerator, &denominator).unwrap();
480493
assert_eq!(expected, actual);
481494
}

provider/datagen/src/transform/cldr/units/info.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
use std::{borrow::Cow, collections::BTreeMap};
66

77
use crate::transform::cldr::cldr_serde::{self};
8-
use fraction::{GenericFraction, Zero};
98
use icu_provider::{
109
datagen::IterableDataProvider, DataError, DataLocale, DataPayload, DataProvider, DataRequest,
1110
DataResponse,
@@ -116,6 +115,7 @@ fn test_basic() {
116115
use icu_provider::prelude::*;
117116
use icu_unitsconversion::provider::*;
118117
use num_bigint::BigUint;
118+
use num_rational::Ratio;
119119
use zerofrom::ZeroFrom;
120120
use zerovec::maps::ZeroVecLike;
121121

@@ -157,7 +157,7 @@ fn test_basic() {
157157
factor_num: ZeroVec::from(big_one.to_bytes_le()),
158158
factor_den: ZeroVec::from(big_one.to_bytes_le()),
159159
offset_sign: Sign::Positive,
160-
offset_num: ZeroVec::from(BigUint::zero().to_bytes_le()),
160+
offset_num: ZeroVec::from(BigUint::from(0u32).to_bytes_le()),
161161
offset_den: ZeroVec::from(big_one.to_bytes_le()),
162162
exactness: Exactness::Exact,
163163
}
@@ -167,17 +167,17 @@ fn test_basic() {
167167
let foot_convert_index = foot.convert_info.get().unwrap().as_unsigned_int() as usize;
168168
let foot_convert_ule = convert_units.zvl_get(foot_convert_index).unwrap();
169169
let foot_convert: ConversionInfo = ZeroFrom::zero_from(foot_convert_ule);
170-
let ft_to_m = GenericFraction::<BigUint>::new(BigUint::from(3048u32), BigUint::from(10000u32));
170+
let ft_to_m = Ratio::new(BigUint::from(3048u32), BigUint::from(10000u32));
171171

172172
assert_eq!(
173173
foot_convert,
174174
ConversionInfo {
175175
base_unit: Cow::Borrowed("meter"),
176176
factor_sign: Sign::Positive,
177-
factor_num: ZeroVec::from(ft_to_m.numer().unwrap().to_bytes_le()),
178-
factor_den: ZeroVec::from(ft_to_m.denom().unwrap().to_bytes_le()),
177+
factor_num: ZeroVec::from(ft_to_m.numer().to_bytes_le()),
178+
factor_den: ZeroVec::from(ft_to_m.denom().to_bytes_le()),
179179
offset_sign: Sign::Positive,
180-
offset_num: ZeroVec::from(BigUint::zero().to_bytes_le()),
180+
offset_num: ZeroVec::from(BigUint::from(0u32).to_bytes_le()),
181181
offset_den: ZeroVec::from(big_one.to_bytes_le()),
182182
exactness: Exactness::Exact,
183183
}

0 commit comments

Comments
 (0)