icu_provider/baked/
zerotrie.rs

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//! Data stored as as [`ZeroTrieSimpleAscii`]
6
7/// This is a valid separator as `DataLocale` will never produce it.
8///
9/// Mostly for internal use
10pub const ID_SEPARATOR: u8 = 0x1E;
11
12pub use crate::DynamicDataMarker;
13use crate::{
14    prelude::{zerofrom::ZeroFrom, *},
15    ule::MaybeAsVarULE,
16};
17pub use zerotrie::ZeroTrieSimpleAscii;
18use zerovec::VarZeroSlice;
19
20fn get_index(
21    trie: ZeroTrieSimpleAscii<&'static [u8]>,
22    id: DataIdentifierBorrowed,
23    attributes_prefix_match: bool,
24) -> Option<usize> {
25    use writeable::Writeable;
26    let mut cursor = trie.cursor();
27    let _is_ascii = id.locale.write_to(&mut cursor);
28    if !id.marker_attributes.is_empty() {
29        cursor.step(ID_SEPARATOR);
30        id.marker_attributes.write_to(&mut cursor).ok()?;
31        loop {
32            if let Some(v) = cursor.take_value() {
33                break Some(v);
34            }
35            if !attributes_prefix_match || cursor.probe(0).is_none() {
36                break None;
37            }
38        }
39    } else {
40        cursor.take_value()
41    }
42}
43
44#[cfg(feature = "alloc")]
45#[allow(clippy::type_complexity)]
46fn iter(
47    trie: &'static ZeroTrieSimpleAscii<&'static [u8]>,
48) -> core::iter::FilterMap<
49    zerotrie::ZeroTrieStringIterator<'static>,
50    fn((alloc::string::String, usize)) -> Option<DataIdentifierCow<'static>>,
51> {
52    use alloc::borrow::ToOwned;
53    trie.iter().filter_map(move |(s, _)| {
54        if let Some((locale, attrs)) = s.split_once(ID_SEPARATOR as char) {
55            Some(DataIdentifierCow::from_owned(
56                DataMarkerAttributes::try_from_str(attrs).ok()?.to_owned(),
57                locale.parse().ok()?,
58            ))
59        } else {
60            s.parse().ok().map(DataIdentifierCow::from_locale)
61        }
62    })
63}
64
65/// Regular baked data: a trie for lookups and a slice of values
66#[derive(Debug)]
67pub struct Data<M: DataMarker> {
68    // Unsafe invariant: actual values contained MUST be valid indices into `values`
69    trie: ZeroTrieSimpleAscii<&'static [u8]>,
70    values: &'static [M::DataStruct],
71}
72
73impl<M: DataMarker> Data<M> {
74    /// Construct from a trie and values
75    ///
76    /// # Safety
77    /// The actual values contained in the trie must be valid indices into `values`
78    pub const unsafe fn from_trie_and_values_unchecked(
79        trie: ZeroTrieSimpleAscii<&'static [u8]>,
80        values: &'static [M::DataStruct],
81    ) -> Self {
82        Self { trie, values }
83    }
84}
85
86impl<M: DataMarker> super::private::Sealed for Data<M> {}
87impl<M: DataMarker> super::DataStore<M> for Data<M> {
88    fn get(
89        &self,
90        id: DataIdentifierBorrowed,
91        attributes_prefix_match: bool,
92    ) -> Option<DataPayload<M>> {
93        get_index(self.trie, id, attributes_prefix_match)
94            // Safety: Allowed since `i` came from the trie and the field safety invariant
95            .map(|i| unsafe { self.values.get_unchecked(i) })
96            .map(DataPayload::from_static_ref)
97    }
98
99    #[cfg(feature = "alloc")]
100    type IterReturn = core::iter::FilterMap<
101        zerotrie::ZeroTrieStringIterator<'static>,
102        fn((alloc::string::String, usize)) -> Option<DataIdentifierCow<'static>>,
103    >;
104    #[cfg(feature = "alloc")]
105    fn iter(&'static self) -> Self::IterReturn {
106        iter(&self.trie)
107    }
108}
109
110/// Optimized data stored as a single VarZeroSlice to reduce token count
111#[allow(missing_debug_implementations)] // Debug on this will not be too useful
112pub struct DataForVarULEs<M: DataMarker>
113where
114    M::DataStruct: MaybeAsVarULE,
115    M::DataStruct: ZeroFrom<'static, <M::DataStruct as MaybeAsVarULE>::EncodedStruct>,
116{
117    // Unsafe invariant: actual values contained MUST be valid indices into `values`
118    trie: ZeroTrieSimpleAscii<&'static [u8]>,
119    values: &'static VarZeroSlice<<M::DataStruct as MaybeAsVarULE>::EncodedStruct>,
120}
121
122impl<M: DataMarker> super::private::Sealed for DataForVarULEs<M>
123where
124    M::DataStruct: MaybeAsVarULE,
125    M::DataStruct: ZeroFrom<'static, <M::DataStruct as MaybeAsVarULE>::EncodedStruct>,
126{
127}
128
129impl<M: DataMarker> DataForVarULEs<M>
130where
131    M::DataStruct: MaybeAsVarULE,
132    M::DataStruct: ZeroFrom<'static, <M::DataStruct as MaybeAsVarULE>::EncodedStruct>,
133{
134    /// Construct from a trie and values
135    ///
136    /// # Safety
137    /// The actual values contained in the trie must be valid indices into `values`
138    pub const unsafe fn from_trie_and_values_unchecked(
139        trie: ZeroTrieSimpleAscii<&'static [u8]>,
140        values: &'static VarZeroSlice<<M::DataStruct as MaybeAsVarULE>::EncodedStruct>,
141    ) -> Self {
142        Self { trie, values }
143    }
144}
145
146impl<M: DataMarker> super::DataStore<M> for DataForVarULEs<M>
147where
148    M::DataStruct: MaybeAsVarULE,
149    M::DataStruct: ZeroFrom<'static, <M::DataStruct as MaybeAsVarULE>::EncodedStruct>,
150{
151    fn get(
152        &self,
153        id: DataIdentifierBorrowed,
154        attributes_prefix_match: bool,
155    ) -> Option<DataPayload<M>> {
156        get_index(self.trie, id, attributes_prefix_match)
157            // Safety: Allowed since `i` came from the trie and the field safety invariant
158            .map(|i| unsafe { self.values.get_unchecked(i) })
159            .map(M::DataStruct::zero_from)
160            .map(DataPayload::from_owned)
161    }
162
163    #[cfg(feature = "alloc")]
164    type IterReturn = core::iter::FilterMap<
165        zerotrie::ZeroTrieStringIterator<'static>,
166        fn((alloc::string::String, usize)) -> Option<DataIdentifierCow<'static>>,
167    >;
168    #[cfg(feature = "alloc")]
169    fn iter(&'static self) -> Self::IterReturn {
170        iter(&self.trie)
171    }
172}