1#![allow(clippy::exhaustive_structs, clippy::exhaustive_enums)]
7
8use icu_provider::prelude::*;
19
20mod serde_dfa;
21pub use serde_dfa::SerdeDFA;
22use zerovec::VarZeroCow;
23
24#[cfg(feature = "compiled_data")]
25#[derive(Debug)]
26pub struct Baked;
34
35#[cfg(feature = "compiled_data")]
36#[allow(unused_imports)]
37const _: () = {
38 use icu_list_data::*;
39 pub mod icu {
40 pub use crate as list;
41 pub use icu_locale as locale;
42 }
43 make_provider!(Baked);
44 impl_list_and_v1!(Baked);
45 impl_list_or_v1!(Baked);
46 impl_list_unit_v1!(Baked);
47};
48
49#[cfg(feature = "datagen")]
50pub const MARKERS: &[DataMarkerInfo] = &[ListAndV1::INFO, ListOrV1::INFO, ListUnitV1::INFO];
52
53data_marker!(
54 ListAndV1,
56 "list/and/v1",
57 ListFormatterPatterns<'static>,
58);
59data_marker!(
60 ListOrV1,
62 "list/or/v1",
63 ListFormatterPatterns<'static>,
64);
65data_marker!(
66 ListUnitV1,
68 "list/unit/v1",
69 ListFormatterPatterns<'static>,
70);
71
72icu_provider::data_struct!(
73 ListFormatterPatterns<'_>,
74 #[cfg(feature = "datagen")]
75);
76
77#[derive(Clone, Debug, PartialEq, yoke::Yokeable, zerofrom::ZeroFrom)]
85#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
86#[cfg_attr(feature = "datagen", databake(path = icu_list::provider))]
87#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
88pub struct ListFormatterPatterns<'data> {
89 #[cfg_attr(feature = "serde", serde(borrow))]
91 pub start: ListJoinerPattern<'data>,
92 #[cfg_attr(feature = "serde", serde(borrow))]
95 pub middle: VarZeroCow<'data, str>,
96 #[cfg_attr(feature = "serde", serde(borrow))]
98 pub end: ConditionalListJoinerPattern<'data>,
99 #[cfg_attr(feature = "serde", serde(borrow))]
101 pub pair: Option<ConditionalListJoinerPattern<'data>>,
102}
103
104impl ListFormatterPatterns<'_> {
105 pub const NARROW: &'static DataMarkerAttributes = DataMarkerAttributes::from_str_or_panic("N");
107 #[doc(hidden)]
108 pub const NARROW_STR: &'static str = Self::NARROW.as_str();
109 pub const SHORT: &'static DataMarkerAttributes = DataMarkerAttributes::from_str_or_panic("S");
111 #[doc(hidden)]
112 pub const SHORT_STR: &'static str = Self::SHORT.as_str();
113 pub const WIDE: &'static DataMarkerAttributes = DataMarkerAttributes::from_str_or_panic("W");
115 #[doc(hidden)]
116 pub const WIDE_STR: &'static str = Self::WIDE.as_str();
117}
118
119#[derive(Clone, Debug, PartialEq, yoke::Yokeable, zerofrom::ZeroFrom)]
127#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
128#[cfg_attr(feature = "datagen", databake(path = icu_list::provider))]
129#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
130pub struct ConditionalListJoinerPattern<'data> {
131 #[cfg_attr(feature = "serde", serde(borrow))]
133 pub default: ListJoinerPattern<'data>,
134 #[cfg_attr(
136 feature = "serde",
137 serde(borrow, deserialize_with = "SpecialCasePattern::deserialize_option")
138 )]
139 pub special_case: Option<SpecialCasePattern<'data>>,
140}
141
142#[derive(Clone, Debug, PartialEq, yoke::Yokeable, zerofrom::ZeroFrom)]
150#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
151#[cfg_attr(feature = "datagen", databake(path = icu_list::provider))]
152pub struct SpecialCasePattern<'data> {
153 pub condition: SerdeDFA<'data>,
155 pub pattern: ListJoinerPattern<'data>,
157}
158
159#[cfg(feature = "serde")]
160impl<'data> SpecialCasePattern<'data> {
161 fn deserialize_option<'de: 'data, D>(deserializer: D) -> Result<Option<Self>, D::Error>
163 where
164 D: serde::de::Deserializer<'de>,
165 {
166 use serde::Deserialize;
167
168 #[derive(Deserialize)]
169 struct SpecialCasePatternOptionalDfa<'data> {
170 #[cfg_attr(
171 feature = "serde",
172 serde(borrow, deserialize_with = "SerdeDFA::maybe_deserialize")
173 )]
174 pub condition: Option<SerdeDFA<'data>>,
175 #[cfg_attr(feature = "serde", serde(borrow))]
176 pub pattern: ListJoinerPattern<'data>,
177 }
178
179 Ok(
180 match Option::<SpecialCasePatternOptionalDfa<'data>>::deserialize(deserializer)? {
181 Some(SpecialCasePatternOptionalDfa {
182 condition: Some(condition),
183 pattern,
184 }) => Some(SpecialCasePattern { condition, pattern }),
185 _ => None,
186 },
187 )
188 }
189}
190
191#[derive(Clone, Debug, PartialEq, yoke::Yokeable, zerofrom::ZeroFrom)]
199#[cfg_attr(feature = "datagen", derive(serde::Serialize))]
200pub struct ListJoinerPattern<'data> {
201 pub(crate) string: VarZeroCow<'data, str>,
203 #[cfg_attr(feature = "datagen", serde(skip))]
208 pub(crate) index_0: u8,
209 pub(crate) index_1: u8,
211}
212
213#[cfg(feature = "serde")]
214impl<'de: 'data, 'data> serde::Deserialize<'de> for ListJoinerPattern<'data> {
215 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
216 where
217 D: serde::Deserializer<'de>,
218 {
219 #[derive(serde::Deserialize)]
220 struct Dummy<'data> {
221 #[cfg_attr(feature = "serde", serde(borrow))]
222 string: VarZeroCow<'data, str>,
223 index_1: u8,
224 }
225 let Dummy { string, index_1 } = Dummy::deserialize(deserializer)?;
226
227 if index_1 as usize > string.len() {
228 use serde::de::Error;
229 Err(D::Error::custom("invalid index_1"))
230 } else {
231 Ok(ListJoinerPattern {
232 string,
233 index_0: 0,
234 index_1,
235 })
236 }
237 }
238}
239
240impl<'a> ListJoinerPattern<'a> {
241 pub const fn from_parts(string: VarZeroCow<'a, str>, index_1: u8) -> Self {
246 Self {
247 string,
248 index_0: 0,
249 index_1,
250 }
251 }
252}
253
254#[cfg(feature = "datagen")]
255impl databake::Bake for ListJoinerPattern<'_> {
256 fn bake(&self, env: &databake::CrateEnv) -> databake::TokenStream {
257 env.insert("icu_list");
258 let string = self.string.bake(env);
259 let index_1 = self.index_1.bake(env);
260 databake::quote! {
261 icu_list::provider::ListJoinerPattern::from_parts(#string, #index_1)
262 }
263 }
264}
265
266#[cfg(feature = "datagen")]
267impl databake::BakeSize for ListJoinerPattern<'_> {
268 fn borrows_size(&self) -> usize {
269 self.string.borrows_size()
270 }
271}
272
273#[cfg(all(test, feature = "datagen"))]
274#[test]
275fn databake() {
276 databake::test_bake!(
277 ListJoinerPattern,
278 const,
279 crate::provider::ListJoinerPattern::from_parts(
280 unsafe { zerovec::VarZeroCow::from_bytes_unchecked(b", ") },
281 2u8
282 ),
283 icu_list
284 );
285}