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

error[E0277]: (dyn Any + 'static) cannot be sent between threads safely #299

Open
lynn2910 opened this issue Dec 6, 2022 · 11 comments
Open
Labels
crate:fluent-bundle Issues related to fluent-bundle crate documentation enhancement

Comments

@lynn2910
Copy link

lynn2910 commented Dec 6, 2022

Hi, I know this error is an issue that has been closed, but I don't understand HOW to access the "new_concurrent" method.

When I use this code:

  {
    let ftl_string = include_str!("../assets/languages/fr.ftl");
    let res = FluentResource::try_new(ftl_string.to_string()).expect("Failed to parse an FTL string.");
    
    let lang = langid!("fr-FR");
    let mut bundle = FluentBundle::new(vec![lang.clone()]);

    bundle.add_resource(res).expect("Failed to add FTL resources to the bundle.");

    langs.insert(lang, bundle);
  }

It doesn't give any error (in that part, I use threads so this part broke my whole project).
But, when I try to use the FluentBundle::new_concurrent method instead of FluentBundle::new, it says that this function doesn't exist, and I can't find anything about it in the documentation.

How can we access to this method ?

@zbraniecki
Copy link
Collaborator

Ah, good call. It's not very ergonomic now, you need to do:

let bundle = bundle::FluentBundle<_, intl_memoizer::concurrent::IntlMemoizer>;

@lynn2910
Copy link
Author

lynn2910 commented Dec 7, 2022

Thank you, it works perfectly now !

@lynn2910
Copy link
Author

lynn2910 commented Dec 7, 2022

For those who were also wondering how to do it:

// an example of a basic fluent implementation with a HashMap to store languages (works with threads!)
// Don't forget to add the necessary dependencies to your Cargo.toml
use std::collections::HashMap;
use fluent::{ FluentResource, bundle::FluentBundle };
use unic_langid::{self, LanguageIdentifier, langid};
use intl_memoizer;

// Very important !!!!
type TranslationType = FluentBundle<FluentResource, intl_memoizer::concurrent::IntlLangMemoizer>;

fn load() -> HashMap<LanguageIdentifier, TranslationType> {
  let mut langs: HashMap<LanguageIdentifier, TranslationType> = HashMap::new();
  {
    let ftl_string = include_str!("../assets/languages/fr.ftl"); // you can use a &str or read a file instead of include_str !
    let res = FluentResource::try_new(ftl_string.to_string()).expect("Failed to parse an FTL string.");
    
    let lang = langid!("fr-FR");
    let mut bundle = FluentBundle::new_concurrent(vec![lang.clone()]);

    bundle.add_resource(res).expect("Failed to add FTL resources to the bundle.");

    langs.insert(lang, bundle);
  }
  langs
}

It would be nice if we could find a better documentation on how to do this 😀

@zbraniecki
Copy link
Collaborator

Would appreciate PR! Maybe even add type alias in bundle::concurrent::FluentBundle? :)

@ClementGre
Copy link

Is there a way to achieve this while using the fluent-fallback crate ?

When using this crate, a Bundles type is created using the Localization::with_env(...).bundles() function :

let bundles = Localization::with_env(
        vec!["back.ftl".into(), "common.ftl".into()],
        true,
        vec![langid!("fr-FR"), langid!("en-US")],
        ResourceManager::new("../translations/{locale}/{res_id}".to_string()),
    ).bundles();

Then, I get the trait `Send` is not implemented for `(dyn Any + 'static) when using bundle as a parameter T where T: Send + Sync + 'static.

@zbraniecki
Copy link
Collaborator

You would want to introduce a fluent_fallback::concurrent::Localization likely. We didn't get to write a PR for it yet.

@ClementGre
Copy link

Well, I understand why to use intl_memoizer::concurrent::IntlLangMemoizer for FluentBundle, but there is no such type parameter in Localization.

Then I don't know at all how could I introduce a fluent_fallback::concurrent::Localization.
(Moreover, it is not the Localization impl that has threading issues, but the Bundles impl produced by .bundles).

(Sorry, I'm pretty new to Rust)

@zbraniecki
Copy link
Collaborator

Then I don't know at all how could I introduce a fluent_fallback::concurrent::Localization.

You would need to create an equivalent of Localization in concurrent module that is parametrized on concurrent::FluentBundle.

You would need to write it all, there is no such solution yet.

@ClementGre
Copy link

Why would it be parameterized on FluentBundle ?
Localization does not uses FluentBundle at all and it generates a Bundles object that represents all of the loaded bundles, then it can fallback when a translation is missing.

@zbraniecki
Copy link
Collaborator

hmm, maybe you're right. I don't have the complete mental model in my mind now. Maybe you need to adjust ResourceManager? And that may require a Localization that works with concurrent ResourceManager that produces concurrent FluentBundle.

@ClementGre
Copy link

ClementGre commented Dec 22, 2022

I think the file bundles.rs should be edited cause it is the &Rc<Bundles<G>> returned by Localization::bundles(&self) that is not thread-safe (does not implement Send + Sync + 'static).

But I don't have the knowledge in Rust to do this so I'll wait for someone to fix the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
crate:fluent-bundle Issues related to fluent-bundle crate documentation enhancement
Projects
None yet
Development

No branches or pull requests

4 participants