Skip to content

Commit

Permalink
Add icu_preferences util
Browse files Browse the repository at this point in the history
  • Loading branch information
Zibi Braniecki committed Apr 29, 2022
1 parent 2397c6d commit 58797c5
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ members = [
"utils/fixed_decimal",
"utils/litemap",
"utils/pattern",
"utils/preferences",
"utils/tinystr",
"utils/uniset",
"utils/writeable",
Expand Down
21 changes: 21 additions & 0 deletions components/datetime/src/options/preferences.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
//! let prefs = preferences::Bag::from_hour_cycle(preferences::HourCycle::H23);
//! ```
use crate::fields;
use icu_locid::{unicode_ext_value, extensions::unicode};
use core::convert::TryFrom;

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -122,3 +124,22 @@ impl HourCycle {
}
}
}

const H11: unicode::Value = unicode_ext_value!("h11");
const H12: unicode::Value = unicode_ext_value!("h12");
const H23: unicode::Value = unicode_ext_value!("h23");
const H24: unicode::Value = unicode_ext_value!("h24");

impl TryFrom<&unicode::Value> for HourCycle {
type Error = ();

fn try_from(value: &unicode::Value) -> Result<Self, Self::Error> {
match value {
_ if value == &H11 => Ok(Self::H11),
_ if value == &H12 => Ok(Self::H12),
_ if value == &H23 => Ok(Self::H23),
_ if value == &H24 => Ok(Self::H24),
_ => Err(())
}
}
}
28 changes: 28 additions & 0 deletions utils/preferences/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# This file is part of ICU4X. For terms of use, please see the file
# called LICENSE at the top level of the ICU4X source tree
# (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).

[package]
name = "icu_preferences"
description = "API for resolving user preferences against unicode extensions"
version = "0.0.1"
authors = ["The ICU4X Project Developers"]
edition = "2021"
readme = "README.md"
repository = "https://github.com/unicode-org/icu4x"
license-file = "LICENSE"
categories = ["internationalization"]
# Keep this in sync with other crates unless there are exceptions
include = [
"src/**/*",
"examples/**/*",
"benches/**/*",
"tests/**/*",
"Cargo.toml",
"LICENSE",
"README.md"
]

[dependencies]
icu_locid = { version = "0.5", path = "../../components/locid" }
icu_datetime = { version = "0.5", path = "../../components/datetime" }
32 changes: 32 additions & 0 deletions utils/preferences/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#[macro_use]
mod macros;

#[cfg(test)]
mod tests {
use super::*;
use icu_datetime::options::preferences::HourCycle;
use icu_locid::{unicode_ext_key, Locale};

preferences!(
Preferences,
ResolvedPreferences,
{
hour_cycle => Option<HourCycle>, HourCycle, Some(unicode_ext_key!("hc"))
}
);

#[test]
fn it_works() {
let l: Locale = "en-US-u-hc-h23".parse().unwrap();

let prefs = Preferences { hour_cycle: None };

let defaults = ResolvedPreferences {
hour_cycle: HourCycle::H12,
};

let resolved_prefs = ResolvedPreferences::try_from((&prefs, &l, &defaults)).unwrap();

assert_eq!(resolved_prefs.hour_cycle, HourCycle::H23);
}
}
40 changes: 40 additions & 0 deletions utils/preferences/src/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#[macro_export]
macro_rules! preferences {
($name:ident, $resolved_name:ident, {$($key:ident => $pref:ty, $resolved:ty, $ue:expr),*}) => (
#[derive(Default)]
pub struct $name {
$(
$key: $pref,
)*
}

pub struct $resolved_name {
$(
$key: $resolved,
)*
}

impl TryFrom<(&$name, &Locale, &$resolved_name)> for $resolved_name {
type Error = ();

fn try_from(input: (&$name, &Locale, &$resolved_name)) -> Result<Self, Self::Error> {
let (prefs, locale, defaults) = input;
let keywords = &locale.extensions.unicode.keywords;

$(
let mut $key = prefs.$key;
if $key.is_none() {
$key = $ue.and_then(
|ue_key| keywords.get(&ue_key).map(TryInto::try_into)
).transpose()?;
}
)*
Ok($resolved_name {
$(
$key: $key.unwrap_or(defaults.$key),
)*
})
}
}
)
}
85 changes: 85 additions & 0 deletions utils/preferences/tests/dtf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
use icu_datetime::options::preferences::HourCycle;
use icu_locid::{unicode_ext_key, Locale};
use icu_preferences::preferences;

#[derive(Clone, Copy)]
enum Calendar {
Gregory,
}

impl TryFrom<&icu_locid::extensions::unicode::Value> for Calendar {
type Error = ();

fn try_from(_i: &icu_locid::extensions::unicode::Value) -> Result<Self, Self::Error> {
Ok(Calendar::Gregory)
}
}

preferences!(
DTFPreferences,
ResolvedDTFPreferences,
{
hour_cycle => Option<HourCycle>, HourCycle, Some(unicode_ext_key!("hc")),
calendar => Option<Calendar>, Calendar, Some(unicode_ext_key!("ca"))
}
);

struct DateTimeFormat {
prefs: ResolvedDTFPreferences,
}

impl DateTimeFormat {
pub fn new(locale: &Locale, prefs: &DTFPreferences) -> Self {
let en_us_defaults = ResolvedDTFPreferences {
hour_cycle: HourCycle::H12,
calendar: Calendar::Gregory,
};

let prefs = ResolvedDTFPreferences::try_from((prefs, locale, &en_us_defaults)).unwrap();

Self { prefs }
}

pub fn format(&self, _input: u64) -> String {
match self.prefs.hour_cycle {
HourCycle::H11 => "00:13 am",
HourCycle::H12 => "12:13 am",
HourCycle::H23 => "00:13",
HourCycle::H24 => "24:13",
}
.to_string()
}
}

#[test]
fn dtf_default() {
let loc: Locale = "en-US".parse().unwrap();
let prefs = DTFPreferences {
hour_cycle: None,
..Default::default()
};
let dtf = DateTimeFormat::new(&loc, &prefs);
assert_eq!(dtf.format(0), String::from("12:13 am"));
}

#[test]
fn dtf_uext() {
let loc: Locale = "en-US-u-hc-h11".parse().unwrap();
let prefs = DTFPreferences {
hour_cycle: None,
..Default::default()
};
let dtf = DateTimeFormat::new(&loc, &prefs);
assert_eq!(dtf.format(0), String::from("00:13 am"));
}

#[test]
fn dtf_prefs() {
let loc: Locale = "en-US-u-hc-h11".parse().unwrap();
let prefs = DTFPreferences {
hour_cycle: Some(HourCycle::H24),
..Default::default()
};
let dtf = DateTimeFormat::new(&loc, &prefs);
assert_eq!(dtf.format(0), String::from("24:13"));
}

0 comments on commit 58797c5

Please sign in to comment.