1use std::fmt;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum QualifierKey {
9 Language,
10 Region,
11 Density,
13 Orientation,
14 Device,
15 Script,
16 ColorMode,
18 Mcc,
19 Mnc,
20 InputDevice,
21 Other(u32),
23}
24
25impl QualifierKey {
26 fn from_code(code: u32) -> QualifierKey {
27 match code {
28 0 => QualifierKey::Language,
29 1 => QualifierKey::Region,
30 2 => QualifierKey::Density,
31 3 => QualifierKey::Orientation,
32 4 => QualifierKey::Device,
33 5 => QualifierKey::Script,
34 6 => QualifierKey::ColorMode,
35 7 => QualifierKey::Mcc,
36 8 => QualifierKey::Mnc,
37 10 => QualifierKey::InputDevice,
38 other => QualifierKey::Other(other),
39 }
40 }
41}
42
43impl fmt::Display for QualifierKey {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 f.write_str(match self {
47 QualifierKey::Language => "language",
48 QualifierKey::Region => "region",
49 QualifierKey::Density => "density",
50 QualifierKey::Orientation => "orientation",
51 QualifierKey::Device => "device",
52 QualifierKey::Script => "script",
53 QualifierKey::ColorMode => "colorMode",
54 QualifierKey::Mcc => "mcc",
55 QualifierKey::Mnc => "mnc",
56 QualifierKey::InputDevice => "inputDevice",
57 QualifierKey::Other(code) => return write!(f, "key{code}"),
58 })
59 }
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
64pub struct Qualifier {
65 pub key: QualifierKey,
66 pub value: u32,
69}
70
71impl Qualifier {
72 pub(super) fn from_raw(key: u32, value: u32) -> Qualifier {
73 Qualifier { key: QualifierKey::from_code(key), value }
74 }
75
76 fn letters(self) -> String {
79 self.value.to_be_bytes().into_iter().filter(|&b| b != 0).map(|b| if b.is_ascii_graphic() { char::from(b) } else { '?' }).collect()
80 }
81
82 fn enumerator(self, names: &[(u32, &'static str)]) -> Option<&'static str> {
83 names.iter().find(|(value, _)| *value == self.value).map(|(_, name)| *name)
84 }
85}
86
87const DENSITIES: &[(u32, &str)] = &[(120, "sdpi"), (160, "mdpi"), (240, "ldpi"), (320, "xldpi"), (480, "xxldpi"), (640, "xxxldpi")];
88const ORIENTATIONS: &[(u32, &str)] = &[(0, "vertical"), (1, "horizontal")];
89const DEVICES: &[(u32, &str)] = &[(0, "phone"), (1, "tablet"), (2, "car"), (3, "pad"), (4, "tv"), (6, "wearable"), (7, "2in1")];
90const COLOR_MODES: &[(u32, &str)] = &[(0, "dark"), (1, "light")];
91const INPUT_DEVICES: &[(u32, &str)] = &[(0, "pointingdevice")];
92
93impl fmt::Display for Qualifier {
97 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 let named = match self.key {
99 QualifierKey::Language | QualifierKey::Script | QualifierKey::Region => return f.write_str(&self.letters()),
100 QualifierKey::Mcc => return write!(f, "mcc{}", self.value),
101 QualifierKey::Mnc => return write!(f, "mnc{}", self.value),
102 QualifierKey::Density => self.enumerator(DENSITIES),
103 QualifierKey::Orientation => self.enumerator(ORIENTATIONS),
104 QualifierKey::Device => self.enumerator(DEVICES),
105 QualifierKey::ColorMode => self.enumerator(COLOR_MODES),
106 QualifierKey::InputDevice => self.enumerator(INPUT_DEVICES),
107 QualifierKey::Other(_) => None,
108 };
109 match named {
110 Some(name) => f.write_str(name),
111 None => write!(f, "{}={}", self.key, self.value),
112 }
113 }
114}
115
116#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
119pub struct Qualifiers {
120 params: Vec<Qualifier>,
121}
122
123impl Qualifiers {
124 pub(super) fn new(params: Vec<Qualifier>) -> Qualifiers {
125 Qualifiers { params }
126 }
127
128 pub fn params(&self) -> &[Qualifier] {
130 &self.params
131 }
132
133 pub fn is_base(&self) -> bool {
135 self.params.is_empty()
136 }
137
138 pub fn get(&self, key: QualifierKey) -> Option<u32> {
140 self.params.iter().find(|p| p.key == key).map(|p| p.value)
141 }
142}
143
144impl fmt::Display for Qualifiers {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 if self.params.is_empty() {
150 return f.write_str("base");
151 }
152 for (i, param) in self.params.iter().enumerate() {
153 let attaches = matches!(param.key, QualifierKey::Script | QualifierKey::Region | QualifierKey::Mnc);
154 if i > 0 {
155 f.write_str(if attaches { "_" } else { "-" })?;
156 }
157 write!(f, "{param}")?;
158 }
159 Ok(())
160 }
161}