Skip to content

Commit b43b053

Browse files
committed
Introduce icu_preferences
1 parent 31e085a commit b43b053

35 files changed

+1493
-8
lines changed

Cargo.lock

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ members = [
6565
"utils/ixdtf",
6666
"utils/litemap",
6767
"utils/pattern",
68+
"utils/preferences",
6869
"utils/resb",
6970
"utils/tinystr",
7071
"utils/tzif",

components/locid/src/extensions/other/mod.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,12 @@
1919
//! let mut loc: Locale = "en-US-a-foo-faa".parse().expect("Parsing failed.");
2020
//! ```
2121
22-
mod subtag;
23-
2422
use crate::parser::ParserError;
2523
use crate::parser::SubtagIterator;
2624
use crate::shortvec::ShortBoxSlice;
27-
use alloc::vec::Vec;
2825
#[doc(inline)]
29-
pub use subtag::{subtag, Subtag};
26+
pub use crate::subtags::{subtag, Subtag};
27+
use alloc::vec::Vec;
3028

3129
/// A list of [`Other Use Extensions`] as defined in [`Unicode Locale
3230
/// Identifier`] specification.

components/locid/src/extensions/unicode/keywords.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,11 @@ impl Keywords {
358358
}
359359
}
360360

361+
/// Produce an ordered iterator over key-value pairs
362+
pub fn iter(&self) -> impl Iterator<Item = (&Key, &Value)> {
363+
self.0.iter()
364+
}
365+
361366
pub(crate) fn for_each_subtag_str<E, F>(&self, f: &mut F) -> Result<(), E>
362367
where
363368
F: FnMut(&str) -> Result<(), E>,

components/locid/src/extensions/unicode/value.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use crate::parser::{ParserError, SubtagIterator};
66
use crate::shortvec::ShortBoxSlice;
7+
use crate::subtags::Subtag;
78
use core::ops::RangeInclusive;
89
use core::str::FromStr;
910
use tinystr::TinyAsciiStr;
@@ -32,7 +33,7 @@ use tinystr::TinyAsciiStr;
3233
/// assert_eq!(value!("true").to_string(), "");
3334
/// ```
3435
#[derive(Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord, Default)]
35-
pub struct Value(ShortBoxSlice<TinyAsciiStr<{ *VALUE_LENGTH.end() }>>);
36+
pub struct Value(pub ShortBoxSlice<TinyAsciiStr<{ *VALUE_LENGTH.end() }>>);
3637

3738
const VALUE_LENGTH: RangeInclusive<usize> = 3..=8;
3839
const TRUE_VALUE: TinyAsciiStr<8> = tinystr::tinystr!(8, "true");
@@ -90,6 +91,41 @@ impl Value {
9091
self.0.single()
9192
}
9293

94+
pub fn first_subtag_matches(&self, input: &str) -> bool {
95+
if let Some(s) = self.0.get(0) {
96+
s == input
97+
} else {
98+
false
99+
}
100+
}
101+
102+
pub fn second_subtag_matches(&self, input: &str) -> bool {
103+
if let Some(s) = self.0.get(1) {
104+
s == input
105+
} else {
106+
false
107+
}
108+
}
109+
110+
pub fn second_subtag_is_empty(&self) -> bool {
111+
self.0.get(1).is_none()
112+
}
113+
114+
pub fn second_subtag(&self) -> Self {
115+
Self::from_tinystr(self.0.get(1).copied())
116+
}
117+
118+
pub fn unshift_subtag(&mut self) -> Option<Subtag> {
119+
let mut subtags = self.0.clone().to_vec();
120+
if subtags.is_empty() {
121+
None
122+
} else {
123+
let first = subtags.remove(0);
124+
self.0 = subtags.into();
125+
Some(Subtag(first))
126+
}
127+
}
128+
93129
#[doc(hidden)]
94130
pub const fn from_tinystr(subtag: Option<TinyAsciiStr<8>>) -> Self {
95131
match subtag {
@@ -191,6 +227,15 @@ macro_rules! extensions_unicode_value {
191227
);
192228
R
193229
}};
230+
($value:literal, $value2:literal) => {{
231+
let v: &str = concat!($value, "-", $value2);
232+
let R: $crate::extensions::unicode::Value =
233+
match $crate::extensions::unicode::Value::try_from_bytes(v.as_bytes()) {
234+
Ok(r) => r,
235+
_ => panic!(concat!("Invalid Unicode extension value: ", $value)),
236+
};
237+
R
238+
}};
194239
}
195240
#[doc(inline)]
196241
pub use extensions_unicode_value as value;

