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

Unum part 3 #146

Merged
merged 1 commit into from
Jul 17, 2020
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
15 changes: 15 additions & 0 deletions rust_icu_uformattable/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,21 @@ impl<'a> crate::UFormattable<'a> {
})
}

/// Reveals the underlying representation as a mutable pointer.
///
/// **DO NOT USE UNLESS YOU HAVE NO OTHER CHOICE**
///
/// The intended use of this method is for other crates that need to obtain
/// low-level representations of this type.
#[doc(hidden)]
pub fn as_mut_ptr(&mut self) -> *mut sys::UFormattable {
self.rep.as_ptr()
}

pub fn as_ptr(&self) -> *const sys::UFormattable {
self.rep.as_ptr()
}

/// Returns `true` if this formattable is numeric.
///
/// Implements `ufmt_isNumeric`
Expand Down
7 changes: 7 additions & 0 deletions rust_icu_unum/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ log = "0.4.6"
paste = "0.1.5"
rust_icu_common = { path = "../rust_icu_common", version = "0.3.1", default-features = false }
rust_icu_sys = { path = "../rust_icu_sys", version = "0.3.1", default-features = false }
rust_icu_uformattable = { path = "../rust_icu_uformattable", version = "0.3.1", default-features = false }
rust_icu_uloc = { path = "../rust_icu_uloc", version = "0.3.1", default-features = false }
rust_icu_ustring = { path = "../rust_icu_ustring", version = "0.3.1", default-features = false }
anyhow = "1.0.25"
Expand All @@ -34,36 +35,42 @@ default = ["use-bindgen", "renaming", "icu_config"]
use-bindgen = [
"rust_icu_common/use-bindgen",
"rust_icu_sys/use-bindgen",
"rust_icu_uformattable/use-bindgen",
"rust_icu_uloc/use-bindgen",
"rust_icu_ustring/use-bindgen",
]
renaming = [
"rust_icu_common/renaming",
"rust_icu_sys/renaming",
"rust_icu_uformattable/renaming",
"rust_icu_uloc/renaming",
"rust_icu_ustring/renaming",
]
icu_config = [
"rust_icu_common/icu_config",
"rust_icu_sys/icu_config",
"rust_icu_uformattable/icu_config",
"rust_icu_uloc/icu_config",
"rust_icu_ustring/icu_config",
]
icu_version_in_env = [
"rust_icu_common/icu_version_in_env",
"rust_icu_sys/icu_version_in_env",
"rust_icu_uformattable/icu_version_in_env",
"rust_icu_uloc/icu_version_in_env",
"rust_icu_ustring/icu_version_in_env",
]
icu_version_64_plus = [
"rust_icu_common/icu_version_64_plus",
"rust_icu_sys/icu_version_64_plus",
"rust_icu_uformattable/icu_version_64_plus",
"rust_icu_uloc/icu_version_64_plus",
"rust_icu_ustring/icu_version_64_plus",
]
icu_version_67_plus = [
"rust_icu_common/icu_version_67_plus",
"rust_icu_sys/icu_version_67_plus",
"rust_icu_uformattable/icu_version_67_plus",
"rust_icu_uloc/icu_version_67_plus",
"rust_icu_ustring/icu_version_67_plus",
]
Expand Down
150 changes: 141 additions & 9 deletions rust_icu_unum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use {
paste, rust_icu_common as common, rust_icu_sys as sys,
rust_icu_sys::versioned_function,
rust_icu_sys::*,
rust_icu_uloc as uloc, rust_icu_ustring as ustring,
rust_icu_uformattable as uformattable, rust_icu_uloc as uloc, rust_icu_ustring as ustring,
rust_icu_ustring::buffered_uchar_method_with_retry,
std::{convert::TryFrom, convert::TryInto, ptr},
};
Expand Down Expand Up @@ -235,21 +235,29 @@ impl UNumberFormat {
}

