summaryrefslogtreecommitdiffstats
path: root/third_party/rust/intl-memoizer
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/intl-memoizer
parentInitial commit. (diff)
downloadfirefox-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.json1
-rw-r--r--third_party/rust/intl-memoizer/Cargo.toml35
-rw-r--r--third_party/rust/intl-memoizer/README.md65
-rw-r--r--third_party/rust/intl-memoizer/src/concurrent.rs39
-rw-r--r--third_party/rust/intl-memoizer/src/lib.rs140
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));
+ }
+ }
+}