1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use fluent_langneg::negotiate::NegotiationStrategy as LangNegNegotiationStrategy;
6 use fluent_langneg::negotiate_languages;
7 use nsstring::nsACString;
8 use nsstring::nsCString;
9 use thin_vec::ThinVec;
10 use unic_langid::{LanguageIdentifier, LanguageIdentifierError};
11 use unic_langid_ffi::new_langid_for_mozilla;
12 
13 /// We want to return the exact strings that were passed to us out of the
14 /// available and default pool. Since for the negotiation we canonicalize them
15 /// in `LanguageIdentifier`, this struct will preserve the original, non-canonicalized
16 /// string, and then use it to populate return array.
17 #[derive(Debug, PartialEq)]
18 struct LangIdString<'l> {
19     pub source: &'l nsCString,
20     pub langid: LanguageIdentifier,
21 }
22 
23 impl<'l> LangIdString<'l> {
try_new(s: &'l nsCString) -> Result<Self, LanguageIdentifierError>24     pub fn try_new(s: &'l nsCString) -> Result<Self, LanguageIdentifierError> {
25         new_langid_for_mozilla(s).map(|l| LangIdString {
26             source: s,
27             langid: l,
28         })
29     }
30 }
31 
32 impl<'l> AsRef<LanguageIdentifier> for LangIdString<'l> {
as_ref(&self) -> &LanguageIdentifier33     fn as_ref(&self) -> &LanguageIdentifier {
34         &self.langid
35     }
36 }
37 
38 #[repr(C)]
39 pub enum NegotiationStrategy {
40     Filtering,
41     Matching,
42     Lookup,
43 }
44 
get_strategy(input: NegotiationStrategy) -> LangNegNegotiationStrategy45 fn get_strategy(input: NegotiationStrategy) -> LangNegNegotiationStrategy {
46     match input {
47         NegotiationStrategy::Filtering => LangNegNegotiationStrategy::Filtering,
48         NegotiationStrategy::Matching => LangNegNegotiationStrategy::Matching,
49         NegotiationStrategy::Lookup => LangNegNegotiationStrategy::Lookup,
50     }
51 }
52 
53 #[no_mangle]
fluent_langneg_negotiate_languages( requested: &ThinVec<nsCString>, available: &ThinVec<nsCString>, default: &nsACString, strategy: NegotiationStrategy, result: &mut ThinVec<nsCString>, )54 pub extern "C" fn fluent_langneg_negotiate_languages(
55     requested: &ThinVec<nsCString>,
56     available: &ThinVec<nsCString>,
57     default: &nsACString,
58     strategy: NegotiationStrategy,
59     result: &mut ThinVec<nsCString>,
60 ) {
61     let requested = requested
62         .iter()
63         .filter_map(|s| new_langid_for_mozilla(s).ok())
64         .collect::<Vec<_>>();
65 
66     let available = available
67         .iter()
68         .filter_map(|s| LangIdString::try_new(s).ok())
69         .collect::<Vec<_>>();
70 
71     let d: nsCString = default.into();
72     let default = LangIdString::try_new(&d).ok();
73 
74     let strategy = get_strategy(strategy);
75 
76     for l in negotiate_languages(&requested, &available, default.as_ref(), strategy) {
77         result.push(l.source.clone());
78     }
79 }
80