Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix transliterator fallback loading #5468

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

sffc
Copy link
Member

@sffc sffc commented Aug 30, 2024

I don't know exactly what the code was doing, but pulling it out into pieces instead of chaining function calls makes it easier to reason about and debug.

@sffc sffc requested a review from a team as a code owner August 30, 2024 22:01
@sffc sffc requested review from robertbastian and skius and removed request for a team August 30, 2024 22:02
Copy link
Member

@robertbastian robertbastian left a comment

Choose a reason for hiding this comment

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

What exactly is the "fix" part of this PR? Can you provide a test case that it fixes?

Comment on lines -309 to -323
let internal_t = dep
// a) hardcoded specials
.strip_prefix("x-")
.map(|special| Transliterator::load_special(special, normalizer_provider))
// b) the user-provided override
.or_else(|| Transliterator::load_with_override(&dep, lookup?).transpose())
// c) the data
.unwrap_or_else(|| {
let mut internal_t = None;
// a) hardcoded specials
if let Some(special) = dep.strip_prefix("x-") {
internal_t = Transliterator::load_special(special, normalizer_provider)?;
}
// b) the user-provided override
if let Some(lookup) = lookup {
if internal_t.is_none() {
if let Ok(locale) = dep.parse() {
internal_t = Transliterator::load_with_override(&locale, lookup)?;
}
}
}
// c) the data
let internal_t = match internal_t {
Some(t) => t,
None => {
let rbt = Transliterator::load_rbt(
#[allow(clippy::unwrap_used)] // infallible
DataMarkerAttributes::try_from_str(&dep.to_ascii_lowercase()).unwrap(),
transliterator_provider,
)?;
Ok(InternalTransliterator::RuleBased(rbt))
})?;
Copy link
Member

Choose a reason for hiding this comment

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

I find this much more readable than the mutable Option you're using.

Copy link
Member Author

Choose a reason for hiding this comment

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

Problems I had with the previous code:

  1. It was concealing the bug
  2. The functions involved return a mix of Option and Result and it is hard to keep track of which level you are at in unwrapping the values
  3. It's difficult to run the debugger with all the closures. You have to dip in and out of the Rust standard library with all the closures.

But I can convert this back to using the option chain if you prefer, as the code owner.

Copy link
Member

Choose a reason for hiding this comment

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

The bug is fixed by having load_special return Option<Result<...>>. Here you only need to change the map to an and_then.

@@ -341,7 +351,7 @@ impl Transliterator {
fn load_special<P>(
special: &str,
normalizer_provider: &P,
) -> Result<InternalTransliterator, DataError>
) -> Result<Option<InternalTransliterator>, DataError>
Copy link
Member

Choose a reason for hiding this comment

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

I think this should be Option<Result<InternalTransliterator, DataError>>. The option signals that a special transliterator is implemented, and then the result is the result from instantiating that transliterator, i.e. the _ case should just be None.

Copy link
Member Author

Choose a reason for hiding this comment

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

Either way is fine except that Result<Option> means that I can use the ? operator.

Copy link
Member

Choose a reason for hiding this comment

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

You don't need the ? opearator:

"any-nfkc" => Some(ComposingTransliterator::try_nfkc(normalizer_provider).map(InternalTransliterator::Composing)),

@sffc
Copy link
Member Author

sffc commented Sep 3, 2024

What exactly is the "fix" part of this PR?

The "fix" is that load_special was, I think, always returning an Err for any transliterator ID it didn't understand and was not letting the other two functions have a chance at resolving it (load_with_override and load_rbt).

@sffc
Copy link
Member Author

sffc commented Sep 3, 2024

Can you provide a test case that it fixes?

The test that is fixed with this PR is in #5469. Which course of action do you prefer:

  1. Leave it as-is. It is okay to merge this change separate from the demo exercising it.
  2. Close this PR and consider landing this fix to be coupled with landing the demo.
  3. Make a new test case and add it to this PR.

@sffc
Copy link
Member Author

sffc commented Sep 3, 2024

Well, I thought the test I added in #5483 was going to fail on main, but it seems to pass. And I can't reproduce the test failure in #5469 that I was getting last week. 🤷

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants