diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/intl-memoizer | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/intl-memoizer')
-rw-r--r-- | third_party/rust/intl-memoizer/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | third_party/rust/intl-memoizer/Cargo.toml | 35 | ||||
-rw-r--r-- | third_party/rust/intl-memoizer/README.md | 65 | ||||
-rw-r--r-- | third_party/rust/intl-memoizer/src/concurrent.rs | 39 | ||||
-rw-r--r-- | third_party/rust/intl-memoizer/src/lib.rs | 140 |
5 files changed, 280 insertions, 0 deletions
diff --git a/third_party/rust/intl-memoizer/.cargo-checksum.json b/third_party/rust/intl-memoizer/.cargo-checksum.json new file mode 100644 index 0000000000..4cc58e2eeb --- /dev/null +++ b/third_party/rust/intl-memoizer/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"844d2077a77d1b483fcb76035f5e5f0efa4d07f69f0b67a499fce1cb019b393b","README.md":"c7084646fb85a4a7031e31e917ba510a942f6ec9958b440c29754765e8f417b4","src/concurrent.rs":"d52dc59d705f1177b311a32032daef09637867c9cae80718fc5d06c5e0a8463e","src/lib.rs":"9cb0ed0f06699ead0416a70868021c32087c7fe085f64cc73dbac395f4b08fc5"},"package":"8a0ed58ba6089d49f8a9a7d5e16fc9b9e2019cdf40ef270f3d465fa244d9630b"}
\ No newline at end of file diff --git a/third_party/rust/intl-memoizer/Cargo.toml b/third_party/rust/intl-memoizer/Cargo.toml new file mode 100644 index 0000000000..707bec3ecd --- /dev/null +++ b/third_party/rust/intl-memoizer/Cargo.toml @@ -0,0 +1,35 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "intl-memoizer" +version = "0.5.0" +authors = ["Zibi Braniecki <gandalf@mozilla.com>", "Manish Goregaokar <manishsmail@gmail.com>"] +include = ["src/**/*", "benches/*.rs", "Cargo.toml", "README.md"] +description = "A memoizer specifically tailored for storing lazy-initialized\nintl formatters.\n" +homepage = "http://www.projectfluent.org" +readme = "README.md" +keywords = ["localization", "l10n", "i18n", "intl", "internationalization"] +categories = ["localization", "internationalization"] +license = "Apache-2.0/MIT" +repository = "https://github.com/projectfluent/fluent-rs" +[dependencies.type-map] +version = "0.3" + +[dependencies.unic-langid] +version = "0.9" +[dev-dependencies.fluent-langneg] +version = "0.13" + +[dev-dependencies.intl_pluralrules] +version = "7.0" diff --git a/third_party/rust/intl-memoizer/README.md b/third_party/rust/intl-memoizer/README.md new file mode 100644 index 0000000000..98e0092861 --- /dev/null +++ b/third_party/rust/intl-memoizer/README.md @@ -0,0 +1,65 @@ +# IntlMemoizer + +`intl-memoizer` is a crate designed to handle lazy-initialized references +to intl formatters. + +The assumption is that allocating a new formatter instance is costly, and such +instance is read-only during its life time, with constructor being expensive, and +`format`/`select` calls being cheap. + +In result it pays off to use a singleton to manage memoization of all instances of intl +APIs such as `PluralRules`, DateTimeFormat` etc. between all `FluentBundle` instances. + +Usage +----- + +```rust +use intl_memoizer::{IntlMemoizer, Memoizable}; +use unic_langid::langid; + +use intl_pluralrules::{PluralRules, PluralRuleType, PluralCategory}; + +impl Memoizable for PluralRules { + type Args = (PluralRulesType,); + fn construct(lang: LanguageIdentifier, args: Self::Args) -> Self { + Self::new(lang, args.0) + } +} + +fn main() { + let lang = langid!("en-US"); + + // A single memoizer for all languages + let mut memoizer = IntlMemoizer::new(); + + // A RefCell for a particular language to be used in all `FluentBundle` + // instances. + let mut en_us_memoizer = memoizer.get_for_lang(lang.clone()); + + // Per-call borrow + let mut en_us_memoizer_borrow = en_us_memoizer.borrow_mut(); + let cb = en_us_memoizer_borrow.get::<PluralRules>((PluralRulesType::Cardinal,)); + assert_eq!(cb.select(1), PluralCategory::One); +} + +``` + +Get Involved +------------ + +`fluent-rs` is open-source, licensed under the Apache License, Version 2.0. We +encourage everyone to take a look at our code and we'll listen to your +feedback. + + +Discuss +------- + +We'd love to hear your thoughts on Project Fluent! Whether you're a localizer +looking for a better way to express yourself in your language, or a developer +trying to make your app localizable and multilingual, or a hacker looking for +a project to contribute to, please do get in touch on the mailing list and the +IRC channel. + + - Discourse: https://discourse.mozilla.org/c/fluent + - IRC channel: [irc://irc.mozilla.org/l20n](irc://irc.mozilla.org/l20n) diff --git a/third_party/rust/intl-memoizer/src/concurrent.rs b/third_party/rust/intl-memoizer/src/concurrent.rs new file mode 100644 index 0000000000..95553281b6 --- /dev/null +++ b/third_party/rust/intl-memoizer/src/concurrent.rs @@ -0,0 +1,39 @@ +use super::*; +use std::sync::Mutex; + +#[derive(Debug)] +pub struct IntlLangMemoizer { + lang: LanguageIdentifier, + map: Mutex<type_map::concurrent::TypeMap>, +} + +impl IntlLangMemoizer { + pub fn new(lang: LanguageIdentifier) -> Self { + Self { + lang, + map: Mutex::new(type_map::concurrent::TypeMap::new()), + } + } + + pub fn with_try_get<I, R, U>(&self, args: I::Args, cb: U) -> Result<R, I::Error> + where + Self: Sized, + I: Memoizable + Sync + Send + 'static, + I::Args: Send + Sync + 'static, + U: FnOnce(&I) -> R, + { + let mut map = self.map.lock().unwrap(); + let cache = map + .entry::<HashMap<I::Args, I>>() + .or_insert_with(HashMap::new); + + let e = match cache.entry(args.clone()) { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => { + let val = I::construct(self.lang.clone(), args)?; + entry.insert(val) + } + }; + Ok(cb(&e)) + } +} diff --git a/third_party/rust/intl-memoizer/src/lib.rs b/third_party/rust/intl-memoizer/src/lib.rs new file mode 100644 index 0000000000..8205616a87 --- /dev/null +++ b/third_party/rust/intl-memoizer/src/lib.rs @@ -0,0 +1,140 @@ +use std::cell::RefCell; +use std::collections::hash_map::Entry; +use std::collections::HashMap; +use std::hash::Hash; +use std::rc::{Rc, Weak}; +use unic_langid::LanguageIdentifier; + +pub mod concurrent; + +pub trait Memoizable { + type Args: 'static + Eq + Hash + Clone; + type Error; + fn construct(lang: LanguageIdentifier, args: Self::Args) -> Result<Self, Self::Error> + where + Self: std::marker::Sized; +} + +#[derive(Debug)] +pub struct IntlLangMemoizer { + lang: LanguageIdentifier, + map: RefCell<type_map::TypeMap>, +} + +impl IntlLangMemoizer { + pub fn new(lang: LanguageIdentifier) -> Self { + Self { + lang, + map: RefCell::new(type_map::TypeMap::new()), + } + } + + pub fn with_try_get<I, R, U>(&self, args: I::Args, cb: U) -> Result<R, I::Error> + where + Self: Sized, + I: Memoizable + 'static, + U: FnOnce(&I) -> R, + { + let mut map = self + .map + .try_borrow_mut() + .expect("Cannot use memoizer reentrantly"); + let cache = map + .entry::<HashMap<I::Args, I>>() + .or_insert_with(HashMap::new); + + let e = match cache.entry(args.clone()) { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => { + let val = I::construct(self.lang.clone(), args)?; + entry.insert(val) + } + }; + Ok(cb(&e)) + } +} + +#[derive(Default)] +pub struct IntlMemoizer { + map: HashMap<LanguageIdentifier, Weak<IntlLangMemoizer>>, +} + +impl IntlMemoizer { + pub fn get_for_lang(&mut self, lang: LanguageIdentifier) -> Rc<IntlLangMemoizer> { + match self.map.entry(lang.clone()) { + Entry::Vacant(empty) => { + let entry = Rc::new(IntlLangMemoizer::new(lang)); + empty.insert(Rc::downgrade(&entry)); + entry + } + Entry::Occupied(mut entry) => { + if let Some(entry) = entry.get().upgrade() { + entry + } else { + let e = Rc::new(IntlLangMemoizer::new(lang)); + entry.insert(Rc::downgrade(&e)); + e + } + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use fluent_langneg::{negotiate_languages, NegotiationStrategy}; + use intl_pluralrules::{PluralCategory, PluralRuleType, PluralRules as IntlPluralRules}; + + struct PluralRules(pub IntlPluralRules); + + impl PluralRules { + pub fn new( + lang: LanguageIdentifier, + pr_type: PluralRuleType, + ) -> Result<Self, &'static str> { + let default_lang: LanguageIdentifier = "en".parse().unwrap(); + let pr_lang = negotiate_languages( + &[lang], + &IntlPluralRules::get_locales(pr_type), + Some(&default_lang), + NegotiationStrategy::Lookup, + )[0] + .clone(); + + Ok(Self(IntlPluralRules::create(pr_lang, pr_type)?)) + } + } + + impl Memoizable for PluralRules { + type Args = (PluralRuleType,); + type Error = &'static str; + fn construct(lang: LanguageIdentifier, args: Self::Args) -> Result<Self, Self::Error> { + Self::new(lang, args.0) + } + } + + #[test] + fn it_works() { + let lang: LanguageIdentifier = "en".parse().unwrap(); + + let mut memoizer = IntlMemoizer::default(); + { + let en_memoizer = memoizer.get_for_lang(lang.clone()); + + let result = en_memoizer + .with_try_get::<PluralRules, _, _>((PluralRuleType::CARDINAL,), |cb| cb.0.select(5)) + .unwrap(); + assert_eq!(result, Ok(PluralCategory::OTHER)); + } + + { + let en_memoizer = memoizer.get_for_lang(lang.clone()); + + let result = en_memoizer + .with_try_get::<PluralRules, _, _>((PluralRuleType::CARDINAL,), |cb| cb.0.select(5)) + .unwrap(); + assert_eq!(result, Ok(PluralCategory::OTHER)); + } + } +} |