/// Implements `unum_formatDoubleCurrency`. Since 0.3.1.
pub fn format_double_currency(&self, number: f64, currency: &str) -> Result<String, common::Error> {
pub fn format_double_currency(
&self,
number: f64,
currency: &str,
) -> Result<String, common::Error> {
let currency = ustring::UChar::try_from(currency)?;
let result = self.format_double_currency_ustring(number, &currency)?;
String::try_from(&result)
}

/// Implements `unum_formatDoubleCurrency`. Since 0.3.1
pub fn format_double_currency_ustring(&self, number: f64, currency: &ustring::UChar) -> Result<ustring::UChar, common::Error> {
pub fn format_double_currency_ustring(
&self,
number: f64,
currency: &ustring::UChar,
) -> Result<ustring::UChar, common::Error> {
const CAPACITY: usize = 200;
buffered_uchar_method_with_retry!(
format_double_currency_impl,
CAPACITY,
[
format: *const sys::UNumberFormat,
number: f64,
number: f64,
// NUL terminated!
currency: *mut sys::UChar,
],
Expand All @@ -263,12 +271,83 @@ impl UNumberFormat {
format_double_currency_impl(
versioned_function!(unum_formatDoubleCurrency),
self.rep.as_ptr(),
number,
number,
currencyz.as_mut_c_ptr(),
0 as *mut sys::UFieldPosition,
)
}


/// Implements `unum_parseToUFormattable`. Since 0.3.1.
///
/// > **WARNING** the `parse_position` parameter is with respect to the number index
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"with respect to the number index" is a bit unclear. Maybe something like the "starting index of the numeric string"?

/// in the `UChar` string. This won't work exactly for multibyte UTF8 values of
/// `text`. If you think you will have multibyte values, use instead
/// [UNumberFormat::parse_to_formattable_ustring].
pub fn parse_to_formattable<'a>(
&'a self,
text: &str,
parse_position: Option<i32>,
) -> Result<uformattable::UFormattable<'a>, common::Error> {
let ustr = ustring::UChar::try_from(text)?;
self.parse_to_formattable_ustring(&ustr, parse_position)
}

/// Implements `unum_parseToUFormattable`. Since 0.3.1.
pub fn parse_to_formattable_ustring<'a>(
&'a self,
text: &ustring::UChar,
parse_position: Option<i32>,
) -> Result<uformattable::UFormattable<'a>, common::Error> {
let mut fmt = uformattable::UFormattable::try_new()?;
let mut status = common::Error::OK_CODE;
let mut pos = parse_position.unwrap_or(0);
unsafe {
assert!(common::Error::is_ok(status));
versioned_function!(unum_parseToUFormattable)(
self.rep.as_ptr(),
fmt.as_mut_ptr(),
text.as_c_ptr(),
text.len() as i32,
&mut pos,
&mut status,
)
};
common::Error::ok_or_warning(status)?;
Ok(fmt)
}

/// Implements `unum_formatUFormattable`. Since 0.3.1.
pub fn format_formattable<'a>(
&self,
fmt: &uformattable::UFormattable<'a>,
) -> Result<String, common::Error> {
let result = self.format_formattable_ustring(fmt)?;
String::try_from(&result)
}

/// Implements `unum_formatUFormattable`. Since 0.3.1.
pub fn format_formattable_ustring<'a>(
&self,
fmt: &uformattable::UFormattable<'a>,
) -> Result<ustring::UChar, common::Error> {
const CAPACITY: usize = 200;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this capacity recommended somewhere in ICU4C documentation? Consider mentioning the source in a comment.

buffered_uchar_method_with_retry!(
format_formattable_impl,
CAPACITY,
[
format: *const sys::UNumberFormat,
fmt: *const sys::UFormattable,
],
[pos: *mut sys::UFieldPosition,]
);

format_formattable_impl(
versioned_function!(unum_formatUFormattable),
self.rep.as_ptr(),
fmt.as_ptr(),
0 as *mut sys::UFieldPosition,
)
}
}

/// Used to iterate over the field positions.
Expand Down Expand Up @@ -536,9 +615,7 @@ mod tests {
let fmt =
crate::UNumberFormat::try_new_with_style(test.style, &locale).expect("formatter");

let s = fmt
.format_decimal(test.number)
.expect("format success");
let s = fmt.format_decimal(test.number).expect("format success");

assert_eq!(test.expected, s);
}
Expand Down Expand Up @@ -573,4 +650,59 @@ mod tests {
assert_eq!(test.expected, s);
}
}

#[test]
fn format_and_parse_uformattable() {
#[derive(Debug)]
struct TestCase {
source_locale: &'static str,
number: &'static str,
position: Option<i32>,
style: sys::UNumberFormatStyle,

target_locale: &'static str,
expected: &'static str,
};

let tests = vec![
TestCase {
source_locale: "sr-RS",
number: "123,44",
position: None,
style: sys::UNumberFormatStyle::UNUM_DECIMAL,

target_locale: "en-US",
expected: "123.44",
},

TestCase {
source_locale: "sr-RS",
number: "123,44",
position: Some(2),
style: sys::UNumberFormatStyle::UNUM_DECIMAL,

target_locale: "en-US",
expected: "3.44",
},
];
for test in tests {
let locale = uloc::ULoc::try_from(test.source_locale).expect("locale exists");
let fmt =
crate::UNumberFormat::try_new_with_style(test.style, &locale).expect("source_locale formatter");

let formattable = fmt
.parse_to_formattable(test.number, test.position)
.expect(&format!("parse_to_formattable: {:?}", &test));

let locale = uloc::ULoc::try_from(test.target_locale).expect("locale exists");
let fmt =
crate::UNumberFormat::try_new_with_style(test.style, &locale).expect("target_locale formatter");

let result = fmt
.format_formattable(&formattable)
.expect(&format!("format_formattable: {:?}", &test));

assert_eq!(test.expected, result);
}
}
}