Closed zbraniecki closed 4 years ago
If so, is there a good best-practice on how to introduce such two versions of the same API without having to duplicate the code? My first idea would be to introduce sth like:
pub struct FluentBundleBase<R, I, F> {
pub(crate) resources: Vec<R>,
pub(crate) intls: I<IntlLangMemoizer>,
pub(crate) transform: Option<Box<F<dyn Fn(&str) -> Cow<str>>>>,
pub(crate) formatter:
Option<Box<F<dyn Fn(&FluentValue, &I<IntlLangMemoizer>) -> Option<String>>>>,
}
type FluentFn<F> = F;
type FluentBundle = FluentBundleBase<R, RefCell, FluentFn>;
mod concurrent {
type FluentFn<F> = F + Send + Sync;
type FluentBundle = FluentBundleBase<R, Mutex, FluentFn>;
}
Is that the path worth exploring or is there a better way?
fixed in 0.11!
We now have three elements of the
FluentBundle
that may or may not have to be concurrent:transform: Option<Box<dyn Fn(&str) -> Cow<str> + Send + Sync>>
formatter: Option<Box<dyn Fn(&FluentValue, &Mutex<IntlLangMemoizer>) -> Option<String> + Send + Sync>>
intls: Mutex<IntlLangMemoizer>
Until the last one showed up, the problem wasn't very noticeable because in most scenarios both
transform
andformatter
will stayNone
and when you do set it, you can just make yourFn
Send+Sync
.With the introduction of
IntlMemoizer
this becomes a real chore because now we have aMutex
in the heart of theFluentBundle
and a lock on every number formatting operation or plural rules selection.One way out of that is to follow what https://docs.rs/type-map/0.3.0/type_map/ did and introduce
fluent_bundle::concurrent::FluentBundle
which would be exactly the same as the regularFluentBundle
except that it would requireFn
s to beSend + Sync
and useMutex
for intls.The regular
FluentBundle
then would remove those requirements and useRefCell
forIntlLangMemoizer
.Then, customers like Gecko would use the regular
FluentBundle
while amethyst andhandlebars_fluent
would use the concurrent version.@emilio, @Manishearth - does it look like a sound solution to you?