icu_provider/baked/
zerotrie.rs1pub const ID_SEPARATOR: u8 = 0x1E;
11
12pub use crate::DynamicDataMarker;
13use crate::{
14 prelude::{zerofrom::ZeroFrom, *},
15 ule::MaybeAsVarULE,
16};
17#[cfg(feature = "alloc")]
18use alloc::string::String;
19use core::fmt;
20pub use zerotrie::ZeroTrieSimpleAscii;
21use zerotrie::cursor::ZeroTrieSimpleAsciiCursor;
22use zerovec::{VarZeroSlice, vecs::Index32};
23
24struct EarlyExitCursor<'a, 'b>(&'b mut ZeroTrieSimpleAsciiCursor<'a>);
27
28impl fmt::Write for EarlyExitCursor<'_, '_> {
29 #[inline]
30 fn write_str(&mut self, s: &str) -> fmt::Result {
31 self.0.write_str(s)?;
32 if self.0.is_empty() {
33 Err(fmt::Error)
34 } else {
35 Ok(())
36 }
37 }
38}
39
40fn get_index(
41 trie: ZeroTrieSimpleAscii<&'static [u8]>,
42 id: DataIdentifierBorrowed,
43 attributes_prefix_match: bool,
44) -> Option<usize> {
45 use writeable::Writeable;
46 let mut cursor = trie.cursor();
47 let _is_ascii = id.locale.write_to(&mut EarlyExitCursor(&mut cursor));
48 if !id.marker_attributes.is_empty() {
49 cursor.step(ID_SEPARATOR);
50 id.marker_attributes
51 .write_to(&mut EarlyExitCursor(&mut cursor))
52 .ok()?;
53 loop {
54 if let Some(v) = cursor.take_value() {
55 break Some(v);
56 }
57 if !attributes_prefix_match || cursor.probe(0).is_none() {
58 break None;
59 }
60 }
61 } else {
62 cursor.take_value()
63 }
64}
65
66#[cfg(feature = "alloc")]
67#[expect(clippy::type_complexity)]
68fn iter(
69 trie: &'static ZeroTrieSimpleAscii<&'static [u8]>,
70) -> core::iter::FilterMap<
71 zerotrie::ZeroTrieStringIterator<'static>,
72 fn((String, usize)) -> Option<DataIdentifierCow<'static>>,
73> {
74 use alloc::borrow::ToOwned;
75 trie.iter().filter_map(move |(s, _)| {
76 if let Some((locale, attrs)) = s.split_once(ID_SEPARATOR as char) {
77 Some(DataIdentifierCow::from_owned(
78 DataMarkerAttributes::try_from_str(attrs).ok()?.to_owned(),
79 locale.parse().ok()?,
80 ))
81 } else {
82 s.parse().ok().map(DataIdentifierCow::from_locale)
83 }
84 })
85}
86
87#[derive(Debug)]
89pub struct Data<M: DataMarker> {
90 trie: ZeroTrieSimpleAscii<&'static [u8]>,
92 values: &'static [M::DataStruct],
93}
94
95impl<M: DataMarker> Data<M> {
96 pub const unsafe fn from_trie_and_values_unchecked(
101 trie: ZeroTrieSimpleAscii<&'static [u8]>,
102 values: &'static [M::DataStruct],
103 ) -> Self {
104 Self { trie, values }
105 }
106}
107
108impl<M: DataMarker> super::private::Sealed for Data<M> {}
109impl<M: DataMarker> super::DataStore<M> for Data<M> {
110 fn get(
111 &self,
112 id: DataIdentifierBorrowed,
113 attributes_prefix_match: bool,
114 ) -> Option<DataPayload<M>> {
115 get_index(self.trie, id, attributes_prefix_match)
116 .map(|i| unsafe { self.values.get_unchecked(i) })
118 .map(DataPayload::from_static_ref)
119 }
120
121 #[cfg(feature = "alloc")]
122 type IterReturn = core::iter::FilterMap<
123 zerotrie::ZeroTrieStringIterator<'static>,
124 fn((String, usize)) -> Option<DataIdentifierCow<'static>>,
125 >;
126 #[cfg(feature = "alloc")]
127 fn iter(&'static self) -> Self::IterReturn {
128 iter(&self.trie)
129 }
130}
131
132#[derive(Debug)]
134pub struct DataRef<M: DataMarker> {
135 trie: ZeroTrieSimpleAscii<&'static [u8]>,
137 values: &'static [&'static M::DataStruct],
138}
139
140impl<M: DataMarker> DataRef<M> {
141 pub const unsafe fn from_trie_and_refs_unchecked(
146 trie: ZeroTrieSimpleAscii<&'static [u8]>,
147 values: &'static [&'static M::DataStruct],
148 ) -> Self {
149 Self { trie, values }
150 }
151}
152
153impl<M: DataMarker> super::private::Sealed for DataRef<M> {}
154impl<M: DataMarker> super::DataStore<M> for DataRef<M> {
155 fn get(
156 &self,
157 id: DataIdentifierBorrowed,
158 attributes_prefix_match: bool,
159 ) -> Option<DataPayload<M>> {
160 get_index(self.trie, id, attributes_prefix_match)
161 .map(|i| unsafe { self.values.get_unchecked(i) })
163 .copied()
164 .map(DataPayload::from_static_ref)
165 }
166
167 #[cfg(feature = "alloc")]
168 type IterReturn = core::iter::FilterMap<
169 zerotrie::ZeroTrieStringIterator<'static>,
170 fn((String, usize)) -> Option<DataIdentifierCow<'static>>,
171 >;
172 #[cfg(feature = "alloc")]
173 fn iter(&'static self) -> Self::IterReturn {
174 iter(&self.trie)
175 }
176}
177
178#[allow(missing_debug_implementations)] pub struct DataForVarULEs<M: DataMarker>
181where
182 M::DataStruct: MaybeAsVarULE,
183 M::DataStruct: ZeroFrom<'static, <M::DataStruct as MaybeAsVarULE>::EncodedStruct>,
184{
185 trie: ZeroTrieSimpleAscii<&'static [u8]>,
187 values: &'static VarZeroSlice<<M::DataStruct as MaybeAsVarULE>::EncodedStruct, Index32>,
188}
189
190impl<M: DataMarker> super::private::Sealed for DataForVarULEs<M>
191where
192 M::DataStruct: MaybeAsVarULE,
193 M::DataStruct: ZeroFrom<'static, <M::DataStruct as MaybeAsVarULE>::EncodedStruct>,
194{
195}
196
197impl<M: DataMarker> DataForVarULEs<M>
198where
199 M::DataStruct: MaybeAsVarULE,
200 M::DataStruct: ZeroFrom<'static, <M::DataStruct as MaybeAsVarULE>::EncodedStruct>,
201{
202 pub const unsafe fn from_trie_and_values_unchecked(
207 trie: ZeroTrieSimpleAscii<&'static [u8]>,
208 values: &'static VarZeroSlice<<M::DataStruct as MaybeAsVarULE>::EncodedStruct, Index32>,
209 ) -> Self {
210 Self { trie, values }
211 }
212}
213
214impl<M: DataMarker> super::DataStore<M> for DataForVarULEs<M>
215where
216 M::DataStruct: MaybeAsVarULE,
217 M::DataStruct: ZeroFrom<'static, <M::DataStruct as MaybeAsVarULE>::EncodedStruct>,
218{
219 fn get(
220 &self,
221 id: DataIdentifierBorrowed,
222 attributes_prefix_match: bool,
223 ) -> Option<DataPayload<M>> {
224 get_index(self.trie, id, attributes_prefix_match)
225 .map(|i| unsafe { self.values.get_unchecked(i) })
227 .map(M::DataStruct::zero_from)
228 .map(DataPayload::from_owned)
229 }
230
231 #[cfg(feature = "alloc")]
232 type IterReturn = core::iter::FilterMap<
233 zerotrie::ZeroTrieStringIterator<'static>,
234 fn((String, usize)) -> Option<DataIdentifierCow<'static>>,
235 >;
236 #[cfg(feature = "alloc")]
237 fn iter(&'static self) -> Self::IterReturn {
238 iter(&self.trie)
239 }
240}