tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

builtins.rs (10510B)


      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 crate::ffi;
      6 use fluent::types::{FluentNumberOptions, FluentType, FluentValue};
      7 use fluent::FluentArgs;
      8 use intl_memoizer::IntlLangMemoizer;
      9 use intl_memoizer::Memoizable;
     10 use nsstring::nsCString;
     11 use std::borrow::Cow;
     12 use std::ptr::NonNull;
     13 use unic_langid::LanguageIdentifier;
     14 
     15 pub struct NumberFormat {
     16    raw: Option<NonNull<ffi::RawNumberFormatter>>,
     17 }
     18 
     19 /**
     20 * According to http://userguide.icu-project.org/design, as long as we constrain
     21 * ourselves to const APIs ICU is const-correct.
     22 */
     23 unsafe impl Send for NumberFormat {}
     24 unsafe impl Sync for NumberFormat {}
     25 
     26 impl NumberFormat {
     27    pub fn new(locale: LanguageIdentifier, options: &FluentNumberOptions) -> Self {
     28        let loc: String = locale.to_string();
     29        Self {
     30            raw: unsafe {
     31                NonNull::new(ffi::FluentBuiltInNumberFormatterCreate(
     32                    &loc.into(),
     33                    &options.into(),
     34                ))
     35            },
     36        }
     37    }
     38 
     39    pub fn format(&self, input: f64) -> String {
     40        if let Some(raw) = self.raw {
     41            unsafe {
     42                let mut byte_count = 0;
     43                let mut capacity = 0;
     44                let buffer = ffi::FluentBuiltInNumberFormatterFormat(
     45                    raw.as_ptr(),
     46                    input,
     47                    &mut byte_count,
     48                    &mut capacity,
     49                );
     50                if buffer.is_null() {
     51                    return String::new();
     52                }
     53                String::from_raw_parts(buffer, byte_count, capacity)
     54            }
     55        } else {
     56            String::new()
     57        }
     58    }
     59 }
     60 
     61 impl Drop for NumberFormat {
     62    fn drop(&mut self) {
     63        if let Some(raw) = self.raw {
     64            unsafe { ffi::FluentBuiltInNumberFormatterDestroy(raw.as_ptr()) };
     65        }
     66    }
     67 }
     68 
     69 impl Memoizable for NumberFormat {
     70    type Args = (FluentNumberOptions,);
     71    type Error = &'static str;
     72    fn construct(lang: LanguageIdentifier, args: Self::Args) -> Result<Self, Self::Error> {
     73        Ok(NumberFormat::new(lang, &args.0))
     74    }
     75 }
     76 
     77 #[repr(C)]
     78 #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
     79 pub enum FluentDateTimeStyle {
     80    Full,
     81    Long,
     82    Medium,
     83    Short,
     84    None,
     85 }
     86 
     87 impl Default for FluentDateTimeStyle {
     88    fn default() -> Self {
     89        Self::None
     90    }
     91 }
     92 
     93 impl From<&str> for FluentDateTimeStyle {
     94    fn from(input: &str) -> Self {
     95        match input {
     96            "full" => Self::Full,
     97            "long" => Self::Long,
     98            "medium" => Self::Medium,
     99            "short" => Self::Short,
    100            _ => Self::None,
    101        }
    102    }
    103 }
    104 
    105 #[repr(C)]
    106 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
    107 pub enum FluentDateTimeHourCycle {
    108    H24,
    109    H23,
    110    H12,
    111    H11,
    112    None,
    113 }
    114 
    115 impl Default for FluentDateTimeHourCycle {
    116    fn default() -> Self {
    117        Self::None
    118    }
    119 }
    120 
    121 impl From<&str> for FluentDateTimeHourCycle {
    122    fn from(input: &str) -> Self {
    123        match input {
    124            "h24" => Self::H24,
    125            "h23" => Self::H23,
    126            "h12" => Self::H12,
    127            "h11" => Self::H11,
    128            _ => Self::None,
    129        }
    130    }
    131 }
    132 
    133 #[repr(C)]
    134 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
    135 pub enum FluentDateTimeTextComponent {
    136    Long,
    137    Short,
    138    Narrow,
    139    None,
    140 }
    141 
    142 impl Default for FluentDateTimeTextComponent {
    143    fn default() -> Self {
    144        Self::None
    145    }
    146 }
    147 
    148 impl From<&str> for FluentDateTimeTextComponent {
    149    fn from(input: &str) -> Self {
    150        match input {
    151            "long" => Self::Long,
    152            "short" => Self::Short,
    153            "narrow" => Self::Narrow,
    154            _ => Self::None,
    155        }
    156    }
    157 }
    158 
    159 #[repr(C)]
    160 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
    161 pub enum FluentDateTimeNumericComponent {
    162    Numeric,
    163    TwoDigit,
    164    None,
    165 }
    166 
    167 impl Default for FluentDateTimeNumericComponent {
    168    fn default() -> Self {
    169        Self::None
    170    }
    171 }
    172 
    173 impl From<&str> for FluentDateTimeNumericComponent {
    174    fn from(input: &str) -> Self {
    175        match input {
    176            "numeric" => Self::Numeric,
    177            "2-digit" => Self::TwoDigit,
    178            _ => Self::None,
    179        }
    180    }
    181 }
    182 
    183 #[repr(C)]
    184 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
    185 pub enum FluentDateTimeMonthComponent {
    186    Numeric,
    187    TwoDigit,
    188    Long,
    189    Short,
    190    Narrow,
    191    None,
    192 }
    193 
    194 impl Default for FluentDateTimeMonthComponent {
    195    fn default() -> Self {
    196        Self::None
    197    }
    198 }
    199 
    200 impl From<&str> for FluentDateTimeMonthComponent {
    201    fn from(input: &str) -> Self {
    202        match input {
    203            "numeric" => Self::Numeric,
    204            "2-digit" => Self::TwoDigit,
    205            "long" => Self::Long,
    206            "short" => Self::Short,
    207            "narrow" => Self::Narrow,
    208            _ => Self::None,
    209        }
    210    }
    211 }
    212 
    213 #[repr(C)]
    214 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
    215 pub enum FluentDateTimeTimeZoneNameComponent {
    216    Long,
    217    Short,
    218    None,
    219 }
    220 
    221 impl Default for FluentDateTimeTimeZoneNameComponent {
    222    fn default() -> Self {
    223        Self::None
    224    }
    225 }
    226 
    227 impl From<&str> for FluentDateTimeTimeZoneNameComponent {
    228    fn from(input: &str) -> Self {
    229        match input {
    230            "long" => Self::Long,
    231            "short" => Self::Short,
    232            _ => Self::None,
    233        }
    234    }
    235 }
    236 
    237 #[repr(C)]
    238 #[derive(Default, Debug, Clone, Hash, PartialEq, Eq)]
    239 pub struct FluentDateTimeOptions {
    240    pub date_style: FluentDateTimeStyle,
    241    pub time_style: FluentDateTimeStyle,
    242    pub hour_cycle: FluentDateTimeHourCycle,
    243    pub weekday: FluentDateTimeTextComponent,
    244    pub era: FluentDateTimeTextComponent,
    245    pub year: FluentDateTimeNumericComponent,
    246    pub month: FluentDateTimeMonthComponent,
    247    pub day: FluentDateTimeNumericComponent,
    248    pub hour: FluentDateTimeNumericComponent,
    249    pub minute: FluentDateTimeNumericComponent,
    250    pub second: FluentDateTimeNumericComponent,
    251    pub time_zone_name: FluentDateTimeTimeZoneNameComponent,
    252 }
    253 
    254 impl FluentDateTimeOptions {
    255    pub fn merge(&mut self, opts: &FluentArgs) {
    256        for (key, value) in opts.iter() {
    257            match (key, value) {
    258                ("dateStyle", FluentValue::String(n)) => {
    259                    self.date_style = n.as_ref().into();
    260                }
    261                ("timeStyle", FluentValue::String(n)) => {
    262                    self.time_style = n.as_ref().into();
    263                }
    264                ("hourCycle", FluentValue::String(n)) => {
    265                    self.hour_cycle = n.as_ref().into();
    266                }
    267                ("weekday", FluentValue::String(n)) => {
    268                    self.weekday = n.as_ref().into();
    269                }
    270                ("era", FluentValue::String(n)) => {
    271                    self.era = n.as_ref().into();
    272                }
    273                ("year", FluentValue::String(n)) => {
    274                    self.year = n.as_ref().into();
    275                }
    276                ("month", FluentValue::String(n)) => {
    277                    self.month = n.as_ref().into();
    278                }
    279                ("day", FluentValue::String(n)) => {
    280                    self.day = n.as_ref().into();
    281                }
    282                ("hour", FluentValue::String(n)) => {
    283                    self.hour = n.as_ref().into();
    284                }
    285                ("minute", FluentValue::String(n)) => {
    286                    self.minute = n.as_ref().into();
    287                }
    288                ("second", FluentValue::String(n)) => {
    289                    self.second = n.as_ref().into();
    290                }
    291                ("timeZoneName", FluentValue::String(n)) => {
    292                    self.time_zone_name = n.as_ref().into();
    293                }
    294                _ => {}
    295            }
    296        }
    297    }
    298 }
    299 
    300 #[derive(Debug, PartialEq, Clone)]
    301 pub struct FluentDateTime {
    302    epoch: f64,
    303    options: FluentDateTimeOptions,
    304 }
    305 
    306 impl FluentType for FluentDateTime {
    307    fn duplicate(&self) -> Box<dyn FluentType + Send> {
    308        Box::new(self.clone())
    309    }
    310    fn as_string(&self, intls: &IntlLangMemoizer) -> Cow<'static, str> {
    311        let result = intls
    312            .with_try_get::<DateTimeFormat, _, _>((self.options.clone(),), |dtf| {
    313                dtf.format(self.epoch)
    314            })
    315            .expect("Failed to retrieve a DateTimeFormat instance.");
    316        result.into()
    317    }
    318    fn as_string_threadsafe(
    319        &self,
    320        _: &intl_memoizer::concurrent::IntlLangMemoizer,
    321    ) -> Cow<'static, str> {
    322        unimplemented!()
    323    }
    324 }
    325 
    326 impl std::fmt::Display for FluentDateTime {
    327    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    328        write!(f, "DATETIME: {}", self.epoch)
    329    }
    330 }
    331 
    332 impl FluentDateTime {
    333    pub fn new(epoch: f64, options: FluentDateTimeOptions) -> Self {
    334        Self { epoch, options }
    335    }
    336 }
    337 
    338 pub struct DateTimeFormat {
    339    raw: Option<NonNull<ffi::RawDateTimeFormatter>>,
    340 }
    341 
    342 /**
    343 * According to http://userguide.icu-project.org/design, as long as we constrain
    344 * ourselves to const APIs ICU is const-correct.
    345 */
    346 unsafe impl Send for DateTimeFormat {}
    347 unsafe impl Sync for DateTimeFormat {}
    348 
    349 impl DateTimeFormat {
    350    pub fn new(locale: LanguageIdentifier, options: FluentDateTimeOptions) -> Self {
    351        // ICU needs null-termination here, otherwise we could use nsCStr.
    352        let loc: nsCString = locale.to_string().into();
    353        Self {
    354            raw: unsafe { NonNull::new(ffi::FluentBuiltInDateTimeFormatterCreate(&loc, options)) },
    355        }
    356    }
    357 
    358    pub fn format(&self, input: f64) -> String {
    359        if let Some(raw) = self.raw {
    360            unsafe {
    361                let mut byte_count = 0;
    362                let buffer =
    363                    ffi::FluentBuiltInDateTimeFormatterFormat(raw.as_ptr(), input, &mut byte_count);
    364                if buffer.is_null() {
    365                    return String::new();
    366                }
    367                String::from_raw_parts(buffer, byte_count as usize, byte_count as usize)
    368            }
    369        } else {
    370            String::new()
    371        }
    372    }
    373 }
    374 
    375 impl Drop for DateTimeFormat {
    376    fn drop(&mut self) {
    377        if let Some(raw) = self.raw {
    378            unsafe { ffi::FluentBuiltInDateTimeFormatterDestroy(raw.as_ptr()) };
    379        }
    380    }
    381 }
    382 
    383 impl Memoizable for DateTimeFormat {
    384    type Args = (FluentDateTimeOptions,);
    385    type Error = &'static str;
    386    fn construct(lang: LanguageIdentifier, args: Self::Args) -> Result<Self, Self::Error> {
    387        Ok(DateTimeFormat::new(lang, args.0))
    388    }
    389 }