From 1822af2bfc0bde6b3ea3a8880f82889c2904bd9f Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 9 Feb 2025 11:24:33 -0800 Subject: [PATCH] Add Borrowed variants to casemapper types (#6088) --- components/casemap/src/casemapper.rs | 203 +++++++++++------- components/casemap/src/closer.rs | 149 +++++++++---- components/casemap/src/lib.rs | 6 +- components/casemap/src/set.rs | 8 +- components/casemap/src/titlecase.rs | 109 +++++++--- .../tests/transliterate/lower_ascii.rs | 8 +- ffi/capi/bindings/dart/CaseMapCloser.g.dart | 4 +- ffi/capi/bindings/dart/CaseMapper.g.dart | 32 +-- ffi/capi/bindings/dart/TitlecaseMapper.g.dart | 2 +- ffi/capi/src/casemap.rs | 115 ++++++---- tools/make/diplomat-coverage/src/allowlist.rs | 1 + 11 files changed, 415 insertions(+), 222 deletions(-) diff --git a/components/casemap/src/casemapper.rs b/components/casemap/src/casemapper.rs index a0e5e4600e2..6741ebcdd06 100644 --- a/components/casemap/src/casemapper.rs +++ b/components/casemap/src/casemapper.rs @@ -16,6 +16,9 @@ use writeable::Writeable; /// A struct with the ability to convert characters and strings to uppercase or lowercase, /// or fold them to a normalized form for case-insensitive comparison. /// +/// Most methods for this type live on [`CaseMapperBorrowed`], which you can obtain via +/// [`CaseMapper::new()`] or [`CaseMapper::as_borrowed()`]. +/// /// # Examples /// /// ```rust @@ -38,21 +41,32 @@ pub struct CaseMapper { pub(crate) data: DataPayload, } -#[cfg(feature = "compiled_data")] -impl Default for CaseMapper { - fn default() -> Self { - Self::new() - } -} - impl AsRef for CaseMapper { fn as_ref(&self) -> &CaseMapper { self } } -impl CaseMapper { - /// Creates a [`CaseMapper`] using compiled data. +/// A struct with the ability to convert characters and strings to uppercase or lowercase, +/// or fold them to a normalized form for case-insensitive comparison, borrowed version. +/// +/// See methods or [`CaseMapper`] for examples. +#[derive(Clone, Debug, Copy)] +pub struct CaseMapperBorrowed<'a> { + pub(crate) data: &'a CaseMap<'a>, +} + +impl CaseMapperBorrowed<'static> { + /// Cheaply converts a [`CaseMapperBorrowed<'static>`] into a [`CaseMapper`]. + /// + /// Note: Due to branching and indirection, using [`CaseMapper`] might inhibit some + /// compile-time optimizations that are possible with [`CaseMapperBorrowed`]. + pub const fn static_to_owned(self) -> CaseMapper { + CaseMapper { + data: DataPayload::from_static_ref(self.data), + } + } + /// Creates a [`CaseMapperBorrowed`] using compiled data. /// /// ✨ *Enabled with the `compiled_data` Cargo feature.* /// @@ -74,28 +88,19 @@ impl CaseMapper { #[cfg(feature = "compiled_data")] pub const fn new() -> Self { Self { - data: DataPayload::from_static_ref(crate::provider::Baked::SINGLETON_CASE_MAP_V1), + data: crate::provider::Baked::SINGLETON_CASE_MAP_V1, } } +} - icu_provider::gen_any_buffer_data_constructors!(() -> error: DataError, - functions: [ - new: skip, - try_new_with_any_provider, - try_new_with_buffer_provider, - try_new_unstable, - Self, - ]); - - #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::new)] - pub fn try_new_unstable

(provider: &P) -> Result - where - P: DataProvider + ?Sized, - { - let data = provider.load(Default::default())?.payload; - Ok(Self { data }) +#[cfg(feature = "compiled_data")] +impl Default for CaseMapperBorrowed<'static> { + fn default() -> Self { + Self::new() } +} +impl<'a> CaseMapperBorrowed<'a> { /// Returns the full lowercase mapping of the given string as a [`Writeable`]. /// This function is context and language sensitive. Callers should pass the text's language /// as a `LanguageIdentifier` (usually the `id` field of the `Locale`) if available, or @@ -103,12 +108,8 @@ impl CaseMapper { /// /// See [`Self::lowercase_to_string()`] for the equivalent convenience function that returns a String, /// as well as for an example. - pub fn lowercase<'a>( - &'a self, - src: &'a str, - langid: &LanguageIdentifier, - ) -> impl Writeable + 'a { - self.data.get().full_helper_writeable::( + pub fn lowercase(self, src: &'a str, langid: &LanguageIdentifier) -> impl Writeable + 'a { + self.data.full_helper_writeable::( src, CaseMapLocale::from_langid(langid), MappingKind::Lower, @@ -123,12 +124,8 @@ impl CaseMapper { /// /// See [`Self::uppercase_to_string()`] for the equivalent convenience function that returns a String, /// as well as for an example. - pub fn uppercase<'a>( - &'a self, - src: &'a str, - langid: &LanguageIdentifier, - ) -> impl Writeable + 'a { - self.data.get().full_helper_writeable::( + pub fn uppercase(self, src: &'a str, langid: &LanguageIdentifier) -> impl Writeable + 'a { + self.data.full_helper_writeable::( src, CaseMapLocale::from_langid(langid), MappingKind::Upper, @@ -159,8 +156,8 @@ impl CaseMapper { /// as well as for an example. /// /// [`TitlecaseMapper`]: crate::TitlecaseMapper - pub fn titlecase_segment_with_only_case_data<'a>( - &'a self, + pub fn titlecase_segment_with_only_case_data( + self, src: &'a str, langid: &LanguageIdentifier, options: TitlecaseOptions, @@ -174,17 +171,18 @@ impl CaseMapper { /// /// We return a concrete type instead of `impl Trait` so the return value can be mixed with that of other calls /// to this function with different closures - pub(crate) fn titlecase_segment_with_adjustment<'a>( - &'a self, + pub(crate) fn titlecase_segment_with_adjustment( + self, src: &'a str, langid: &LanguageIdentifier, options: TitlecaseOptions, char_is_lead: impl Fn(&CaseMap, char) -> bool, ) -> StringAndWriteable<'a, FullCaseWriteable<'a, true>> { - let data = self.data.get(); let (head, rest) = match options.leading_adjustment.unwrap_or_default() { LeadingAdjustment::Auto | LeadingAdjustment::ToCased => { - let first_cased = src.char_indices().find(|(_i, ch)| char_is_lead(data, *ch)); + let first_cased = src + .char_indices() + .find(|(_i, ch)| char_is_lead(self.data, *ch)); if let Some((first_cased, _ch)) = first_cased { ( src.get(..first_cased).unwrap_or(""), @@ -196,7 +194,7 @@ impl CaseMapper { } LeadingAdjustment::None => ("", src), }; - let writeable = data.full_helper_writeable::( + let writeable = self.data.full_helper_writeable::( rest, CaseMapLocale::from_langid(langid), MappingKind::Title, @@ -214,8 +212,8 @@ impl CaseMapper { /// /// See [`Self::fold_string()`] for the equivalent convenience function that returns a String, /// as well as for an example. - pub fn fold<'a>(&'a self, src: &'a str) -> impl Writeable + 'a { - self.data.get().full_helper_writeable::( + pub fn fold(self, src: &'a str) -> impl Writeable + 'a { + self.data.full_helper_writeable::( src, CaseMapLocale::Root, MappingKind::Fold, @@ -231,8 +229,8 @@ impl CaseMapper { /// /// See [`Self::fold_turkic_string()`] for the equivalent convenience function that returns a String, /// as well as for an example. - pub fn fold_turkic<'a>(&'a self, src: &'a str) -> impl Writeable + 'a { - self.data.get().full_helper_writeable::( + pub fn fold_turkic(self, src: &'a str) -> impl Writeable + 'a { + self.data.full_helper_writeable::( src, CaseMapLocale::Turkish, MappingKind::Fold, @@ -266,7 +264,7 @@ impl CaseMapper { /// assert_eq!(cm.lowercase_to_string("CONSTANTINOPLE", &root), "constantinople"); /// assert_eq!(cm.lowercase_to_string("CONSTANTINOPLE", &langid!("tr")), "constantınople"); /// ``` - pub fn lowercase_to_string(&self, src: &str, langid: &LanguageIdentifier) -> String { + pub fn lowercase_to_string(self, src: &str, langid: &LanguageIdentifier) -> String { self.lowercase(src, langid).write_to_string().into_owned() } @@ -299,7 +297,7 @@ impl CaseMapper { /// assert_eq!(cm.uppercase_to_string("և Երևանի", &root), "ԵՒ ԵՐԵՒԱՆԻ"); /// assert_eq!(cm.uppercase_to_string("և Երևանի", &langid!("hy")), "ԵՎ ԵՐԵՎԱՆԻ"); // Eastern Armenian ech-yiwn ligature /// ``` - pub fn uppercase_to_string(&self, src: &str, langid: &LanguageIdentifier) -> String { + pub fn uppercase_to_string(self, src: &str, langid: &LanguageIdentifier) -> String { self.uppercase(src, langid).write_to_string().into_owned() } @@ -358,7 +356,7 @@ impl CaseMapper { /// /// [`TitlecaseMapper`]: crate::TitlecaseMapper pub fn titlecase_segment_with_only_case_data_to_string( - &self, + self, src: &str, langid: &LanguageIdentifier, options: TitlecaseOptions, @@ -390,7 +388,7 @@ impl CaseMapper { /// assert_eq!(cm.fold_string("नमस्ते दुनिया"), "नमस्ते दुनिया"); /// assert_eq!(cm.fold_string("Привет мир"), "привет мир"); /// ``` - pub fn fold_string(&self, src: &str) -> String { + pub fn fold_string(self, src: &str) -> String { self.fold(src).write_to_string().into_owned() } @@ -420,16 +418,16 @@ impl CaseMapper { /// assert_eq!(cm.fold_turkic_string("नमस्ते दुनिया"), "नमस्ते दुनिया"); /// assert_eq!(cm.fold_turkic_string("Привет мир"), "привет мир"); /// ``` - pub fn fold_turkic_string(&self, src: &str) -> String { + pub fn fold_turkic_string(self, src: &str) -> String { self.fold_turkic(src).write_to_string().into_owned() } /// Adds all simple case mappings and the full case folding for `c` to `set`. /// Also adds special case closure mappings. /// - /// Identical to [`CaseMapCloser::add_case_closure_to()`], see docs there for more information. + /// Identical to [`CaseMapCloserBorrowed::add_case_closure_to()`], see docs there for more information. /// This method is duplicated so that one does not need to load extra unfold data - /// if they only need this and not also [`CaseMapCloser::add_string_case_closure_to()`]. + /// if they only need this and not also [`CaseMapCloserBorrowed::add_string_case_closure_to()`]. /// /// /// # Examples @@ -449,16 +447,16 @@ impl CaseMapper { /// assert!(!set.contains('s')); // does not contain itself /// ``` /// - /// [`CaseMapCloser::add_case_closure_to()`]: crate::CaseMapCloser::add_case_closure_to - /// [`CaseMapCloser::add_string_case_closure_to()`]: crate::CaseMapCloser::add_string_case_closure_to - pub fn add_case_closure_to(&self, c: char, set: &mut S) { - self.data.get().add_case_closure_to(c, set); + /// [`CaseMapCloserBorrowed::add_case_closure_to()`]: crate::CaseMapCloserBorrowed::add_case_closure_to + /// [`CaseMapCloserBorrowed::add_string_case_closure_to()`]: crate::CaseMapCloserBorrowed::add_string_case_closure_to + pub fn add_case_closure_to(self, c: char, set: &mut S) { + self.data.add_case_closure_to(c, set); } /// Returns the lowercase mapping of the given `char`. /// This function only implements simple and common mappings. Full mappings, /// which can map one `char` to a string, are not included. - /// For full mappings, use [`CaseMapper::lowercase`]. + /// For full mappings, use [`CaseMapperBorrowed::lowercase`]. /// /// # Examples /// @@ -472,14 +470,14 @@ impl CaseMapper { /// assert_eq!(cm.simple_lowercase('Ć'), 'ć'); /// assert_eq!(cm.simple_lowercase('Γ'), 'γ'); /// ``` - pub fn simple_lowercase(&self, c: char) -> char { - self.data.get().simple_lower(c) + pub fn simple_lowercase(self, c: char) -> char { + self.data.simple_lower(c) } /// Returns the uppercase mapping of the given `char`. /// This function only implements simple and common mappings. Full mappings, /// which can map one `char` to a string, are not included. - /// For full mappings, use [`CaseMapper::uppercase`]. + /// For full mappings, use [`CaseMapperBorrowed::uppercase`]. /// /// # Examples /// @@ -495,8 +493,8 @@ impl CaseMapper { /// /// assert_eq!(cm.simple_uppercase('dz'), 'DZ'); /// ``` - pub fn simple_uppercase(&self, c: char) -> char { - self.data.get().simple_upper(c) + pub fn simple_uppercase(self, c: char) -> char { + self.data.simple_upper(c) } /// Returns the titlecase mapping of the given `char`. @@ -517,26 +515,26 @@ impl CaseMapper { /// assert_eq!(cm.simple_titlecase('ć'), 'Ć'); /// assert_eq!(cm.simple_titlecase('γ'), 'Γ'); /// ``` - pub fn simple_titlecase(&self, c: char) -> char { - self.data.get().simple_title(c) + pub fn simple_titlecase(self, c: char) -> char { + self.data.simple_title(c) } /// Returns the simple case folding of the given char. - /// For full mappings, use [`CaseMapper::fold`]. + /// For full mappings, use [`CaseMapperBorrowed::fold`]. /// /// This function can be used to perform caseless matches on /// individual characters. /// > *Note:* With Unicode 15.0 data, there are three /// > pairs of characters for which equivalence under this /// > function is inconsistent with equivalence of the - /// > one-character strings under [`CaseMapper::fold`]. + /// > one-character strings under [`CaseMapperBorrowed::fold`]. /// > This is resolved in Unicode 15.1 and later. /// /// For compatibility applications where simple case folding /// of strings is required, this function can be applied to /// each character of a string. Note that the resulting /// equivalence relation is different from that obtained - /// by [`CaseMapper::fold`]: + /// by [`CaseMapperBorrowed::fold`]: /// The strings "Straße" and "STRASSE" are distinct /// under simple case folding, but are equivalent under /// default (full) case folding. @@ -562,18 +560,18 @@ impl CaseMapper { /// assert_eq!(cm.simple_fold('İ'), 'İ'); /// assert_eq!(cm.simple_fold('ı'), 'ı'); /// ``` - pub fn simple_fold(&self, c: char) -> char { - self.data.get().simple_fold(c, FoldOptions::default()) + pub fn simple_fold(self, c: char) -> char { + self.data.simple_fold(c, FoldOptions::default()) } /// Returns the simple case folding of the given char, using Turkic (T) mappings for /// dotted/dotless i. This function does not fold `i` and `I` to the same character. Instead, /// `I` will fold to `ı`, and `İ` will fold to `i`. Otherwise, this is the same as - /// [`CaseMapper::fold()`]. + /// [`CaseMapperBorrowed::fold()`]. /// /// You can use the case folding to perform Turkic caseless matches on characters /// provided they don't full-casefold to strings. To avoid that situation, - /// convert to a string and use [`CaseMapper::fold_turkic`]. + /// convert to a string and use [`CaseMapperBorrowed::fold_turkic`]. /// /// /// # Examples @@ -586,13 +584,64 @@ impl CaseMapper { /// assert_eq!(cm.simple_fold_turkic('I'), 'ı'); /// assert_eq!(cm.simple_fold_turkic('İ'), 'i'); /// ``` - pub fn simple_fold_turkic(&self, c: char) -> char { + pub fn simple_fold_turkic(self, c: char) -> char { self.data - .get() .simple_fold(c, FoldOptions::with_turkic_mappings()) } } +impl CaseMapper { + /// Creates a [`CaseMapperBorrowed`] using compiled data. + /// + /// ✨ *Enabled with the `compiled_data` Cargo feature.* + /// + /// [📚 Help choosing a constructor](icu_provider::constructors) + /// + /// # Examples + /// + /// ```rust + /// use icu::casemap::CaseMapper; + /// use icu::locale::langid; + /// + /// let cm = CaseMapper::new(); + /// + /// assert_eq!( + /// cm.uppercase_to_string("hello world", &langid!("und")), + /// "HELLO WORLD" + /// ); + /// ``` + #[cfg(feature = "compiled_data")] + #[allow(clippy::new_ret_no_self)] // Intentional + pub const fn new() -> CaseMapperBorrowed<'static> { + CaseMapperBorrowed::new() + } + + /// Constructs a borrowed version of this type for more efficient querying. + pub fn as_borrowed(&self) -> CaseMapperBorrowed<'_> { + CaseMapperBorrowed { + data: self.data.get(), + } + } + + icu_provider::gen_any_buffer_data_constructors!(() -> error: DataError, + functions: [ + new: skip, + try_new_with_any_provider, + try_new_with_buffer_provider, + try_new_unstable, + Self, + ]); + + #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::new)] + pub fn try_new_unstable

(provider: &P) -> Result + where + P: DataProvider + ?Sized, + { + let data = provider.load(Default::default())?.payload; + Ok(Self { data }) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/components/casemap/src/closer.rs b/components/casemap/src/closer.rs index 6be826acfa4..f2aae43b5eb 100644 --- a/components/casemap/src/closer.rs +++ b/components/casemap/src/closer.rs @@ -2,9 +2,9 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use crate::provider::{CaseMapUnfoldV1, CaseMapV1}; +use crate::provider::{CaseMapUnfold, CaseMapUnfoldV1, CaseMapV1}; use crate::set::ClosureSink; -use crate::CaseMapper; +use crate::{CaseMapper, CaseMapperBorrowed}; use icu_provider::prelude::*; @@ -12,6 +12,9 @@ use icu_provider::prelude::*; /// over a character or string. This wrapper can be constructed directly, or /// by wrapping a reference to an existing [`CaseMapper`]. /// +/// Most methods for this type live on [`CaseMapCloserBorrowed`], which you can obtain via +/// [`CaseMapCloser::new()`] or [`CaseMapCloser::as_borrowed()`]. +/// /// # Examples /// /// ```rust @@ -40,16 +43,29 @@ pub struct CaseMapCloser { unfold: DataPayload, } -#[cfg(feature = "compiled_data")] -impl Default for CaseMapCloser { - /// ✨ *Enabled with the `compiled_data` Cargo feature.* - fn default() -> Self { - Self::new() +impl CaseMapCloser { + icu_provider::gen_any_buffer_data_constructors!(() -> error: DataError, + functions: [ + new: skip, + try_new_with_any_provider, + try_new_with_buffer_provider, + try_new_unstable, + Self, + ]); + + #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::new)] + pub fn try_new_unstable

(provider: &P) -> Result + where + P: DataProvider + DataProvider + ?Sized, + { + let cm = CaseMapper::try_new_unstable(provider)?; + let unfold = provider.load(Default::default())?.payload; + Ok(Self { cm, unfold }) } } impl CaseMapCloser { - /// A constructor which creates a [`CaseMapCloser`] using compiled data. + /// A constructor which creates a [`CaseMapCloserBorrowed`] using compiled data. /// /// # Examples /// @@ -78,32 +94,9 @@ impl CaseMapCloser { /// /// [📚 Help choosing a constructor](icu_provider::constructors) #[cfg(feature = "compiled_data")] - pub const fn new() -> Self { - Self { - cm: CaseMapper::new(), - unfold: DataPayload::from_static_ref( - crate::provider::Baked::SINGLETON_CASE_MAP_UNFOLD_V1, - ), - } - } - - icu_provider::gen_any_buffer_data_constructors!(() -> error: DataError, - functions: [ - new: skip, - try_new_with_any_provider, - try_new_with_buffer_provider, - try_new_unstable, - Self, - ]); - - #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::new)] - pub fn try_new_unstable

(provider: &P) -> Result - where - P: DataProvider + DataProvider + ?Sized, - { - let cm = CaseMapper::try_new_unstable(provider)?; - let unfold = provider.load(Default::default())?.payload; - Ok(Self { cm, unfold }) + #[allow(clippy::new_ret_no_self)] // Intentional + pub const fn new() -> CaseMapCloserBorrowed<'static> { + CaseMapCloserBorrowed::new() } } @@ -147,6 +140,80 @@ impl> CaseMapCloser { }) } + /// Constructs a borrowed version of this type for more efficient querying. + pub fn as_borrowed(&self) -> CaseMapCloserBorrowed<'_> { + CaseMapCloserBorrowed { + cm: self.cm.as_ref().as_borrowed(), + unfold: self.unfold.get(), + } + } +} + +/// A borrowed [`CaseMapCloser`]. +/// +/// See methods or [`CaseMapCloser`] for examples. +#[derive(Clone, Debug, Copy)] +pub struct CaseMapCloserBorrowed<'a> { + cm: CaseMapperBorrowed<'a>, + unfold: &'a CaseMapUnfold<'a>, +} + +impl CaseMapCloserBorrowed<'static> { + /// A constructor which creates a [`CaseMapCloserBorrowed`] using compiled data. + /// + /// # Examples + /// + /// ```rust + /// use icu::casemap::CaseMapCloser; + /// use icu::collections::codepointinvlist::CodePointInversionListBuilder; + /// + /// let cm = CaseMapCloser::new(); + /// let mut builder = CodePointInversionListBuilder::new(); + /// let found = cm.add_string_case_closure_to("ffi", &mut builder); + /// assert!(found); + /// let set = builder.build(); + /// + /// assert!(set.contains('ffi')); + /// + /// let mut builder = CodePointInversionListBuilder::new(); + /// let found = cm.add_string_case_closure_to("ss", &mut builder); + /// assert!(found); + /// let set = builder.build(); + /// + /// assert!(set.contains('ß')); + /// assert!(set.contains('ẞ')); + /// ``` + /// + /// ✨ *Enabled with the `compiled_data` Cargo feature.* + /// + /// [📚 Help choosing a constructor](icu_provider::constructors) + #[cfg(feature = "compiled_data")] + pub const fn new() -> CaseMapCloserBorrowed<'static> { + CaseMapCloserBorrowed { + cm: CaseMapper::new(), + unfold: crate::provider::Baked::SINGLETON_CASE_MAP_UNFOLD_V1, + } + } + /// Cheaply converts a [`CaseMapCloserBorrowed<'static>`] into a [`CaseMapCloser`]. + /// + /// Note: Due to branching and indirection, using [`CaseMapCloser`] might inhibit some + /// compile-time optimizations that are possible with [`CaseMapCloserBorrowed`]. + pub const fn static_to_owned(self) -> CaseMapCloser { + CaseMapCloser { + cm: self.cm.static_to_owned(), + unfold: DataPayload::from_static_ref(self.unfold), + } + } +} + +#[cfg(feature = "compiled_data")] +impl Default for CaseMapCloserBorrowed<'static> { + fn default() -> Self { + Self::new() + } +} + +impl CaseMapCloserBorrowed<'_> { /// Adds all simple case mappings and the full case folding for `c` to `set`. /// Also adds special case closure mappings. /// @@ -160,7 +227,7 @@ impl> CaseMapCloser { /// - for sharp s include ss /// - for k include the Kelvin sign /// - /// This function is identical to [`CaseMapper::add_case_closure_to()`]; if you don't + /// This function is identical to [`CaseMapperBorrowed::add_case_closure_to()`]; if you don't /// need [`Self::add_string_case_closure_to()`] consider using a [`CaseMapper`] to avoid /// loading additional data. /// @@ -180,8 +247,8 @@ impl> CaseMapCloser { /// assert!(set.contains('ſ')); /// assert!(!set.contains('s')); // does not contain itself /// ``` - pub fn add_case_closure_to(&self, c: char, set: &mut S) { - self.cm.as_ref().add_case_closure_to(c, set); + pub fn add_case_closure_to(self, c: char, set: &mut S) { + self.cm.add_case_closure_to(c, set); } /// Finds all characters and strings which may casemap to `s` as their full case folding string @@ -216,11 +283,7 @@ impl> CaseMapCloser { /// assert!(set.contains('ß')); /// assert!(set.contains('ẞ')); /// ``` - pub fn add_string_case_closure_to(&self, s: &str, set: &mut S) -> bool { - self.cm - .as_ref() - .data - .get() - .add_string_case_closure_to(s, set, self.unfold.get()) + pub fn add_string_case_closure_to(self, s: &str, set: &mut S) -> bool { + self.cm.data.add_string_case_closure_to(s, set, self.unfold) } } diff --git a/components/casemap/src/lib.rs b/components/casemap/src/lib.rs index cc0f3ee14e1..194a294486e 100644 --- a/components/casemap/src/lib.rs +++ b/components/casemap/src/lib.rs @@ -59,7 +59,7 @@ pub mod titlecase; pub mod greek_to_me; mod internals; -pub use casemapper::CaseMapper; -pub use closer::CaseMapCloser; +pub use casemapper::{CaseMapper, CaseMapperBorrowed}; +pub use closer::{CaseMapCloser, CaseMapCloserBorrowed}; pub use set::ClosureSink; -pub use titlecase::TitlecaseMapper; +pub use titlecase::{TitlecaseMapper, TitlecaseMapperBorrowed}; diff --git a/components/casemap/src/set.rs b/components/casemap/src/set.rs index fd7478c4355..d5d02eb79a1 100644 --- a/components/casemap/src/set.rs +++ b/components/casemap/src/set.rs @@ -5,8 +5,8 @@ use icu_collections::codepointinvlist::CodePointInversionListBuilder; /// An object that accepts characters and/or strings -/// to be used with [`CaseMapCloser::add_string_case_closure_to()`] -/// and [`CaseMapCloser::add_case_closure_to()`]. +/// to be used with [`CaseMapCloserBorrowed::add_string_case_closure_to()`] +/// and [`CaseMapCloserBorrowed::add_case_closure_to()`]. /// /// Usually this object /// will be some kind of set over codepoints and strings, or something that @@ -15,8 +15,8 @@ use icu_collections::codepointinvlist::CodePointInversionListBuilder; /// An implementation is provided for [`CodePointInversionListBuilder`], but users are encouraged /// to implement this trait on their own collections as needed. /// -/// [`CaseMapCloser::add_string_case_closure_to()`]: crate::CaseMapCloser::add_string_case_closure_to -/// [`CaseMapCloser::add_case_closure_to()`]: crate::CaseMapCloser::add_case_closure_to +/// [`CaseMapCloserBorrowed::add_string_case_closure_to()`]: crate::CaseMapCloserBorrowed::add_string_case_closure_to +/// [`CaseMapCloserBorrowed::add_case_closure_to()`]: crate::CaseMapCloserBorrowed::add_case_closure_to pub trait ClosureSink { /// Add a character to the set fn add_char(&mut self, c: char); diff --git a/components/casemap/src/titlecase.rs b/components/casemap/src/titlecase.rs index cca7fde5ca3..343423a6c89 100644 --- a/components/casemap/src/titlecase.rs +++ b/components/casemap/src/titlecase.rs @@ -4,12 +4,12 @@ //! Titlecasing-specific try_new_with_mapper_unstable use crate::provider::CaseMapV1; -use crate::CaseMapper; +use crate::{CaseMapper, CaseMapperBorrowed}; use alloc::string::String; use icu_locale_core::LanguageIdentifier; use icu_properties::props::{GeneralCategory, GeneralCategoryGroup}; use icu_properties::provider::GeneralCategoryV1; -use icu_properties::CodePointMapData; +use icu_properties::{CodePointMapData, CodePointMapDataBorrowed}; use icu_provider::prelude::*; use writeable::Writeable; @@ -128,7 +128,7 @@ pub enum LeadingAdjustment { /// Adjust the string to the first relevant character before beginning to apply casing /// ("'twixt" -> "'Twixt"). "Relevant" character is picked by best available algorithm, /// by default will adjust to first letter, number, symbol, or private use character, - /// but if no data is available (e.g. this API is being called via [`CaseMapper::titlecase_segment_with_only_case_data()`]), + /// but if no data is available (e.g. this API is being called via [`CaseMapperBorrowed::titlecase_segment_with_only_case_data()`]), /// then may be equivalent to "adjust to cased". /// /// This is the default @@ -161,7 +161,10 @@ pub struct TitlecaseOptions { /// to support the non-legacy "head adjustment" behavior. /// /// -/// By default, [`Self::titlecase_segment()`] and [`Self::titlecase_segment_to_string()`] perform "leading adjustment", +/// Most methods for this type live on [`TitlecaseMapperBorrowed`], which you can obtain via +/// [`TitlecaseMapper::new()`] or [`TitlecaseMapper::as_borrowed()`]. +/// +/// By default, [`TitlecaseMapperBorrowed::titlecase_segment()`] and [`TitlecaseMapperBorrowed::titlecase_segment_to_string()`] perform "leading adjustment", /// where they wait till the first relevant character to begin titlecasing. For example, in the string `'twixt`, the apostrophe /// is ignored because the word starts at the first "t", which will get titlecased (producing `'Twixt`). Other punctuation will /// also be ignored, like in the string `«hello»`, which will get titlecased to `«Hello»`. @@ -208,28 +211,7 @@ pub struct TitlecaseMapper { gc: CodePointMapData, } -#[cfg(feature = "compiled_data")] -impl Default for TitlecaseMapper { - fn default() -> Self { - Self::new() - } -} - impl TitlecaseMapper { - /// A constructor which creates a [`TitlecaseMapper`] using compiled data - /// - /// ✨ *Enabled with the `compiled_data` Cargo feature.* - /// - /// [📚 Help choosing a constructor](icu_provider::constructors) - #[cfg(feature = "compiled_data")] - pub const fn new() -> Self { - Self { - cm: CaseMapper::new(), - gc: icu_properties::CodePointMapData::::new() - .static_to_owned(), - } - } - icu_provider::gen_any_buffer_data_constructors!(() -> error: DataError, functions: [ new: skip, @@ -250,6 +232,18 @@ impl TitlecaseMapper { } } +impl TitlecaseMapper { + /// A constructor which creates a [`TitlecaseMapperBorrowed`] using compiled data + /// + /// ✨ *Enabled with the `compiled_data` Cargo feature.* + /// + /// [📚 Help choosing a constructor](icu_provider::constructors) + #[cfg(feature = "compiled_data")] + #[allow(clippy::new_ret_no_self)] // Intentional + pub const fn new() -> TitlecaseMapperBorrowed<'static> { + TitlecaseMapperBorrowed::new() + } +} // We use Borrow, not AsRef, since we want the blanket impl on T impl> TitlecaseMapper { icu_provider::gen_any_buffer_data_constructors!((casemapper: CM) -> error: DataError, @@ -286,6 +280,57 @@ impl> TitlecaseMapper { Ok(Self { cm: casemapper, gc }) } + /// Constructs a borrowed version of this type for more efficient querying. + pub fn as_borrowed(&self) -> TitlecaseMapperBorrowed<'_> { + TitlecaseMapperBorrowed { + cm: self.cm.as_ref().as_borrowed(), + gc: self.gc.as_borrowed(), + } + } +} + +/// A borrowed [`TitlecaseMapper`]. +/// +/// See methods or [`TitlecaseMapper`] for examples. +#[derive(Clone, Debug, Copy)] +pub struct TitlecaseMapperBorrowed<'a> { + cm: CaseMapperBorrowed<'a>, + gc: CodePointMapDataBorrowed<'a, GeneralCategory>, +} + +impl TitlecaseMapperBorrowed<'static> { + /// A constructor which creates a [`TitlecaseMapperBorrowed`] using compiled data + /// + /// ✨ *Enabled with the `compiled_data` Cargo feature.* + /// + /// [📚 Help choosing a constructor](icu_provider::constructors) + #[cfg(feature = "compiled_data")] + pub const fn new() -> Self { + Self { + cm: CaseMapper::new(), + gc: icu_properties::CodePointMapData::::new(), + } + } + /// Cheaply converts a [`TitlecaseMapperBorrowed<'static>`] into a [`TitlecaseMapper`]. + /// + /// Note: Due to branching and indirection, using [`TitlecaseMapper`] might inhibit some + /// compile-time optimizations that are possible with [`TitlecaseMapper`]. + pub const fn static_to_owned(self) -> TitlecaseMapper { + TitlecaseMapper { + cm: self.cm.static_to_owned(), + gc: self.gc.static_to_owned(), + } + } +} + +#[cfg(feature = "compiled_data")] +impl Default for TitlecaseMapperBorrowed<'static> { + fn default() -> Self { + Self::new() + } +} + +impl<'a> TitlecaseMapperBorrowed<'a> { /// Returns the full titlecase mapping of the given string as a [`Writeable`], treating /// the string as a single segment (and thus only titlecasing the beginning of it). /// @@ -297,10 +342,10 @@ impl> TitlecaseMapper { /// as a `LanguageIdentifier` (usually the `id` field of the `Locale`) if available, or /// `Default::default()` for the root locale. /// - /// See [`Self::titlecase_segment_to_string()`] for the equivalent convenience function that returns a String, + /// See [`TitlecaseMapperBorrowed::titlecase_segment_to_string()`] for the equivalent convenience function that returns a String, /// as well as for an example. - pub fn titlecase_segment<'a>( - &'a self, + pub fn titlecase_segment( + self, src: &'a str, langid: &LanguageIdentifier, options: TitlecaseOptions, @@ -312,13 +357,11 @@ impl> TitlecaseMapper { .union(GeneralCategoryGroup::Symbol) .union(GeneralCategoryGroup::PrivateUse); self.cm - .as_ref() .titlecase_segment_with_adjustment(src, langid, options, |_data, ch| { - HEAD_GROUPS.contains(self.gc.as_borrowed().get(ch)) + HEAD_GROUPS.contains(self.gc.get(ch)) }) } else { self.cm - .as_ref() .titlecase_segment_with_adjustment(src, langid, options, |data, ch| { data.is_cased(ch) }) @@ -336,7 +379,7 @@ impl> TitlecaseMapper { /// as a `LanguageIdentifier` (usually the `id` field of the `Locale`) if available, or /// `Default::default()` for the root locale. /// - /// See [`Self::titlecase_segment()`] for the equivalent lower-level function that returns a [`Writeable`] + /// See [`TitlecaseMapperBorrowed::titlecase_segment()`] for the equivalent lower-level function that returns a [`Writeable`] /// /// # Examples /// @@ -432,7 +475,7 @@ impl> TitlecaseMapper { /// ); /// ``` pub fn titlecase_segment_to_string( - &self, + self, src: &str, langid: &LanguageIdentifier, options: TitlecaseOptions, diff --git a/components/experimental/tests/transliterate/lower_ascii.rs b/components/experimental/tests/transliterate/lower_ascii.rs index bfe883f17a8..93f6d5ea916 100644 --- a/components/experimental/tests/transliterate/lower_ascii.rs +++ b/components/experimental/tests/transliterate/lower_ascii.rs @@ -4,7 +4,7 @@ use core::any::TypeId; -use icu::casemap::CaseMapper; +use icu::casemap::CaseMapperBorrowed; use icu_experimental::transliterate::{ provider::TransliteratorRulesV1, CustomTransliterator, RuleCollection, RuleCollectionProvider, Transliterator, @@ -44,7 +44,7 @@ where } #[derive(Debug)] -struct LowercaseTransliterator(CaseMapper); +struct LowercaseTransliterator(CaseMapperBorrowed<'static>); impl CustomTransliterator for LowercaseTransliterator { fn transliterate(&self, input: &str, range: std::ops::Range) -> String { @@ -88,7 +88,9 @@ fn test_lower_ascii() { &"und-t-und-x0-lowascii".parse().unwrap(), |locale| { if locale.normalizing_eq("und-t-und-x0-lower") { - Some(Ok(Box::new(LowercaseTransliterator(CaseMapper::new())))) + Some(Ok(Box::new(LowercaseTransliterator( + CaseMapperBorrowed::new(), + )))) } else { None } diff --git a/ffi/capi/bindings/dart/CaseMapCloser.g.dart b/ffi/capi/bindings/dart/CaseMapCloser.g.dart index 20710080a09..7b4db924150 100644 --- a/ffi/capi/bindings/dart/CaseMapCloser.g.dart +++ b/ffi/capi/bindings/dart/CaseMapCloser.g.dart @@ -51,7 +51,7 @@ final class CaseMapCloser implements ffi.Finalizable { /// Adds all simple case mappings and the full case folding for `c` to `builder`. /// Also adds special case closure mappings. /// - /// See the [Rust documentation for `add_case_closure_to`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapCloser.html#method.add_case_closure_to) for more information. + /// See the [Rust documentation for `add_case_closure_to`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapCloserBorrowed.html#method.add_case_closure_to) for more information. void addCaseClosureTo(Rune c, CodePointSetBuilder builder) { _icu4x_CaseMapCloser_add_case_closure_to_mv1(_ffi, c, builder._ffi); } @@ -61,7 +61,7 @@ final class CaseMapCloser implements ffi.Finalizable { /// /// Returns true if the string was found /// - /// See the [Rust documentation for `add_string_case_closure_to`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapCloser.html#method.add_string_case_closure_to) for more information. + /// See the [Rust documentation for `add_string_case_closure_to`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapCloserBorrowed.html#method.add_string_case_closure_to) for more information. bool addStringCaseClosureTo(String s, CodePointSetBuilder builder) { final temp = _FinalizedArena(); final result = _icu4x_CaseMapCloser_add_string_case_closure_to_mv1(_ffi, s._utf8AllocIn(temp.arena), builder._ffi); diff --git a/ffi/capi/bindings/dart/CaseMapper.g.dart b/ffi/capi/bindings/dart/CaseMapper.g.dart index 5204c9c11fe..94487651bad 100644 --- a/ffi/capi/bindings/dart/CaseMapper.g.dart +++ b/ffi/capi/bindings/dart/CaseMapper.g.dart @@ -45,7 +45,7 @@ final class CaseMapper implements ffi.Finalizable { /// Returns the full lowercase mapping of the given string /// - /// See the [Rust documentation for `lowercase`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapper.html#method.lowercase) for more information. + /// See the [Rust documentation for `lowercase`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapperBorrowed.html#method.lowercase) for more information. String lowercase(String s, Locale locale) { final temp = _FinalizedArena(); final write = _Write(); @@ -55,7 +55,7 @@ final class CaseMapper implements ffi.Finalizable { /// Returns the full uppercase mapping of the given string /// - /// See the [Rust documentation for `uppercase`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapper.html#method.uppercase) for more information. + /// See the [Rust documentation for `uppercase`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapperBorrowed.html#method.uppercase) for more information. String uppercase(String s, Locale locale) { final temp = _FinalizedArena(); final write = _Write(); @@ -69,7 +69,7 @@ final class CaseMapper implements ffi.Finalizable { /// /// The `v1` refers to the version of the options struct, which may change as we add more options /// - /// See the [Rust documentation for `titlecase_segment_with_only_case_data`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapper.html#method.titlecase_segment_with_only_case_data) for more information. + /// See the [Rust documentation for `titlecase_segment_with_only_case_data`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapperBorrowed.html#method.titlecase_segment_with_only_case_data) for more information. String titlecaseSegmentWithOnlyCaseData(String s, Locale locale, TitlecaseOptions options) { final temp = _FinalizedArena(); final write = _Write(); @@ -79,7 +79,7 @@ final class CaseMapper implements ffi.Finalizable { /// Case-folds the characters in the given string /// - /// See the [Rust documentation for `fold`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapper.html#method.fold) for more information. + /// See the [Rust documentation for `fold`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapperBorrowed.html#method.fold) for more information. String fold(String s) { final temp = _FinalizedArena(); final write = _Write(); @@ -90,7 +90,7 @@ final class CaseMapper implements ffi.Finalizable { /// Case-folds the characters in the given string /// using Turkic (T) mappings for dotted/dotless I. /// - /// See the [Rust documentation for `fold_turkic`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapper.html#method.fold_turkic) for more information. + /// See the [Rust documentation for `fold_turkic`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapperBorrowed.html#method.fold_turkic) for more information. String foldTurkic(String s) { final temp = _FinalizedArena(); final write = _Write(); @@ -110,7 +110,7 @@ final class CaseMapper implements ffi.Finalizable { /// Identical to the similarly named method on `CaseMapCloser`, use that if you /// plan on using string case closure mappings too. /// - /// See the [Rust documentation for `add_case_closure_to`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapper.html#method.add_case_closure_to) for more information. + /// See the [Rust documentation for `add_case_closure_to`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapperBorrowed.html#method.add_case_closure_to) for more information. void addCaseClosureTo(Rune c, CodePointSetBuilder builder) { _icu4x_CaseMapper_add_case_closure_to_mv1(_ffi, c, builder._ffi); } @@ -119,9 +119,9 @@ final class CaseMapper implements ffi.Finalizable { /// /// This function only implements simple and common mappings. /// Full mappings, which can map one char to a string, are not included. - /// For full mappings, use `CaseMapper::lowercase`. + /// For full mappings, use `CaseMapperBorrowed::lowercase`. /// - /// See the [Rust documentation for `simple_lowercase`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapper.html#method.simple_lowercase) for more information. + /// See the [Rust documentation for `simple_lowercase`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapperBorrowed.html#method.simple_lowercase) for more information. Rune simpleLowercase(Rune ch) { final result = _icu4x_CaseMapper_simple_lowercase_mv1(_ffi, ch); return result; @@ -131,9 +131,9 @@ final class CaseMapper implements ffi.Finalizable { /// /// This function only implements simple and common mappings. /// Full mappings, which can map one char to a string, are not included. - /// For full mappings, use `CaseMapper::uppercase`. + /// For full mappings, use `CaseMapperBorrowed::uppercase`. /// - /// See the [Rust documentation for `simple_uppercase`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapper.html#method.simple_uppercase) for more information. + /// See the [Rust documentation for `simple_uppercase`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapperBorrowed.html#method.simple_uppercase) for more information. Rune simpleUppercase(Rune ch) { final result = _icu4x_CaseMapper_simple_uppercase_mv1(_ffi, ch); return result; @@ -143,9 +143,9 @@ final class CaseMapper implements ffi.Finalizable { /// /// This function only implements simple and common mappings. /// Full mappings, which can map one char to a string, are not included. - /// For full mappings, use `CaseMapper::titlecase_segment`. + /// For full mappings, use `CaseMapperBorrowed::titlecase_segment`. /// - /// See the [Rust documentation for `simple_titlecase`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapper.html#method.simple_titlecase) for more information. + /// See the [Rust documentation for `simple_titlecase`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapperBorrowed.html#method.simple_titlecase) for more information. Rune simpleTitlecase(Rune ch) { final result = _icu4x_CaseMapper_simple_titlecase_mv1(_ffi, ch); return result; @@ -154,9 +154,9 @@ final class CaseMapper implements ffi.Finalizable { /// Returns the simple casefolding of the given character. /// /// This function only implements simple folding. - /// For full folding, use `CaseMapper::fold`. + /// For full folding, use `CaseMapperBorrowed::fold`. /// - /// See the [Rust documentation for `simple_fold`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapper.html#method.simple_fold) for more information. + /// See the [Rust documentation for `simple_fold`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapperBorrowed.html#method.simple_fold) for more information. Rune simpleFold(Rune ch) { final result = _icu4x_CaseMapper_simple_fold_mv1(_ffi, ch); return result; @@ -165,9 +165,9 @@ final class CaseMapper implements ffi.Finalizable { /// Returns the simple casefolding of the given character in the Turkic locale /// /// This function only implements simple folding. - /// For full folding, use `CaseMapper::fold_turkic`. + /// For full folding, use `CaseMapperBorrowed::fold_turkic`. /// - /// See the [Rust documentation for `simple_fold_turkic`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapper.html#method.simple_fold_turkic) for more information. + /// See the [Rust documentation for `simple_fold_turkic`](https://docs.rs/icu/latest/icu/casemap/struct.CaseMapperBorrowed.html#method.simple_fold_turkic) for more information. Rune simpleFoldTurkic(Rune ch) { final result = _icu4x_CaseMapper_simple_fold_turkic_mv1(_ffi, ch); return result; diff --git a/ffi/capi/bindings/dart/TitlecaseMapper.g.dart b/ffi/capi/bindings/dart/TitlecaseMapper.g.dart index b2c91ae1d98..33f654c1bcd 100644 --- a/ffi/capi/bindings/dart/TitlecaseMapper.g.dart +++ b/ffi/capi/bindings/dart/TitlecaseMapper.g.dart @@ -52,7 +52,7 @@ final class TitlecaseMapper implements ffi.Finalizable { /// /// The `v1` refers to the version of the options struct, which may change as we add more options /// - /// See the [Rust documentation for `titlecase_segment`](https://docs.rs/icu/latest/icu/casemap/struct.TitlecaseMapper.html#method.titlecase_segment) for more information. + /// See the [Rust documentation for `titlecase_segment`](https://docs.rs/icu/latest/icu/casemap/struct.TitlecaseMapperBorrowed.html#method.titlecase_segment) for more information. String titlecaseSegment(String s, Locale locale, TitlecaseOptions options) { final temp = _FinalizedArena(); final write = _Write(); diff --git a/ffi/capi/src/casemap.rs b/ffi/capi/src/casemap.rs index 7945e9e20f3..704ddd152cf 100644 --- a/ffi/capi/src/casemap.rs +++ b/ffi/capi/src/casemap.rs @@ -55,15 +55,17 @@ pub mod ffi { #[diplomat::opaque] #[diplomat::rust_link(icu::casemap::CaseMapper, Struct)] + #[diplomat::rust_link(icu::casemap::CaseMapperBorrowed, Struct, hidden)] pub struct CaseMapper(pub icu_casemap::CaseMapper); impl CaseMapper { /// Construct a new CaseMapper instance using compiled data. #[diplomat::rust_link(icu::casemap::CaseMapper::new, FnInStruct)] + #[diplomat::rust_link(icu::casemap::CaseMapperBorrowed::new, FnInStruct, hidden)] #[diplomat::attr(auto, constructor)] #[cfg(feature = "compiled_data")] pub fn create() -> Box { - Box::new(CaseMapper(icu_casemap::CaseMapper::new())) + Box::new(CaseMapper(icu_casemap::CaseMapper::new().static_to_owned())) } /// Construct a new CaseMapper instance using a particular data source. @@ -76,17 +78,33 @@ pub mod ffi { ))) } /// Returns the full lowercase mapping of the given string - #[diplomat::rust_link(icu::casemap::CaseMapper::lowercase, FnInStruct)] - #[diplomat::rust_link(icu::casemap::CaseMapper::lowercase_to_string, FnInStruct, hidden)] + #[diplomat::rust_link(icu::casemap::CaseMapperBorrowed::lowercase, FnInStruct)] + #[diplomat::rust_link( + icu::casemap::CaseMapperBorrowed::lowercase_to_string, + FnInStruct, + hidden + )] pub fn lowercase(&self, s: &str, locale: &Locale, write: &mut DiplomatWrite) { - let _infallible = self.0.lowercase(s, &locale.0.id).write_to(write); + let _infallible = self + .0 + .as_borrowed() + .lowercase(s, &locale.0.id) + .write_to(write); } /// Returns the full uppercase mapping of the given string - #[diplomat::rust_link(icu::casemap::CaseMapper::uppercase, FnInStruct)] - #[diplomat::rust_link(icu::casemap::CaseMapper::uppercase_to_string, FnInStruct, hidden)] + #[diplomat::rust_link(icu::casemap::CaseMapperBorrowed::uppercase, FnInStruct)] + #[diplomat::rust_link( + icu::casemap::CaseMapperBorrowed::uppercase_to_string, + FnInStruct, + hidden + )] pub fn uppercase(&self, s: &str, locale: &Locale, write: &mut DiplomatWrite) { - let _infallible = self.0.uppercase(s, &locale.0.id).write_to(write); + let _infallible = self + .0 + .as_borrowed() + .uppercase(s, &locale.0.id) + .write_to(write); } /// Returns the full titlecase mapping of the given string, performing head adjustment without @@ -95,11 +113,11 @@ pub mod ffi { /// /// The `v1` refers to the version of the options struct, which may change as we add more options #[diplomat::rust_link( - icu::casemap::CaseMapper::titlecase_segment_with_only_case_data, + icu::casemap::CaseMapperBorrowed::titlecase_segment_with_only_case_data, FnInStruct )] #[diplomat::rust_link( - icu::casemap::CaseMapper::titlecase_segment_with_only_case_data_to_string, + icu::casemap::CaseMapperBorrowed::titlecase_segment_with_only_case_data_to_string, FnInStruct, hidden )] @@ -113,22 +131,27 @@ pub mod ffi { ) { let _infallible = self .0 + .as_borrowed() .titlecase_segment_with_only_case_data(s, &locale.0.id, options.into()) .write_to(write); } /// Case-folds the characters in the given string - #[diplomat::rust_link(icu::casemap::CaseMapper::fold, FnInStruct)] - #[diplomat::rust_link(icu::casemap::CaseMapper::fold_string, FnInStruct, hidden)] + #[diplomat::rust_link(icu::casemap::CaseMapperBorrowed::fold, FnInStruct)] + #[diplomat::rust_link(icu::casemap::CaseMapperBorrowed::fold_string, FnInStruct, hidden)] pub fn fold(&self, s: &str, write: &mut DiplomatWrite) { - let _infallible = self.0.fold(s).write_to(write); + let _infallible = self.0.as_borrowed().fold(s).write_to(write); } /// Case-folds the characters in the given string /// using Turkic (T) mappings for dotted/dotless I. - #[diplomat::rust_link(icu::casemap::CaseMapper::fold_turkic, FnInStruct)] - #[diplomat::rust_link(icu::casemap::CaseMapper::fold_turkic_string, FnInStruct, hidden)] + #[diplomat::rust_link(icu::casemap::CaseMapperBorrowed::fold_turkic, FnInStruct)] + #[diplomat::rust_link( + icu::casemap::CaseMapperBorrowed::fold_turkic_string, + FnInStruct, + hidden + )] pub fn fold_turkic(&self, s: &str, write: &mut DiplomatWrite) { - let _infallible = self.0.fold_turkic(s).write_to(write); + let _infallible = self.0.as_borrowed().fold_turkic(s).write_to(write); } /// Adds all simple case mappings and the full case folding for `c` to `builder`. @@ -143,7 +166,7 @@ pub mod ffi { /// Identical to the similarly named method on `CaseMapCloser`, use that if you /// plan on using string case closure mappings too. #[cfg(feature = "properties")] - #[diplomat::rust_link(icu::casemap::CaseMapper::add_case_closure_to, FnInStruct)] + #[diplomat::rust_link(icu::casemap::CaseMapperBorrowed::add_case_closure_to, FnInStruct)] #[diplomat::rust_link(icu::casemap::ClosureSink, Trait, hidden)] #[diplomat::rust_link(icu::casemap::ClosureSink::add_char, FnInTrait, hidden)] #[diplomat::rust_link(icu::casemap::ClosureSink::add_string, FnInTrait, hidden)] @@ -153,7 +176,7 @@ pub mod ffi { builder: &mut crate::collections_sets::ffi::CodePointSetBuilder, ) { if let Some(ch) = char::from_u32(c) { - self.0.add_case_closure_to(ch, &mut builder.0) + self.0.as_borrowed().add_case_closure_to(ch, &mut builder.0) } } @@ -161,11 +184,11 @@ pub mod ffi { /// /// This function only implements simple and common mappings. /// Full mappings, which can map one char to a string, are not included. - /// For full mappings, use `CaseMapper::lowercase`. - #[diplomat::rust_link(icu::casemap::CaseMapper::simple_lowercase, FnInStruct)] + /// For full mappings, use `CaseMapperBorrowed::lowercase`. + #[diplomat::rust_link(icu::casemap::CaseMapperBorrowed::simple_lowercase, FnInStruct)] pub fn simple_lowercase(&self, ch: DiplomatChar) -> DiplomatChar { char::from_u32(ch) - .map(|ch| self.0.simple_lowercase(ch) as DiplomatChar) + .map(|ch| self.0.as_borrowed().simple_lowercase(ch) as DiplomatChar) .unwrap_or(ch) } @@ -173,11 +196,11 @@ pub mod ffi { /// /// This function only implements simple and common mappings. /// Full mappings, which can map one char to a string, are not included. - /// For full mappings, use `CaseMapper::uppercase`. - #[diplomat::rust_link(icu::casemap::CaseMapper::simple_uppercase, FnInStruct)] + /// For full mappings, use `CaseMapperBorrowed::uppercase`. + #[diplomat::rust_link(icu::casemap::CaseMapperBorrowed::simple_uppercase, FnInStruct)] pub fn simple_uppercase(&self, ch: DiplomatChar) -> DiplomatChar { char::from_u32(ch) - .map(|ch| self.0.simple_uppercase(ch) as DiplomatChar) + .map(|ch| self.0.as_borrowed().simple_uppercase(ch) as DiplomatChar) .unwrap_or(ch) } @@ -185,48 +208,52 @@ pub mod ffi { /// /// This function only implements simple and common mappings. /// Full mappings, which can map one char to a string, are not included. - /// For full mappings, use `CaseMapper::titlecase_segment`. - #[diplomat::rust_link(icu::casemap::CaseMapper::simple_titlecase, FnInStruct)] + /// For full mappings, use `CaseMapperBorrowed::titlecase_segment`. + #[diplomat::rust_link(icu::casemap::CaseMapperBorrowed::simple_titlecase, FnInStruct)] pub fn simple_titlecase(&self, ch: DiplomatChar) -> DiplomatChar { char::from_u32(ch) - .map(|ch| self.0.simple_titlecase(ch) as DiplomatChar) + .map(|ch| self.0.as_borrowed().simple_titlecase(ch) as DiplomatChar) .unwrap_or(ch) } /// Returns the simple casefolding of the given character. /// /// This function only implements simple folding. - /// For full folding, use `CaseMapper::fold`. - #[diplomat::rust_link(icu::casemap::CaseMapper::simple_fold, FnInStruct)] + /// For full folding, use `CaseMapperBorrowed::fold`. + #[diplomat::rust_link(icu::casemap::CaseMapperBorrowed::simple_fold, FnInStruct)] pub fn simple_fold(&self, ch: DiplomatChar) -> DiplomatChar { char::from_u32(ch) - .map(|ch| self.0.simple_fold(ch) as DiplomatChar) + .map(|ch| self.0.as_borrowed().simple_fold(ch) as DiplomatChar) .unwrap_or(ch) } /// Returns the simple casefolding of the given character in the Turkic locale /// /// This function only implements simple folding. - /// For full folding, use `CaseMapper::fold_turkic`. - #[diplomat::rust_link(icu::casemap::CaseMapper::simple_fold_turkic, FnInStruct)] + /// For full folding, use `CaseMapperBorrowed::fold_turkic`. + #[diplomat::rust_link(icu::casemap::CaseMapperBorrowed::simple_fold_turkic, FnInStruct)] pub fn simple_fold_turkic(&self, ch: DiplomatChar) -> DiplomatChar { char::from_u32(ch) - .map(|ch| self.0.simple_fold_turkic(ch) as DiplomatChar) + .map(|ch| self.0.as_borrowed().simple_fold_turkic(ch) as DiplomatChar) .unwrap_or(ch) } } #[diplomat::opaque] #[diplomat::rust_link(icu::casemap::CaseMapCloser, Struct)] + #[diplomat::rust_link(icu::casemap::CaseMapCloserBorrowed, Struct, hidden)] pub struct CaseMapCloser(pub icu_casemap::CaseMapCloser); impl CaseMapCloser { /// Construct a new CaseMapCloser instance using compiled data. #[diplomat::rust_link(icu::casemap::CaseMapCloser::new, FnInStruct)] + #[diplomat::rust_link(icu::casemap::CaseMapCloserBorrowed::new, FnInStruct, hidden)] #[diplomat::rust_link(icu::casemap::CaseMapCloser::new_with_mapper, FnInStruct, hidden)] #[diplomat::attr(supports = "fallible_constructors", constructor)] #[cfg(feature = "compiled_data")] pub fn create() -> Result, DataError> { - Ok(Box::new(CaseMapCloser(icu_casemap::CaseMapCloser::new()))) + Ok(Box::new(CaseMapCloser( + icu_casemap::CaseMapCloser::new().static_to_owned(), + ))) } /// Construct a new CaseMapCloser instance using a particular data source. #[diplomat::rust_link(icu::casemap::CaseMapCloser::new, FnInStruct)] @@ -243,14 +270,14 @@ pub mod ffi { /// Adds all simple case mappings and the full case folding for `c` to `builder`. /// Also adds special case closure mappings. #[cfg(feature = "properties")] - #[diplomat::rust_link(icu::casemap::CaseMapCloser::add_case_closure_to, FnInStruct)] + #[diplomat::rust_link(icu::casemap::CaseMapCloserBorrowed::add_case_closure_to, FnInStruct)] pub fn add_case_closure_to( &self, c: DiplomatChar, builder: &mut crate::collections_sets::ffi::CodePointSetBuilder, ) { if let Some(ch) = char::from_u32(c) { - self.0.add_case_closure_to(ch, &mut builder.0) + self.0.as_borrowed().add_case_closure_to(ch, &mut builder.0) } } @@ -259,30 +286,37 @@ pub mod ffi { /// /// Returns true if the string was found #[cfg(feature = "properties")] - #[diplomat::rust_link(icu::casemap::CaseMapCloser::add_string_case_closure_to, FnInStruct)] + #[diplomat::rust_link( + icu::casemap::CaseMapCloserBorrowed::add_string_case_closure_to, + FnInStruct + )] pub fn add_string_case_closure_to( &self, s: &DiplomatStr, builder: &mut crate::collections_sets::ffi::CodePointSetBuilder, ) -> bool { let s = core::str::from_utf8(s).unwrap_or(""); - self.0.add_string_case_closure_to(s, &mut builder.0) + self.0 + .as_borrowed() + .add_string_case_closure_to(s, &mut builder.0) } } #[diplomat::opaque] #[diplomat::rust_link(icu::casemap::TitlecaseMapper, Struct)] + #[diplomat::rust_link(icu::casemap::TitlecaseMapperBorrowed, Struct, hidden)] pub struct TitlecaseMapper(pub icu_casemap::TitlecaseMapper); impl TitlecaseMapper { /// Construct a new `TitlecaseMapper` instance using compiled data. #[diplomat::rust_link(icu::casemap::TitlecaseMapper::new, FnInStruct)] + #[diplomat::rust_link(icu::casemap::TitlecaseMapperBorrowed::new, FnInStruct, hidden)] #[diplomat::rust_link(icu::casemap::TitlecaseMapper::new_with_mapper, FnInStruct, hidden)] #[diplomat::attr(supports = "fallible_constructors", constructor)] #[cfg(feature = "compiled_data")] pub fn create() -> Result, DataError> { Ok(Box::new(TitlecaseMapper( - icu_casemap::TitlecaseMapper::new(), + icu_casemap::TitlecaseMapper::new().static_to_owned(), ))) } /// Construct a new `TitlecaseMapper` instance using a particular data source. @@ -300,9 +334,9 @@ pub mod ffi { /// Returns the full titlecase mapping of the given string /// /// The `v1` refers to the version of the options struct, which may change as we add more options - #[diplomat::rust_link(icu::casemap::TitlecaseMapper::titlecase_segment, FnInStruct)] + #[diplomat::rust_link(icu::casemap::TitlecaseMapperBorrowed::titlecase_segment, FnInStruct)] #[diplomat::rust_link( - icu::casemap::TitlecaseMapper::titlecase_segment_to_string, + icu::casemap::TitlecaseMapperBorrowed::titlecase_segment_to_string, FnInStruct, hidden )] @@ -316,6 +350,7 @@ pub mod ffi { ) { let _infallible = self .0 + .as_borrowed() .titlecase_segment(s, &locale.0.id, options.into()) .write_to(write); } diff --git a/tools/make/diplomat-coverage/src/allowlist.rs b/tools/make/diplomat-coverage/src/allowlist.rs index d3aa3a11d44..3836d7821a8 100644 --- a/tools/make/diplomat-coverage/src/allowlist.rs +++ b/tools/make/diplomat-coverage/src/allowlist.rs @@ -319,6 +319,7 @@ lazy_static::lazy_static! { "icu::calendar::any_calendar::AnyCalendarKind", "icu::datetime::options::Length", "icu::casemap::titlecase::TitlecaseMapper", + "icu::casemap::titlecase::TitlecaseMapperBorrowed", "icu::timezone::types::Time", "icu::timezone::types::DateTime", "icu::timezone::types::UtcOffset",