1#[cfg(feature = "alloc")]
6use alloc::borrow::Cow;
7#[cfg(feature = "alloc")]
8use alloc::borrow::ToOwned;
9#[cfg(feature = "alloc")]
10use alloc::boxed::Box;
11#[cfg(feature = "alloc")]
12use alloc::string::String;
13#[cfg(feature = "alloc")]
14use core::cmp::Ordering;
15use core::default::Default;
16use core::fmt;
17use core::fmt::Debug;
18use core::hash::Hash;
19use core::ops::Deref;
20#[cfg(feature = "alloc")]
21use zerovec::ule::VarULE;
22
23pub use icu_locale_core::DataLocale;
24
25#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
27#[allow(clippy::exhaustive_structs)] pub struct DataRequest<'a> {
29 pub id: DataIdentifierBorrowed<'a>,
34 pub metadata: DataRequestMetadata,
36}
37
38#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
41#[non_exhaustive]
42pub struct DataRequestMetadata {
43 pub silent: bool,
45 pub attributes_prefix_match: bool,
47}
48
49#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
51#[non_exhaustive]
52pub struct DataIdentifierBorrowed<'a> {
53 pub marker_attributes: &'a DataMarkerAttributes,
55 pub locale: &'a DataLocale,
57}
58
59impl fmt::Display for DataIdentifierBorrowed<'_> {
60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61 fmt::Display::fmt(self.locale, f)?;
62 if !self.marker_attributes.is_empty() {
63 write!(f, "/{}", self.marker_attributes.as_str())?;
64 }
65 Ok(())
66 }
67}
68
69impl<'a> DataIdentifierBorrowed<'a> {
70 pub fn for_locale(locale: &'a DataLocale) -> Self {
72 Self {
73 locale,
74 ..Default::default()
75 }
76 }
77
78 pub fn for_marker_attributes(marker_attributes: &'a DataMarkerAttributes) -> Self {
80 Self {
81 marker_attributes,
82 ..Default::default()
83 }
84 }
85
86 pub fn for_marker_attributes_and_locale(
88 marker_attributes: &'a DataMarkerAttributes,
89 locale: &'a DataLocale,
90 ) -> Self {
91 Self {
92 marker_attributes,
93 locale,
94 }
95 }
96
97 #[cfg(feature = "alloc")]
99 pub fn into_owned(self) -> DataIdentifierCow<'static> {
100 DataIdentifierCow {
101 marker_attributes: Cow::Owned(self.marker_attributes.to_owned()),
102 locale: *self.locale,
103 }
104 }
105
106 #[cfg(feature = "alloc")]
108 pub fn as_cow(self) -> DataIdentifierCow<'a> {
109 DataIdentifierCow {
110 marker_attributes: Cow::Borrowed(self.marker_attributes),
111 locale: *self.locale,
112 }
113 }
114}
115
116#[derive(Debug, PartialEq, Eq, Hash, Clone)]
120#[non_exhaustive]
121#[cfg(feature = "alloc")]
122pub struct DataIdentifierCow<'a> {
123 pub marker_attributes: Cow<'a, DataMarkerAttributes>,
125 pub locale: DataLocale,
127}
128
129#[cfg(feature = "alloc")]
130impl PartialOrd for DataIdentifierCow<'_> {
131 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
132 Some(self.cmp(other))
133 }
134}
135
136#[cfg(feature = "alloc")]
137impl Ord for DataIdentifierCow<'_> {
138 fn cmp(&self, other: &Self) -> Ordering {
139 self.marker_attributes
140 .cmp(&other.marker_attributes)
141 .then_with(|| self.locale.total_cmp(&other.locale))
142 }
143}
144
145#[cfg(feature = "alloc")]
146impl fmt::Display for DataIdentifierCow<'_> {
147 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148 fmt::Display::fmt(&self.locale, f)?;
149 if !self.marker_attributes.is_empty() {
150 write!(f, "/{}", self.marker_attributes.as_str())?;
151 }
152 Ok(())
153 }
154}
155
156#[cfg(feature = "alloc")]
157impl<'a> DataIdentifierCow<'a> {
158 pub fn as_borrowed(&'a self) -> DataIdentifierBorrowed<'a> {
160 DataIdentifierBorrowed {
161 marker_attributes: &self.marker_attributes,
162 locale: &self.locale,
163 }
164 }
165
166 pub fn from_locale(locale: DataLocale) -> Self {
168 Self {
169 marker_attributes: Cow::Borrowed(DataMarkerAttributes::empty()),
170 locale,
171 }
172 }
173
174 pub fn from_marker_attributes(marker_attributes: &'a DataMarkerAttributes) -> Self {
176 Self {
177 marker_attributes: Cow::Borrowed(marker_attributes),
178 locale: Default::default(),
179 }
180 }
181
182 pub fn from_marker_attributes_owned(marker_attributes: Box<DataMarkerAttributes>) -> Self {
184 Self {
185 marker_attributes: Cow::Owned(marker_attributes),
186 locale: Default::default(),
187 }
188 }
189
190 #[cfg(feature = "alloc")]
192 pub fn from_owned(marker_attributes: Box<DataMarkerAttributes>, locale: DataLocale) -> Self {
193 Self {
194 marker_attributes: Cow::Owned(marker_attributes),
195 locale,
196 }
197 }
198
199 pub fn from_borrowed_and_owned(
201 marker_attributes: &'a DataMarkerAttributes,
202 locale: DataLocale,
203 ) -> Self {
204 Self {
205 marker_attributes: Cow::Borrowed(marker_attributes),
206 locale,
207 }
208 }
209
210 pub fn is_unknown(&self) -> bool {
212 self.marker_attributes.is_empty() && self.locale.is_unknown()
213 }
214}
215
216#[cfg(feature = "alloc")]
217impl Default for DataIdentifierCow<'_> {
218 fn default() -> Self {
219 Self {
220 marker_attributes: Cow::Borrowed(Default::default()),
221 locale: Default::default(),
222 }
223 }
224}
225
226#[derive(PartialEq, Eq, Ord, PartialOrd, Hash)]
230#[repr(transparent)]
231pub struct DataMarkerAttributes {
232 value: str,
234}
235
236impl Default for &DataMarkerAttributes {
237 fn default() -> Self {
238 DataMarkerAttributes::empty()
239 }
240}
241
242impl Deref for DataMarkerAttributes {
243 type Target = str;
244 #[inline]
245 fn deref(&self) -> &Self::Target {
246 &self.value
247 }
248}
249
250impl Debug for DataMarkerAttributes {
251 #[inline]
252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253 self.value.fmt(f)
254 }
255}
256
257#[derive(Debug)]
259#[non_exhaustive]
260pub struct AttributeParseError;
261
262impl DataMarkerAttributes {
263 const fn validate(s: &[u8]) -> Result<(), AttributeParseError> {
265 let mut i = 0;
266 while i < s.len() {
267 #[allow(clippy::indexing_slicing)] if !matches!(s[i], b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'-' | b'_') {
269 return Err(AttributeParseError);
270 }
271 i += 1;
272 }
273 Ok(())
274 }
275
276 pub const fn try_from_str(s: &str) -> Result<&Self, AttributeParseError> {
280 Self::try_from_utf8(s.as_bytes())
281 }
282
283 pub const fn try_from_utf8(code_units: &[u8]) -> Result<&Self, AttributeParseError> {
299 let Ok(()) = Self::validate(code_units) else {
300 return Err(AttributeParseError);
301 };
302
303 let s = unsafe { core::str::from_utf8_unchecked(code_units) };
305
306 Ok(unsafe { &*(s as *const str as *const Self) })
308 }
309
310 #[cfg(feature = "alloc")]
314 pub fn try_from_string(s: String) -> Result<Box<Self>, AttributeParseError> {
315 let Ok(()) = Self::validate(s.as_bytes()) else {
316 return Err(AttributeParseError);
317 };
318
319 Ok(unsafe { core::mem::transmute::<Box<str>, Box<Self>>(s.into_boxed_str()) })
321 }
322
323 pub const fn from_str_or_panic(s: &str) -> &Self {
327 let Ok(r) = Self::try_from_str(s) else {
328 panic!("Invalid marker attribute syntax")
329 };
330 r
331 }
332
333 pub const fn empty() -> &'static Self {
335 unsafe { &*("" as *const str as *const Self) }
337 }
338
339 pub const fn as_str(&self) -> &str {
341 &self.value
342 }
343}
344
345#[cfg(feature = "alloc")]
346impl ToOwned for DataMarkerAttributes {
347 type Owned = Box<Self>;
348 fn to_owned(&self) -> Self::Owned {
349 unsafe { core::mem::transmute::<Box<str>, Box<Self>>(self.as_str().to_boxed()) }
351 }
352}
353
354#[test]
355fn test_data_marker_attributes_from_utf8() {
356 let bytes_vec: Vec<&[u8]> = vec![
357 b"long-meter",
358 b"long",
359 b"meter",
360 b"short-meter-second",
361 b"usd",
362 ];
363
364 for bytes in bytes_vec {
365 let marker = DataMarkerAttributes::try_from_utf8(bytes).unwrap();
366 assert_eq!(marker.to_string().as_bytes(), bytes);
367 }
368}