icu_experimental/dimension/provider/
pattern_key.rs1#![allow(clippy::exhaustive_structs, clippy::exhaustive_enums)]
7
8use zerovec::{
9 maps::ZeroMapKV,
10 ule::{AsULE, UleError, ULE},
11};
12
13use crate::dimension::provider::units_essentials::CompoundCount;
14
15#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)]
16#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
17#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
18#[cfg_attr(feature = "datagen", databake(path = icu_experimental::dimension::provider::pattern_key))]
19#[repr(u8)]
20pub enum PowerValue {
21 Two,
22 Three,
23}
24
25#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)]
26#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
27#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
28#[cfg_attr(feature = "datagen", databake(path = icu_experimental::dimension::provider::pattern_key))]
29pub enum PatternKey {
30 Binary(u8),
31 Decimal(i8),
32 Power {
33 power: PowerValue,
34 count: CompoundCount,
35 },
36}
37
38#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)]
65pub struct PatternKeyULE(u8);
66
67unsafe impl ULE for PatternKeyULE {
77 fn validate_bytes(bytes: &[u8]) -> Result<(), zerovec::ule::UleError> {
78 for &byte in bytes.iter() {
79 if (byte & 0b1100_0000) == 0b1100_0000 {
81 return Err(UleError::parse::<Self>());
82 }
83
84 if (byte & 0b1100_0000) == 0b1000_0000 {
89 if (byte & 0b0010_0000) == 0 {
91 return Err(UleError::parse::<Self>());
92 }
93
94 if (byte & 0b0000_1000) != 0 {
96 return Err(UleError::parse::<Self>());
97 }
98
99 if (byte & 0b0000_0100) != 0 && (byte & 0b0000_0010) != 0 {
101 return Err(UleError::parse::<Self>());
102 }
103 }
104 }
105
106 Ok(())
107 }
108}
109
110impl AsULE for PatternKey {
111 type ULE = PatternKeyULE;
112
113 fn to_unaligned(self) -> Self::ULE {
114 let byte = match self {
115 PatternKey::Binary(value) => value,
116 PatternKey::Decimal(value) => {
117 let sign = if value < 0 { 0b0010_0000 } else { 0 };
118 debug_assert!(value > -32 && value < 32);
119 (0b01 << 6) | sign | (value.unsigned_abs() & 0b0001_1111)
120 }
121 PatternKey::Power { power, count } => {
122 let power_bits = {
123 match power {
124 PowerValue::Two => 0b10 << 4,
125 PowerValue::Three => 0b11 << 4,
126 }
127 };
128 (0b10 << 6) | power_bits | count as u8
130 }
131 };
132
133 PatternKeyULE(byte)
134 }
135
136 fn from_unaligned(unaligned: Self::ULE) -> Self {
137 let byte = unaligned.0;
138
139 let variant = (byte & 0b1100_0000) >> 6;
140 let value = byte & 0b0011_1111;
141
142 match variant {
143 0b00 => PatternKey::Binary(value),
144 0b01 => match value & 0b0010_0000 {
145 0b0000_0000 => PatternKey::Decimal(value as i8),
146 0b0010_0000 => PatternKey::Decimal(-((value & 0b0001_1111) as i8)),
147 _ => unreachable!(),
148 },
149 0b10 => {
150 let power = match value & 0b0011_0000 {
151 0b0010_0000 => PowerValue::Two,
152 0b0011_0000 => PowerValue::Three,
153 _ => unreachable!(),
154 };
155 let count = value & 0b0000_1111;
156 PatternKey::Power {
157 power,
158 count: count.into(),
159 }
160 }
161 _ => unreachable!(),
162 }
163 }
164}
165
166impl<'a> ZeroMapKV<'a> for PatternKey {
167 type Container = zerovec::ZeroVec<'a, PatternKey>;
168 type Slice = zerovec::ZeroSlice<PatternKey>;
169 type GetType = <PatternKey as AsULE>::ULE;
170 type OwnedType = PatternKey;
171}
172
173#[test]
174fn test_pattern_key_ule() {
175 use PowerValue::{Three, Two};
176
177 let binary = PatternKey::Binary(0b0000_1111);
178 let binary_ule = binary.to_unaligned();
179 PatternKeyULE::validate_bytes(&[binary_ule.0]).unwrap();
180 assert_eq!(binary_ule.0, 0b0000_1111);
181
182 let decimal = PatternKey::Decimal(0b0000_1111);
183 let decimal_ule = decimal.to_unaligned();
184 PatternKeyULE::validate_bytes(&[decimal_ule.0]).unwrap();
185 assert_eq!(decimal_ule.0, 0b0100_1111);
186
187 let power2 = PatternKey::Power {
188 power: Two,
189 count: CompoundCount::Two,
190 };
191 let power2_ule = power2.to_unaligned();
192 PatternKeyULE::validate_bytes(&[power2_ule.0]).unwrap();
193 assert_eq!(power2_ule.0, 0b1010_0010);
194
195 let power3 = PatternKey::Power {
196 power: Three,
197 count: CompoundCount::Two,
198 };
199 let power3_ule = power3.to_unaligned();
200 PatternKeyULE::validate_bytes(&[power3_ule.0]).unwrap();
201 assert_eq!(power3_ule.0, 0b1011_0010);
202
203 let binary = PatternKey::from_unaligned(binary_ule);
204 assert_eq!(binary, PatternKey::Binary(0b0000_1111));
205
206 let decimal = PatternKey::from_unaligned(decimal_ule);
207 assert_eq!(decimal, PatternKey::Decimal(0b0000_1111));
208
209 let power2 = PatternKey::from_unaligned(power2_ule);
210 assert_eq!(
211 power2,
212 PatternKey::Power {
213 power: Two,
214 count: CompoundCount::Two,
215 }
216 );
217
218 let power3 = PatternKey::from_unaligned(power3_ule);
219 assert_eq!(
220 power3,
221 PatternKey::Power {
222 power: Three,
223 count: CompoundCount::Two,
224 }
225 );
226
227 let decimal_neg_1 = PatternKey::Decimal(-1);
228 let decimal_neg_1_ule = decimal_neg_1.to_unaligned();
229 assert_eq!(decimal_neg_1_ule.0, 0b0110_0001);
230
231 let decimal_neg_1 = PatternKey::from_unaligned(decimal_neg_1_ule);
232 assert_eq!(decimal_neg_1, PatternKey::Decimal(-1));
233
234 let unvalidated_bytes = [0b1100_0000];
236 assert_eq!(
237 PatternKeyULE::validate_bytes(&unvalidated_bytes),
238 Err(UleError::parse::<PatternKeyULE>())
239 );
240
241 let unvalidated_bytes = [0b1000_0000];
242 assert_eq!(
243 PatternKeyULE::validate_bytes(&unvalidated_bytes),
244 Err(UleError::parse::<PatternKeyULE>())
245 );
246}