Skip to content

Commit

Permalink
Add Borrowed variants to casemapper types (#6088)
Browse files Browse the repository at this point in the history
  • Loading branch information
Manishearth authored Feb 9, 2025
1 parent a051c5b commit 1822af2
Show file tree
Hide file tree
Showing 11 changed files with 415 additions and 222 deletions.
203 changes: 126 additions & 77 deletions components/casemap/src/casemapper.rs

Large diffs are not rendered by default.

149 changes: 106 additions & 43 deletions components/casemap/src/closer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@
// 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::*;

/// A wrapper around [`CaseMapper`] that can produce case mapping closures
/// 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
Expand Down Expand Up @@ -40,16 +43,29 @@ pub struct CaseMapCloser<CM> {
unfold: DataPayload<CaseMapUnfoldV1>,
}

#[cfg(feature = "compiled_data")]
impl Default for CaseMapCloser<CaseMapper> {
/// ✨ *Enabled with the `compiled_data` Cargo feature.*
fn default() -> Self {
Self::new()
impl CaseMapCloser<CaseMapper> {
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<P>(provider: &P) -> Result<Self, DataError>
where
P: DataProvider<CaseMapV1> + DataProvider<CaseMapUnfoldV1> + ?Sized,
{
let cm = CaseMapper::try_new_unstable(provider)?;
let unfold = provider.load(Default::default())?.payload;
Ok(Self { cm, unfold })
}
}

impl CaseMapCloser<CaseMapper> {
/// A constructor which creates a [`CaseMapCloser`] using compiled data.
/// A constructor which creates a [`CaseMapCloserBorrowed`] using compiled data.
///
/// # Examples
///
Expand Down Expand Up @@ -78,32 +94,9 @@ impl CaseMapCloser<CaseMapper> {
///
/// [📚 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<P>(provider: &P) -> Result<Self, DataError>
where
P: DataProvider<CaseMapV1> + DataProvider<CaseMapUnfoldV1> + ?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()
}
}

Expand Down Expand Up @@ -147,6 +140,80 @@ impl<CM: AsRef<CaseMapper>> CaseMapCloser<CM> {
})
}

/// 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<CaseMapper> {
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.
///
Expand All @@ -160,7 +227,7 @@ impl<CM: AsRef<CaseMapper>> CaseMapCloser<CM> {
/// - 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.
///
Expand All @@ -180,8 +247,8 @@ impl<CM: AsRef<CaseMapper>> CaseMapCloser<CM> {
/// assert!(set.contains('ſ'));
/// assert!(!set.contains('s')); // does not contain itself
/// ```
pub fn add_case_closure_to<S: ClosureSink>(&self, c: char, set: &mut S) {
self.cm.as_ref().add_case_closure_to(c, set);
pub fn add_case_closure_to<S: ClosureSink>(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
Expand Down Expand Up @@ -216,11 +283,7 @@ impl<CM: AsRef<CaseMapper>> CaseMapCloser<CM> {
/// assert!(set.contains('ß'));
/// assert!(set.contains('ẞ'));
/// ```
pub fn add_string_case_closure_to<S: ClosureSink>(&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<S: ClosureSink>(self, s: &str, set: &mut S) -> bool {
self.cm.data.add_string_case_closure_to(s, set, self.unfold)
}
}
6 changes: 3 additions & 3 deletions components/casemap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
8 changes: 4 additions & 4 deletions components/casemap/src/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand Down
Loading

0 comments on commit 1822af2

Please sign in to comment.