diff --git a/Cargo.toml b/Cargo.toml index 6edd3d86..cbd99117 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [ "rust_icu_udat", "rust_icu_udata", "rust_icu_uenum", + "rust_icu_uformattable", "rust_icu_ulistformatter", "rust_icu_uloc", "rust_icu_umsg", diff --git a/Makefile b/Makefile index 8e1d7f81..2d48b303 100644 --- a/Makefile +++ b/Makefile @@ -133,6 +133,7 @@ publish: $(call publish,rust_icu_umsg) $(call publish,rust_icu_ulistformatter) $(call publish,rust_icu_upluralrules) + $(call publish,rust_icu_uformattable) $(call publish,rust_icu) # A helper to up-rev the cargo crate versions. @@ -164,6 +165,7 @@ uprev: $(call uprev,rust_icu_upluralrules) $(call uprev,rust_icu_ustring) $(call uprev,rust_icu_utext) + $(call uprev,rust_icu_uformattable) cov: ./build/showprogress.sh diff --git a/README.md b/README.md index 291b636f..d05f7067 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ coverage in the headers. | [rust_icu_udat](https://crates.io/crates/rust_icu_udat)| ICU date and time. Implements [`udat.h`](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/udat_8h.html) C API header from the ICU library. | | [rust_icu_udata](https://crates.io/crates/rust_icu_udata)| ICU binary data. Implements [`udata.h`](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/udata_8h.html) C API header from the ICU library. | | [rust_icu_uenum](https://crates.io/crates/rust_icu_uenum)| ICU enumerations. Implements [`uenum.h`](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/uenum_8h.html) C API header from the ICU library. Mainly `UEnumeration` and friends. | +| [rust_icu_uformattable](https://crates.io/crates/rust_icu_uformattable)| Locale-sensitive list formatting support. Implements [`uformattable.h`](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/uformattable_8h.html) C API header from the ICU library. Since 0.3.1. | | [rust_icu_ulistformatter](https://crates.io/crates/rust_icu_ulistformatter)| Locale-sensitive list formatting support. Implements [`ulistformatter.h`](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/ulistformatter_8h.html) C API header from the ICU library. | | [rust_icu_uloc](https://crates.io/crates/rust_icu_uloc)| Locale support. Implements [`uloc.h`](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/uloc_8h.html) C API header from the ICU library. | | [rust_icu_umsg](https://crates.io/crates/rust_icu_umsg)| MessageFormat support. Implements [`umsg.h`](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/umsg_8h.html) C API header from the ICU library. | diff --git a/build/showprogress.sh b/build/showprogress.sh index f715b949..de6f5c2c 100755 --- a/build/showprogress.sh +++ b/build/showprogress.sh @@ -13,10 +13,12 @@ C_API_HEADER_NAMES=( "udat" "udata" "uenum" + "uformattable" + "ulistformatter" "uloc" + "upluralrules" "umsg" "ustring" - "ustring" "utext" ) diff --git a/coverage/report.md b/coverage/report.md index d62bba9f..965a2a20 100644 --- a/coverage/report.md +++ b/coverage/report.md @@ -2,15 +2,17 @@ | Header | Implemented | | ------ | ----------- | -| `ucal.h` | 15 / 45 | +| `ucal.h` | 15 / 46 | | `ucol.h` | 2 / 50 | | `udat.h` | 6 / 38 | | `udata.h` | 2 / 8 | | `uenum.h` | 8 / 8 | -| `uloc.h` | 19 / 41 | +| `uformattable.h` | 7 / 13 | +| `ulistformatter.h` | 2 / 8 | +| `uloc.h` | 19 / 42 | +| `upluralrules.h` | 3 / 7 | | `umsg.h` | 6 / 20 | | `ustring.h` | 3 / 61 | -| `ustring.h` | 3 / 61 | | `utext.h` | 3 / 28 | # Unimplemented functions per header @@ -47,6 +49,7 @@ | `ucal_getDSTSavings` | | | `ucal_getFieldDifference` | | | `ucal_getGregorianChange` | | +| `ucal_getHostTimeZone` | | | `ucal_getKeywordValuesForLocale` | | | `ucal_getLimit` | | | `ucal_getLocaleByType` | | @@ -196,6 +199,38 @@ | `uenum_reset` | | | `uenum_unext` | | +# Header: `uformattable.h` + +| Unimplemented | Implemented | +| ------------- | ----------- | +| | `$impl_function_name` | +| | `ufmt_close` | +| | `ufmt_getArrayItemByIndex` | +| | `ufmt_getDecNumChars` | +| | `ufmt_getUChars` | +| | `ufmt_isNumeric` | +| | `ufmt_open` | +| `ufmt_getArrayLength` | | +| `ufmt_getDate` | | +| `ufmt_getDouble` | | +| `ufmt_getInt64` | | +| `ufmt_getLong` | | +| `ufmt_getObject` | | +| `ufmt_getType` | | + +# Header: `ulistformatter.h` + +| Unimplemented | Implemented | +| ------------- | ----------- | +| | `ulistfmt_format` | +| | `ulistfmt_openForType` | +| `ulistfmt_close` | | +| `ulistfmt_closeResult` | | +| `ulistfmt_formatStringsToResult` | | +| `ulistfmt_open` | | +| `ulistfmt_openResult` | | +| `ulistfmt_resultAsValue` | | + # Header: `uloc.h` | Unimplemented | Implemented | @@ -242,10 +277,23 @@ | `uloc_getName` | | | `uloc_getParent` | | | `uloc_isRightToLeft` | | +| `uloc_openAvailableByType` | | | `uloc_openKeywords` | | | `uloc_setKeywordValue` | | | `uloc_toLegacyType` | | +# Header: `upluralrules.h` + +| Unimplemented | Implemented | +| ------------- | ----------- | +| | `uplrules_getKeywords` | +| | `uplrules_openForType` | +| | `uplrules_select` | +| `uplrules_close` | | +| `uplrules_open` | | +| `uplrules_selectFormatted` | | +| `uplrules_selectWithFormat` | | + # Header: `umsg.h` | Unimplemented | Implemented | @@ -339,73 +387,6 @@ | `u_unescape` | | | `u_unescapeAt` | | -# Header: `ustring.h` - -| Unimplemented | Implemented | -| ------------- | ----------- | -| | `UChar*` | -| | `u_strFromUTF8` | -| | `u_strToUTF8` | -| `u_austrcpy` | | -| `u_austrncpy` | | -| `u_countChar32` | | -| `u_memcasecmp` | | -| `u_memchr` | | -| `u_memchr32` | | -| `u_memcmp` | | -| `u_memcmpCodePointOrder` | | -| `u_memcpy` | | -| `u_memmove` | | -| `u_memrchr` | | -| `u_memrchr32` | | -| `u_memset` | | -| `u_strcasecmp` | | -| `u_strCaseCompare` | | -| `u_strcat` | | -| `u_strchr` | | -| `u_strchr32` | | -| `u_strcmp` | | -| `u_strcmpCodePointOrder` | | -| `u_strCompare` | | -| `u_strCompareIter` | | -| `u_strcpy` | | -| `u_strcspn` | | -| `u_strFindFirst` | | -| `u_strFindLast` | | -| `u_strFoldCase` | | -| `u_strFromJavaModifiedUTF8WithSub` | | -| `u_strFromUTF32` | | -| `u_strFromUTF32WithSub` | | -| `u_strFromUTF8Lenient` | | -| `u_strFromUTF8WithSub` | | -| `u_strFromWCS` | | -| `u_strHasMoreChar32Than` | | -| `u_strlen` | | -| `u_strncasecmp` | | -| `u_strncat` | | -| `u_strncmp` | | -| `u_strncmpCodePointOrder` | | -| `u_strncpy` | | -| `u_strpbrk` | | -| `u_strrchr` | | -| `u_strrchr32` | | -| `u_strrstr` | | -| `u_strspn` | | -| `u_strstr` | | -| `u_strToJavaModifiedUTF8` | | -| `u_strtok_r` | | -| `u_strToLower` | | -| `u_strToTitle` | | -| `u_strToUpper` | | -| `u_strToUTF32` | | -| `u_strToUTF32WithSub` | | -| `u_strToUTF8WithSub` | | -| `u_strToWCS` | | -| `u_uastrcpy` | | -| `u_uastrncpy` | | -| `u_unescape` | | -| `u_unescapeAt` | | - # Header: `utext.h` | Unimplemented | Implemented | diff --git a/coverage/ucal_all.txt b/coverage/ucal_all.txt index 9b93ddd4..124f1336 100644 --- a/coverage/ucal_all.txt +++ b/coverage/ucal_all.txt @@ -14,6 +14,7 @@ ucal_getDefaultTimeZone ucal_getDSTSavings ucal_getFieldDifference ucal_getGregorianChange +ucal_getHostTimeZone ucal_getKeywordValuesForLocale ucal_getLimit ucal_getLocaleByType diff --git a/coverage/ufmt_all.txt b/coverage/ufmt_all.txt new file mode 100644 index 00000000..e69de29b diff --git a/coverage/uformattable_all.txt b/coverage/uformattable_all.txt new file mode 100644 index 00000000..1cb927c9 --- /dev/null +++ b/coverage/uformattable_all.txt @@ -0,0 +1,13 @@ +ufmt_close +ufmt_getArrayItemByIndex +ufmt_getArrayLength +ufmt_getDate +ufmt_getDecNumChars +ufmt_getDouble +ufmt_getInt64 +ufmt_getLong +ufmt_getObject +ufmt_getType +ufmt_getUChars +ufmt_isNumeric +ufmt_open diff --git a/coverage/uformattable_implemented.txt b/coverage/uformattable_implemented.txt new file mode 100644 index 00000000..f06811a4 --- /dev/null +++ b/coverage/uformattable_implemented.txt @@ -0,0 +1,7 @@ +$impl_function_name +ufmt_close +ufmt_getArrayItemByIndex +ufmt_getDecNumChars +ufmt_getUChars +ufmt_isNumeric +ufmt_open diff --git a/coverage/ulistformatter_all.txt b/coverage/ulistformatter_all.txt new file mode 100644 index 00000000..037550c7 --- /dev/null +++ b/coverage/ulistformatter_all.txt @@ -0,0 +1,8 @@ +ulistfmt_close +ulistfmt_closeResult +ulistfmt_format +ulistfmt_formatStringsToResult +ulistfmt_open +ulistfmt_openForType +ulistfmt_openResult +ulistfmt_resultAsValue diff --git a/coverage/ulistformatter_implemented.txt b/coverage/ulistformatter_implemented.txt new file mode 100644 index 00000000..63e3d003 --- /dev/null +++ b/coverage/ulistformatter_implemented.txt @@ -0,0 +1,2 @@ +ulistfmt_format +ulistfmt_openForType diff --git a/coverage/uloc_all.txt b/coverage/uloc_all.txt index 2ae43c5f..30bb06d1 100644 --- a/coverage/uloc_all.txt +++ b/coverage/uloc_all.txt @@ -31,6 +31,7 @@ uloc_getScript uloc_getVariant uloc_isRightToLeft uloc_minimizeSubtags +uloc_openAvailableByType uloc_openKeywords uloc_setDefault uloc_setKeywordValue diff --git a/coverage/upluralrules_all.txt b/coverage/upluralrules_all.txt new file mode 100644 index 00000000..9c32b705 --- /dev/null +++ b/coverage/upluralrules_all.txt @@ -0,0 +1,7 @@ +uplrules_close +uplrules_getKeywords +uplrules_open +uplrules_openForType +uplrules_select +uplrules_selectFormatted +uplrules_selectWithFormat diff --git a/coverage/upluralrules_implemented.txt b/coverage/upluralrules_implemented.txt new file mode 100644 index 00000000..4d369093 --- /dev/null +++ b/coverage/upluralrules_implemented.txt @@ -0,0 +1,3 @@ +uplrules_getKeywords +uplrules_openForType +uplrules_select diff --git a/rust_icu_common/src/lib.rs b/rust_icu_common/src/lib.rs index 5d70726e..470dafe5 100644 --- a/rust_icu_common/src/lib.rs +++ b/rust_icu_common/src/lib.rs @@ -169,7 +169,7 @@ impl Into for Error { /// BUFFER_CAPACITY, /// [before_arg_a: before_type_a, before_arg_b: before_type_b,], /// [after_arg_a: after_type_a, after_arg_b: after_type_b,] -/// ); +/// ); /// ``` /// /// the generated method has a signature of the form diff --git a/rust_icu_sys/bindgen/lib_63.rs b/rust_icu_sys/bindgen/lib_63.rs index 555fc699..80bc8dc9 100644 --- a/rust_icu_sys/bindgen/lib_63.rs +++ b/rust_icu_sys/bindgen/lib_63.rs @@ -2272,6 +2272,73 @@ fn bindgen_test_layout_UFieldPosition() { } #[repr(u32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd)] +pub enum UFormattableType { + UFMT_DATE = 0, + UFMT_DOUBLE = 1, + UFMT_LONG = 2, + UFMT_STRING = 3, + UFMT_ARRAY = 4, + UFMT_INT64 = 5, + UFMT_OBJECT = 6, + UFMT_COUNT = 7, +} +pub type UFormattable = *mut ::std::os::raw::c_void; +extern "C" { + pub fn ufmt_open_63(status: *mut UErrorCode) -> *mut UFormattable; +} +extern "C" { + pub fn ufmt_close_63(fmt: *mut UFormattable); +} +extern "C" { + pub fn ufmt_getType_63(fmt: *const UFormattable, status: *mut UErrorCode) -> UFormattableType; +} +extern "C" { + pub fn ufmt_isNumeric_63(fmt: *const UFormattable) -> UBool; +} +extern "C" { + pub fn ufmt_getDate_63(fmt: *const UFormattable, status: *mut UErrorCode) -> UDate; +} +extern "C" { + pub fn ufmt_getDouble_63(fmt: *mut UFormattable, status: *mut UErrorCode) -> f64; +} +extern "C" { + pub fn ufmt_getLong_63(fmt: *mut UFormattable, status: *mut UErrorCode) -> i32; +} +extern "C" { + pub fn ufmt_getInt64_63(fmt: *mut UFormattable, status: *mut UErrorCode) -> i64; +} +extern "C" { + pub fn ufmt_getObject_63( + fmt: *const UFormattable, + status: *mut UErrorCode, + ) -> *const ::std::os::raw::c_void; +} +extern "C" { + pub fn ufmt_getUChars_63( + fmt: *mut UFormattable, + len: *mut i32, + status: *mut UErrorCode, + ) -> *const UChar; +} +extern "C" { + pub fn ufmt_getArrayLength_63(fmt: *const UFormattable, status: *mut UErrorCode) -> i32; +} +extern "C" { + pub fn ufmt_getArrayItemByIndex_63( + fmt: *mut UFormattable, + n: i32, + status: *mut UErrorCode, + ) -> *mut UFormattable; +} +extern "C" { + pub fn ufmt_getDecNumChars_63( + fmt: *mut UFormattable, + len: *mut i32, + status: *mut UErrorCode, + ) -> *const ::std::os::raw::c_char; +} +#[repr(u32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd)] pub enum UDisplayContextType { UDISPCTX_TYPE_DIALECT_HANDLING = 0, UDISPCTX_TYPE_CAPITALIZATION = 1, diff --git a/rust_icu_sys/bindgen/lib_64.rs b/rust_icu_sys/bindgen/lib_64.rs index 0d64ee01..0aaede60 100644 --- a/rust_icu_sys/bindgen/lib_64.rs +++ b/rust_icu_sys/bindgen/lib_64.rs @@ -2272,6 +2272,73 @@ fn bindgen_test_layout_UFieldPosition() { } #[repr(u32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd)] +pub enum UFormattableType { + UFMT_DATE = 0, + UFMT_DOUBLE = 1, + UFMT_LONG = 2, + UFMT_STRING = 3, + UFMT_ARRAY = 4, + UFMT_INT64 = 5, + UFMT_OBJECT = 6, + UFMT_COUNT = 7, +} +pub type UFormattable = *mut ::std::os::raw::c_void; +extern "C" { + pub fn ufmt_open_64(status: *mut UErrorCode) -> *mut UFormattable; +} +extern "C" { + pub fn ufmt_close_64(fmt: *mut UFormattable); +} +extern "C" { + pub fn ufmt_getType_64(fmt: *const UFormattable, status: *mut UErrorCode) -> UFormattableType; +} +extern "C" { + pub fn ufmt_isNumeric_64(fmt: *const UFormattable) -> UBool; +} +extern "C" { + pub fn ufmt_getDate_64(fmt: *const UFormattable, status: *mut UErrorCode) -> UDate; +} +extern "C" { + pub fn ufmt_getDouble_64(fmt: *mut UFormattable, status: *mut UErrorCode) -> f64; +} +extern "C" { + pub fn ufmt_getLong_64(fmt: *mut UFormattable, status: *mut UErrorCode) -> i32; +} +extern "C" { + pub fn ufmt_getInt64_64(fmt: *mut UFormattable, status: *mut UErrorCode) -> i64; +} +extern "C" { + pub fn ufmt_getObject_64( + fmt: *const UFormattable, + status: *mut UErrorCode, + ) -> *const ::std::os::raw::c_void; +} +extern "C" { + pub fn ufmt_getUChars_64( + fmt: *mut UFormattable, + len: *mut i32, + status: *mut UErrorCode, + ) -> *const UChar; +} +extern "C" { + pub fn ufmt_getArrayLength_64(fmt: *const UFormattable, status: *mut UErrorCode) -> i32; +} +extern "C" { + pub fn ufmt_getArrayItemByIndex_64( + fmt: *mut UFormattable, + n: i32, + status: *mut UErrorCode, + ) -> *mut UFormattable; +} +extern "C" { + pub fn ufmt_getDecNumChars_64( + fmt: *mut UFormattable, + len: *mut i32, + status: *mut UErrorCode, + ) -> *const ::std::os::raw::c_char; +} +#[repr(u32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd)] pub enum UDisplayContextType { UDISPCTX_TYPE_DIALECT_HANDLING = 0, UDISPCTX_TYPE_CAPITALIZATION = 1, diff --git a/rust_icu_sys/bindgen/lib_65.rs b/rust_icu_sys/bindgen/lib_65.rs index b667d0a1..77b09d92 100644 --- a/rust_icu_sys/bindgen/lib_65.rs +++ b/rust_icu_sys/bindgen/lib_65.rs @@ -2293,6 +2293,73 @@ fn bindgen_test_layout_UFieldPosition() { } #[repr(u32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd)] +pub enum UFormattableType { + UFMT_DATE = 0, + UFMT_DOUBLE = 1, + UFMT_LONG = 2, + UFMT_STRING = 3, + UFMT_ARRAY = 4, + UFMT_INT64 = 5, + UFMT_OBJECT = 6, + UFMT_COUNT = 7, +} +pub type UFormattable = *mut ::std::os::raw::c_void; +extern "C" { + pub fn ufmt_open_65(status: *mut UErrorCode) -> *mut UFormattable; +} +extern "C" { + pub fn ufmt_close_65(fmt: *mut UFormattable); +} +extern "C" { + pub fn ufmt_getType_65(fmt: *const UFormattable, status: *mut UErrorCode) -> UFormattableType; +} +extern "C" { + pub fn ufmt_isNumeric_65(fmt: *const UFormattable) -> UBool; +} +extern "C" { + pub fn ufmt_getDate_65(fmt: *const UFormattable, status: *mut UErrorCode) -> UDate; +} +extern "C" { + pub fn ufmt_getDouble_65(fmt: *mut UFormattable, status: *mut UErrorCode) -> f64; +} +extern "C" { + pub fn ufmt_getLong_65(fmt: *mut UFormattable, status: *mut UErrorCode) -> i32; +} +extern "C" { + pub fn ufmt_getInt64_65(fmt: *mut UFormattable, status: *mut UErrorCode) -> i64; +} +extern "C" { + pub fn ufmt_getObject_65( + fmt: *const UFormattable, + status: *mut UErrorCode, + ) -> *const ::std::os::raw::c_void; +} +extern "C" { + pub fn ufmt_getUChars_65( + fmt: *mut UFormattable, + len: *mut i32, + status: *mut UErrorCode, + ) -> *const UChar; +} +extern "C" { + pub fn ufmt_getArrayLength_65(fmt: *const UFormattable, status: *mut UErrorCode) -> i32; +} +extern "C" { + pub fn ufmt_getArrayItemByIndex_65( + fmt: *mut UFormattable, + n: i32, + status: *mut UErrorCode, + ) -> *mut UFormattable; +} +extern "C" { + pub fn ufmt_getDecNumChars_65( + fmt: *mut UFormattable, + len: *mut i32, + status: *mut UErrorCode, + ) -> *const ::std::os::raw::c_char; +} +#[repr(u32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd)] pub enum UDisplayContextType { UDISPCTX_TYPE_DIALECT_HANDLING = 0, UDISPCTX_TYPE_CAPITALIZATION = 1, diff --git a/rust_icu_sys/bindgen/lib_66.rs b/rust_icu_sys/bindgen/lib_66.rs index 84fafa77..60ec19d8 100644 --- a/rust_icu_sys/bindgen/lib_66.rs +++ b/rust_icu_sys/bindgen/lib_66.rs @@ -2293,6 +2293,73 @@ fn bindgen_test_layout_UFieldPosition() { } #[repr(u32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd)] +pub enum UFormattableType { + UFMT_DATE = 0, + UFMT_DOUBLE = 1, + UFMT_LONG = 2, + UFMT_STRING = 3, + UFMT_ARRAY = 4, + UFMT_INT64 = 5, + UFMT_OBJECT = 6, + UFMT_COUNT = 7, +} +pub type UFormattable = *mut ::std::os::raw::c_void; +extern "C" { + pub fn ufmt_open_66(status: *mut UErrorCode) -> *mut UFormattable; +} +extern "C" { + pub fn ufmt_close_66(fmt: *mut UFormattable); +} +extern "C" { + pub fn ufmt_getType_66(fmt: *const UFormattable, status: *mut UErrorCode) -> UFormattableType; +} +extern "C" { + pub fn ufmt_isNumeric_66(fmt: *const UFormattable) -> UBool; +} +extern "C" { + pub fn ufmt_getDate_66(fmt: *const UFormattable, status: *mut UErrorCode) -> UDate; +} +extern "C" { + pub fn ufmt_getDouble_66(fmt: *mut UFormattable, status: *mut UErrorCode) -> f64; +} +extern "C" { + pub fn ufmt_getLong_66(fmt: *mut UFormattable, status: *mut UErrorCode) -> i32; +} +extern "C" { + pub fn ufmt_getInt64_66(fmt: *mut UFormattable, status: *mut UErrorCode) -> i64; +} +extern "C" { + pub fn ufmt_getObject_66( + fmt: *const UFormattable, + status: *mut UErrorCode, + ) -> *const ::std::os::raw::c_void; +} +extern "C" { + pub fn ufmt_getUChars_66( + fmt: *mut UFormattable, + len: *mut i32, + status: *mut UErrorCode, + ) -> *const UChar; +} +extern "C" { + pub fn ufmt_getArrayLength_66(fmt: *const UFormattable, status: *mut UErrorCode) -> i32; +} +extern "C" { + pub fn ufmt_getArrayItemByIndex_66( + fmt: *mut UFormattable, + n: i32, + status: *mut UErrorCode, + ) -> *mut UFormattable; +} +extern "C" { + pub fn ufmt_getDecNumChars_66( + fmt: *mut UFormattable, + len: *mut i32, + status: *mut UErrorCode, + ) -> *const ::std::os::raw::c_char; +} +#[repr(u32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd)] pub enum UDisplayContextType { UDISPCTX_TYPE_DIALECT_HANDLING = 0, UDISPCTX_TYPE_CAPITALIZATION = 1, diff --git a/rust_icu_sys/bindgen/lib_67.rs b/rust_icu_sys/bindgen/lib_67.rs index e7777374..9133177e 100644 --- a/rust_icu_sys/bindgen/lib_67.rs +++ b/rust_icu_sys/bindgen/lib_67.rs @@ -2293,6 +2293,73 @@ fn bindgen_test_layout_UFieldPosition() { } #[repr(u32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd)] +pub enum UFormattableType { + UFMT_DATE = 0, + UFMT_DOUBLE = 1, + UFMT_LONG = 2, + UFMT_STRING = 3, + UFMT_ARRAY = 4, + UFMT_INT64 = 5, + UFMT_OBJECT = 6, + UFMT_COUNT = 7, +} +pub type UFormattable = *mut ::std::os::raw::c_void; +extern "C" { + pub fn ufmt_open_67(status: *mut UErrorCode) -> *mut UFormattable; +} +extern "C" { + pub fn ufmt_close_67(fmt: *mut UFormattable); +} +extern "C" { + pub fn ufmt_getType_67(fmt: *const UFormattable, status: *mut UErrorCode) -> UFormattableType; +} +extern "C" { + pub fn ufmt_isNumeric_67(fmt: *const UFormattable) -> UBool; +} +extern "C" { + pub fn ufmt_getDate_67(fmt: *const UFormattable, status: *mut UErrorCode) -> UDate; +} +extern "C" { + pub fn ufmt_getDouble_67(fmt: *mut UFormattable, status: *mut UErrorCode) -> f64; +} +extern "C" { + pub fn ufmt_getLong_67(fmt: *mut UFormattable, status: *mut UErrorCode) -> i32; +} +extern "C" { + pub fn ufmt_getInt64_67(fmt: *mut UFormattable, status: *mut UErrorCode) -> i64; +} +extern "C" { + pub fn ufmt_getObject_67( + fmt: *const UFormattable, + status: *mut UErrorCode, + ) -> *const ::std::os::raw::c_void; +} +extern "C" { + pub fn ufmt_getUChars_67( + fmt: *mut UFormattable, + len: *mut i32, + status: *mut UErrorCode, + ) -> *const UChar; +} +extern "C" { + pub fn ufmt_getArrayLength_67(fmt: *const UFormattable, status: *mut UErrorCode) -> i32; +} +extern "C" { + pub fn ufmt_getArrayItemByIndex_67( + fmt: *mut UFormattable, + n: i32, + status: *mut UErrorCode, + ) -> *mut UFormattable; +} +extern "C" { + pub fn ufmt_getDecNumChars_67( + fmt: *mut UFormattable, + len: *mut i32, + status: *mut UErrorCode, + ) -> *const ::std::os::raw::c_char; +} +#[repr(u32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd)] pub enum UDisplayContextType { UDISPCTX_TYPE_DIALECT_HANDLING = 0, UDISPCTX_TYPE_CAPITALIZATION = 1, diff --git a/rust_icu_sys/bindgen/run_bindgen.sh b/rust_icu_sys/bindgen/run_bindgen.sh index d87863ef..e432aca9 100755 --- a/rust_icu_sys/bindgen/run_bindgen.sh +++ b/rust_icu_sys/bindgen/run_bindgen.sh @@ -39,6 +39,7 @@ readonly BINDGEN_SOURCE_MODULES=( "udat" "udata" "uenum" + "uformattable" "ulistformatter" "umsg" "upluralrules" @@ -63,6 +64,7 @@ readonly BINDGEN_ALLOWLIST_TYPES=( "UDateFormat.*" "UEnumeration.*" "UErrorCode" + "UFormattable.*", "UFormattedList.*" "UListFormatter.*" "UMessageFormat" @@ -87,6 +89,7 @@ readonly BINDGEN_ALLOWLIST_FUNCTIONS=( "umsg_.*" "uplrules_.*" "utext_.*" + "ufmt_.*" ) function check_requirements() { diff --git a/rust_icu_sys/build.rs b/rust_icu_sys/build.rs index 01a9aaa4..36eab9a1 100644 --- a/rust_icu_sys/build.rs +++ b/rust_icu_sys/build.rs @@ -44,6 +44,7 @@ mod inner { "udat", "udata", "uenum", + "uformattable", "ulistformatter", "umsg", "upluralrules", @@ -61,6 +62,7 @@ mod inner { "udat_.*", "udata_.*", "uenum_.*", + "ufmt_.*", "ulistfmt_.*", "uloc_.*", "umsg_.*", @@ -83,9 +85,11 @@ mod inner { "UDateFormat.*", "UEnumeration.*", "UErrorCode", + "UFormat.*", "UFormattedList.*", "UListFormatter.*", "UMessageFormat", + "UNUM.*", "UParseError", "UPlural.*", "USet", diff --git a/rust_icu_uformattable/Cargo.toml b/rust_icu_uformattable/Cargo.toml new file mode 100644 index 00000000..17e89ce8 --- /dev/null +++ b/rust_icu_uformattable/Cargo.toml @@ -0,0 +1,68 @@ +[package] +authors = ["Google Inc."] +edition = "2018" +license = "Apache-2.0" +name = "rust_icu_uformattable" +readme = "README.md" +repository = "https://github.com/google/rust_icu" +version = "0.3.1" +default-features = false +keywords = ["icu", "unicode", "i18n", "l10n"] + +description = """ +Native bindings to the ICU4C library from Unicode. + +- uformattable.h: Number formatting support +""" + +[dependencies] +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_ustring = { path = "../rust_icu_ustring", version = "0.3.1", default-features = false } +anyhow = "1.0.25" + +[dev-dependencies] +anyhow = "1.0.25" + +# See the feature description in ../rust_icu_sys/Cargo.toml for details. +[features] +default = ["use-bindgen", "renaming", "icu_config"] + +use-bindgen = [ + "rust_icu_common/use-bindgen", + "rust_icu_sys/use-bindgen", + "rust_icu_ustring/use-bindgen", +] +renaming = [ + "rust_icu_common/renaming", + "rust_icu_sys/renaming", + "rust_icu_ustring/renaming", +] +icu_config = [ + "rust_icu_common/icu_config", + "rust_icu_sys/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_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_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_ustring/icu_version_67_plus", +] + +[badges] +maintenance = { status = "actively-developed" } +is-it-maintained-issue-resolution = { repository = "google/rust_icu" } +is-it-maintained-open-issues = { repository = "google/rust_icu" } +travis-ci = { repository = "google/rust_icu", branch = "master" } diff --git a/rust_icu_uformattable/README.md b/rust_icu_uformattable/README.md new file mode 120000 index 00000000..32d46ee8 --- /dev/null +++ b/rust_icu_uformattable/README.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file diff --git a/rust_icu_uformattable/src/lib.rs b/rust_icu_uformattable/src/lib.rs new file mode 100644 index 00000000..f4b54ca3 --- /dev/null +++ b/rust_icu_uformattable/src/lib.rs @@ -0,0 +1,207 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # ICU number formatting support for rust + +use { + rust_icu_common as common, rust_icu_sys as sys, + rust_icu_sys::versioned_function, + rust_icu_sys::*, + rust_icu_ustring as ustring, + std::{convert::TryFrom, os::raw, ffi, ptr}, +}; + +// Implements the ICU type [`UFormattable`][ufmt]. +// +// [UFormattable] is a thin wrapper for primitive types used for number formatting. +// +// Note from the ICU4C API: +// +// > Underlying is a C interface to the class `icu::Formatable`. Static functions +// on this class convert to and from this interface (via `reinterpret_cast`). Many +// operations are not thread safe, and should not be shared between threads. +// +// [ufmt]: https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/uformattable_8h.html +#[derive(Debug)] +pub struct UFormattable<'a> { + // The underlying representation. + rep: ptr::NonNull, + owner: Option<&'a Self>, +} + +impl<'a> Drop for crate::UFormattable<'a> { + /// Implements `ufmt_close`. + fn drop(&mut self) { + if let None = self.owner { + unsafe { versioned_function!(ufmt_close)(self.rep.as_ptr()) }; + } + } +} + +/// Generates a simple getter, which just shunts into an appropriately +/// named getter function of the sys crate and returns the appropriate type. +/// +/// Example: +/// +/// ``` +/// simple_getter!(get_array_length, ufmt_getArrayLength, i32); +/// ``` +/// +/// * `$method_name` is an identifier +macro_rules! simple_getter { + ($method_name:ident, $impl_function_name:ident, $return_type:ty) => { + /// Implements `$impl_function_name` + /// Use [UFormattable::get_type] to verify that the type matches. + pub fn $method_name(&self) -> Result<$return_type, common::Error> { + let mut status = common::Error::OK_CODE; + let ret = unsafe { + assert!(common::Error::is_ok(status)); + versioned_function!($impl_function_name)( + self.rep.as_ptr(), &mut status) + }; + common::Error::ok_or_warning(status)?; + Ok(ret) + } + } +} + +impl<'a> crate::UFormattable<'a> { + /// Initialize a [crate::UFormattable] to type `UNUM_LONG`, value 0 may + /// return error. + /// + /// Implements `ufmt_open`. + pub fn try_new<'b>() -> Result, common::Error> { + let mut status = common::Error::OK_CODE; + // We verify that status is OK on entry and on exit, and that the + // returned representation is not null. + let rep = unsafe { + assert!(common::Error::is_ok(status)); + versioned_function!(ufmt_open)(&mut status) + }; + common::Error::ok_or_warning(status)?; + Ok(UFormattable { + rep: ptr::NonNull::new(rep).unwrap(), + owner: None, + }) + } + + /// Returns `true` if this formattable is numeric. + /// + /// Implements `ufmt_isNumeric` + pub fn is_numeric(&self) -> bool { + let ubool = unsafe { versioned_function!(ufmt_isNumeric)(self.rep.as_ptr()) }; + match ubool { + 0i8 => false, + _ => true, + } + } + + // Returns the type of this formattable. The comment here and below is + // used in coverage analysis; the macro `simple_getter!` generates + // user-visible documentation. + // + // Implements `ufmt_getType` + simple_getter!(get_type, ufmt_getType, sys::UFormattableType); + + // Implements `ufmt_getDate` + simple_getter!(get_date, ufmt_getDate, sys::UDate); + + // Implements `ufmt_getDouble` + simple_getter!(get_double, ufmt_getDouble, f64); + + // Implements `ufmt_getLong` + simple_getter!(get_i32, ufmt_getLong, i32); + + // Implements `ufmt_getInt64` + simple_getter!(get_i64, ufmt_getInt64, i64); + + // Implements `ufmt_getArrayLength` + simple_getter!(get_array_length, ufmt_getArrayLength, i32); + + // Implements `ufmt_getUChars` + pub fn get_ustring(&self) -> Result { + let mut status = common::Error::OK_CODE; + let mut ustrlen = 0i32; + let raw: *const sys::UChar = unsafe { + assert!(common::Error::is_ok(status)); + versioned_function!(ufmt_getUChars)( + self.rep.as_ptr(), &mut ustrlen, &mut status) + }; + common::Error::ok_or_warning(status)?; + let ret = unsafe { + assert_ne!(raw, 0 as *const sys::UChar); + assert!(ustrlen >= 0); + ustring::UChar::clone_from_raw_parts(raw, ustrlen) + }; + Ok(ret) + } + + /// Implements `ufmt_getUChars` + pub fn get_str(&self) -> Result { + let ustr = self.get_ustring()?; + String::try_from(&ustr) + } + + /// Use [UFormattable::get_type] to ensure that this formattable is an array before using this + /// method. Otherwise you will get an error. The lifetime of the resulting formattable is tied + /// to this one. + /// + /// Implements `ufmt_getArrayItemByIndex` + pub fn get_array_item_by_index(&'a self, index: i32) -> Result, common::Error> { + let mut status = common::Error::OK_CODE; + let raw: *mut sys::UFormattable = unsafe { + assert!(common::Error::is_ok(status)); + versioned_function!(ufmt_getArrayItemByIndex)( + self.rep.as_ptr(), index, &mut status) + }; + common::Error::ok_or_warning(status)?; + assert_ne!(raw, 0 as *mut sys::UFormattable); + Ok(UFormattable{ rep: ptr::NonNull::new(raw).unwrap(), owner: Some(&self) }) + } + + /// Implements `ufmt_getDecNumChars` + pub fn get_dec_num_chars(&self) -> Result { + let mut status = common::Error::OK_CODE; + let mut cstrlen = 0i32; + let raw: *const raw::c_char = unsafe { + assert!(common::Error::is_ok(status)); + versioned_function!(ufmt_getDecNumChars)( + self.rep.as_ptr(), &mut cstrlen, &mut status) + }; + common::Error::ok_or_warning(status)?; + let ret = unsafe { + assert_ne!(raw, 0 as *const raw::c_char); + assert!(cstrlen >= 0); + ffi::CStr::from_ptr(raw) + }; + Ok(ret.to_str().map_err(|e: std::str::Utf8Error| common::Error::from(e))?.to_string()) + } +} + +#[cfg(test)] +mod tests { + use crate::*; + + // There doesn't seem to be a way to initialize a nonzero Numeric for testing all of this code. + // So it seems it would have to remain uncovered with tests, until some other code gets to + // use it. + + #[test] + fn basic() { + let n = crate::UFormattable::try_new().expect("try_new"); + assert_eq!(sys::UFormattableType::UFMT_LONG, n.get_type().expect("get_type")); + assert_eq!(0, n.get_i32().expect("get_i32")); + assert_eq!("0", n.get_dec_num_chars().expect("get_dec_num_chars")); + } +} diff --git a/rust_icu_ustring/src/lib.rs b/rust_icu_ustring/src/lib.rs index e26b5ca3..6e70e38b 100644 --- a/rust_icu_ustring/src/lib.rs +++ b/rust_icu_ustring/src/lib.rs @@ -172,6 +172,28 @@ impl crate::UChar { crate::UChar::from(rep) } + /// Creates a new [crate::UChar] from its low-level representation, a buffer + /// pointer and a buffer size. + /// + /// Does *not* take ownership of the buffer that was passed in. + /// + /// **DO NOT USE UNLESS YOU HAVE NO OTHER CHOICE.** + #[doc(hidden)] + pub unsafe fn clone_from_raw_parts(rep: *const sys::UChar, len: i32) -> crate::UChar { + assert!(len >= 0); + // Always works for len: i32 >= 0. + let cap = len as usize; + + // View the deconstructed buffer as a vector of UChars. Then make a + // copy of it to return. This is not efficient, but is always safe. + let original = Vec::from_raw_parts(rep as *mut sys::UChar, cap, cap); + let copy = original.clone(); + // Don't free the buffer we don't own. + std::mem::forget(original); + crate::UChar::from(copy) + } + + /// Converts into a zeroed-out string. /// /// This is a very weird ICU API thing, where there apparently exists a zero-terminated @@ -204,6 +226,7 @@ impl crate::UChar { pub fn resize(&mut self, new_size: usize) { self.rep.resize(new_size, 0); } + } #[cfg(test)]