components/locid/src/helpers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ macro_rules! impl_tinystr_subtag {
2222
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
2323
#[repr(transparent)]
2424
$(#[$doc])*
25-
pub struct $name(tinystr::TinyAsciiStr<$len_end>);
25+
pub struct $name(pub tinystr::TinyAsciiStr<$len_end>);
2626

2727
impl $name {
2828
/// A constructor which takes a UTF-8 slice, parses it and

components/locid/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ mod locale;
7272
mod macros;
7373
mod ordering;
7474
mod parser;
75-
mod shortvec;
75+
pub mod shortvec;
7676

7777
pub use langid::LanguageIdentifier;
7878
pub use locale::Locale;

components/locid/src/shortvec/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ impl<T> Default for ShortBoxSliceInner<T> {
6666
///
6767
/// Supports mutation but always reallocs when mutated.
6868
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
69-
pub(crate) struct ShortBoxSlice<T>(ShortBoxSliceInner<T>);
69+
pub struct ShortBoxSlice<T>(ShortBoxSliceInner<T>);
7070

7171
impl<T> Default for ShortBoxSlice<T> {
7272
fn default() -> Self {

components/locid/src/subtags/mod.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,38 @@ pub use script::{script, Script};
6060
#[doc(inline)]
6161
pub use variant::{variant, Variant};
6262
pub use variants::Variants;
63+
64+
impl_tinystr_subtag!(
65+
/// A single item used in a list of [`Private`](super::Private) extensions.
66+
///
67+
/// The subtag has to be an ASCII alphanumerical string no shorter than
68+
/// one character and no longer than eight.
69+
///
70+
/// # Examples
71+
///
72+
/// ```
73+
/// use icu::locid::extensions::private::Subtag;
74+
///
75+
/// let subtag1: Subtag = "Foo".parse().expect("Failed to parse a Subtag.");
76+
///
77+
/// assert_eq!(subtag1.as_str(), "foo");
78+
/// ```
79+
Subtag,
80+
subtags,
81+
subtag,
82+
subtags_subtag,
83+
1..=8,
84+
s,
85+
s.is_ascii_alphanumeric(),
86+
s.to_ascii_lowercase(),
87+
s.is_ascii_alphanumeric() && s.is_ascii_lowercase(),
88+
InvalidExtension,
89+
["foo12"],
90+
["toolooong"],
91+
);
92+
93+
impl Subtag {
94+
pub(crate) const fn valid_key(v: &[u8]) -> bool {
95+
2 <= v.len() && v.len() <= 8
96+
}
97+
}

utils/preferences/Cargo.toml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# This file is part of ICU4X. For terms of use, please see the file
2+
# called LICENSE at the top level of the ICU4X source tree
3+
# (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4+
5+
[package]
6+
name = "icu_preferences"
7+
description = "API for resolving preferences"
8+
version = "0.0.1"
9+
categories = ["internationalization"]
10+
license-file = "LICENSE"
11+
12+
authors.workspace = true
13+
edition.workspace = true
14+
include.workspace = true
15+
repository.workspace = true
16+
rust-version.workspace = true
17+
18+
[package.metadata.workspaces]
19+
independent = true
20+
21+
[package.metadata.docs.rs]
22+
all-features = true
23+
24+
[dependencies]
25+
icu_locid = { workspace = true }
26+
tinystr = { workspace = true }
27+
28+
[dev-dependencies]
29+
icu_datetime = { workspace = true }

utils/preferences/LICENSE

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
UNICODE LICENSE V3
2+
3+
COPYRIGHT AND PERMISSION NOTICE
4+
5+
Copyright © 2020-2023 Unicode, Inc.
6+
7+
NOTICE TO USER: Carefully read the following legal agreement. BY
8+
DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR
9+
SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
10+
TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT
11+
DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
12+
13+
Permission is hereby granted, free of charge, to any person obtaining a
14+
copy of data files and any associated documentation (the "Data Files") or
15+
software and any associated documentation (the "Software") to deal in the
16+
Data Files or Software without restriction, including without limitation
17+
the rights to use, copy, modify, merge, publish, distribute, and/or sell
18+
copies of the Data Files or Software, and to permit persons to whom the
19+
Data Files or Software are furnished to do so, provided that either (a)
20+
this copyright and permission notice appear with all copies of the Data
21+
Files or Software, or (b) this copyright and permission notice appear in
22+
associated Documentation.
23+
24+
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
25+
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
27+
THIRD PARTY RIGHTS.
28+
29+
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE
30+
BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
31+
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
32+
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
33+
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA
34+
FILES OR SOFTWARE.
35+
36+
Except as contained in this notice, the name of a copyright holder shall
37+
not be used in advertising or otherwise to promote the sale, use or other
38+
dealings in these Data Files or Software without prior written
39+
authorization of the copyright holder.
40+
41+
42+
43+
Portions of ICU4X may have been adapted from ICU4C and/or ICU4J.
44+
ICU 1.8.1 to ICU 57.1 © 1995-2016 International Business Machines Corporation and others.

utils/preferences/README.md

Lines changed: 59 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod unicode;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// This file is part of ICU4X. For terms of use, please see the file
2+
// called LICENSE at the top level of the ICU4X source tree
3+
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4+
5+
#[non_exhaustive]
6+
#[derive(Debug)]
7+
pub enum Error {
8+
UnknownKeyword,
9+
InvalidKeywordValue,
10+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// This file is part of ICU4X. For terms of use, please see the file
2+
// called LICENSE at the top level of the ICU4X source tree
3+
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4+
5+
#![allow(non_snake_case)]
6+
7+
use crate::enum_keyword;
8+
9+
// https://github.com/unicode-org/cldr/blob/main/common/bcp47/calendar.xml
10+
enum_keyword!(IslamicCalendar {
11+
"umalqura" => Umalqura,
12+
"tbla" => Tbla,
13+
"civil" => Civil,
14+
"rgsa" => Rgsa
15+
});
16+
17+
enum_keyword!(Calendar {
18+
"buddhist" => Buddhist,
19+
"chinese" => Chinese,
20+
"coptic" => Coptic,
21+
"dangi" => Dangi,
22+
"ethioaa" => Ethioaa,
23+
"ethiopic" => Ethiopic,
24+
"gregory" => Gregory,
25+
"hebrew" => Hebrew,
26+
"indian" => Indian,
27+
"islamic" => Islamic(IslamicCalendar) {
28+
"umalqura" => Umalqura,
29+
"civil" => Civil
30+
},
31+
"iso8601" => Iso8601,
32+
"japanese" => Japanese,
33+
"persian" => Persian,
34+
"roc" => Roc
35+
}, "ca");
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// This file is part of ICU4X. For terms of use, please see the file
2+
// called LICENSE at the top level of the ICU4X source tree
3+
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4+
5+
crate::enum_keyword!(Collation {
6+
"standard" => Standard,
7+
"search" => Search,
8+
"phonetic" => Phonetic,
9+
"pinyin" => Pinyin,
10+
"searchjl" => Searchjl
11+
}, "co");

0 commit comments

Comments
 (0)