1use displaydoc::Display;
23use icu_collections::codepointtrie::{CodePointTrie, TrieValue};
24use icu_provider::prelude::*;
25use zerovec::ule::{AsULE, CharULE, ULE};
26use zerovec::ZeroVecError;
27
28#[icu_provider::data_struct(marker(
37 BidiAuxiliaryPropertiesV1Marker,
38 "props/bidiauxiliaryprops@1",
39 singleton
40))]
41#[derive(Debug, Eq, PartialEq, Clone)]
42#[cfg_attr(
43 feature = "datagen",
44 derive(serde::Serialize, databake::Bake),
45 databake(path = icu_properties::provider::bidi_data),
46)]
47#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
48pub struct BidiAuxiliaryPropertiesV1<'data> {
49 #[cfg_attr(feature = "serde", serde(borrow))]
52 pub trie: CodePointTrie<'data, MirroredPairedBracketData>,
53}
54
55impl<'data> BidiAuxiliaryPropertiesV1<'data> {
56 #[doc(hidden)]
57 pub fn new(
58 trie: CodePointTrie<'data, MirroredPairedBracketData>,
59 ) -> BidiAuxiliaryPropertiesV1<'data> {
60 BidiAuxiliaryPropertiesV1 { trie }
61 }
62}
63
64#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
65#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
66#[cfg_attr(feature = "datagen", derive(databake::Bake))]
67#[cfg_attr(feature = "datagen", databake(path = icu_properties::provider::bidi_data))]
68#[doc(hidden)] pub struct MirroredPairedBracketData {
70 pub mirroring_glyph: char,
71 pub mirrored: bool,
72 pub paired_bracket_type: CheckedBidiPairedBracketType,
73}
74
75impl Default for MirroredPairedBracketData {
76 fn default() -> Self {
77 Self {
78 mirroring_glyph: 0 as char,
79 mirrored: false,
80 paired_bracket_type: CheckedBidiPairedBracketType::None,
81 }
82 }
83}
84
85impl From<MirroredPairedBracketData> for u32 {
86 fn from(mpbd: MirroredPairedBracketData) -> u32 {
87 let mut result = mpbd.mirroring_glyph as u32;
88 result |= (mpbd.mirrored as u32) << 21;
89 result |= (mpbd.paired_bracket_type as u32) << 22;
90 result
91 }
92}
93
94#[derive(Display, Debug, Clone, Copy, PartialEq, Eq)]
96#[displaydoc("Invalid MirroredPairedBracketData serialized in int: {0}")]
97pub struct MirroredPairedBracketDataTryFromError(u32);
98
99impl TryFrom<u32> for MirroredPairedBracketData {
100 type Error = MirroredPairedBracketDataTryFromError;
101
102 fn try_from(i: u32) -> Result<Self, MirroredPairedBracketDataTryFromError> {
103 let code_point = i & 0x1FFFFF;
104 let mirroring_glyph =
105 char::try_from_u32(code_point).map_err(|_| MirroredPairedBracketDataTryFromError(i))?;
106 let mirrored = ((i >> 21) & 0x1) == 1;
107 let paired_bracket_type = {
108 let value = ((i >> 22) & 0x3) as u8;
109 match value {
110 0 => CheckedBidiPairedBracketType::None,
111 1 => CheckedBidiPairedBracketType::Open,
112 2 => CheckedBidiPairedBracketType::Close,
113 _ => {
114 return Err(MirroredPairedBracketDataTryFromError(i));
115 }
116 }
117 };
118 Ok(MirroredPairedBracketData {
119 mirroring_glyph,
120 mirrored,
121 paired_bracket_type,
122 })
123 }
124}
125
126#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
130#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
131#[cfg_attr(feature = "datagen", derive(databake::Bake))]
132#[cfg_attr(feature = "datagen", databake(path = icu_properties::provider::bidi_data))]
133#[repr(u8)]
134#[zerovec::make_ule(CheckedBidiPairedBracketTypeULE)]
135#[allow(clippy::exhaustive_enums)]
137pub enum CheckedBidiPairedBracketType {
138 None = 0,
140 Open = 1,
142 Close = 2,
144}
145
146#[doc(hidden)]
157#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
159#[repr(C, packed)]
160pub struct MirroredPairedBracketDataULE([u8; 3]);
161
162unsafe impl ULE for MirroredPairedBracketDataULE {
173 #[inline]
174 fn validate_byte_slice(bytes: &[u8]) -> Result<(), ZeroVecError> {
175 if bytes.len() % 3 != 0 {
176 return Err(ZeroVecError::length::<Self>(bytes.len()));
177 }
178 #[allow(clippy::indexing_slicing)] for byte_triple in bytes.chunks_exact(3) {
181 #[allow(clippy::unwrap_used)] let [byte0, byte1, byte2] = *<&[u8; 3]>::try_from(byte_triple).unwrap();
184 let mut mirroring_glyph_code_point: u32 = (byte2 & 0x1F) as u32;
185 mirroring_glyph_code_point = (mirroring_glyph_code_point << 8) | (byte1 as u32);
186 mirroring_glyph_code_point = (mirroring_glyph_code_point << 8) | (byte0 as u32);
187 let _mirroring_glyph =
188 char::from_u32(mirroring_glyph_code_point).ok_or(ZeroVecError::parse::<Self>())?;
189
190 if (byte2 & 0xC0) == 0xC0 {
195 return Err(ZeroVecError::parse::<Self>());
196 }
197 }
198
199 Ok(())
200 }
201}
202
203impl AsULE for MirroredPairedBracketData {
204 type ULE = MirroredPairedBracketDataULE;
205
206 #[inline]
207 fn to_unaligned(self) -> Self::ULE {
208 let mut ch = u32::from(self.mirroring_glyph);
209 ch |= u32::from(self.mirrored) << 21;
210 ch |= (self.paired_bracket_type as u32) << 22;
211 let [byte0, byte1, byte2, _] = ch.to_le_bytes();
212 MirroredPairedBracketDataULE([byte0, byte1, byte2])
213 }
214
215 #[inline]
216 fn from_unaligned(unaligned: Self::ULE) -> Self {
217 let [unaligned_byte0, unaligned_byte1, unaligned_byte2] = unaligned.0;
218 let mirroring_glyph_ule_bytes = &[unaligned_byte0, unaligned_byte1, unaligned_byte2 & 0x1F];
219 let mirroring_glyph_ule =
222 unsafe { CharULE::from_byte_slice_unchecked(mirroring_glyph_ule_bytes) };
223 let mirroring_glyph = mirroring_glyph_ule
224 .first()
225 .map(|ule| char::from_unaligned(*ule))
226 .unwrap_or(char::REPLACEMENT_CHARACTER);
227 let mirrored = ((unaligned.0[2] >> 5) & 0x1) == 1;
228 let paired_bracket_type = {
229 let discriminant = unaligned.0[2] >> 6;
230 debug_assert!(
231 discriminant != 3,
232 "Bidi_Paired_Bracket_Type can only be Open/Close/None in MirroredPairedBracketData"
233 );
234 match discriminant {
235 1 => CheckedBidiPairedBracketType::Open,
236 2 => CheckedBidiPairedBracketType::Close,
237 _ => CheckedBidiPairedBracketType::None,
238 }
239 };
240
241 MirroredPairedBracketData {
242 mirroring_glyph,
243 mirrored,
244 paired_bracket_type,
245 }
246 }
247}
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252
253 #[test]
254 fn test_parse() {
255 let data = MirroredPairedBracketData {
259 mirroring_glyph: '}',
260 mirrored: true,
261 paired_bracket_type: CheckedBidiPairedBracketType::Open,
262 };
263 let expected_bytes = &[0x7D, 0x0, 0x60];
264 assert_eq!(
265 expected_bytes,
266 MirroredPairedBracketDataULE::as_byte_slice(&[data.to_unaligned()])
267 );
268
269 let ule = MirroredPairedBracketDataULE::parse_byte_slice(expected_bytes).unwrap();
271 let parsed_data = MirroredPairedBracketData::from_unaligned(*ule.first().unwrap());
272 assert_eq!(data, parsed_data);
273 }
274
275 #[test]
276 fn test_parse_error() {
277 let ule_bytes = &mut [0x7D, 0x0, 0x60];
279
280 ule_bytes[2] |= 0xC0;
284
285 let ule_parse_result = MirroredPairedBracketDataULE::parse_byte_slice(ule_bytes);
287 assert!(ule_parse_result.is_err());
288 }
289}