icu_datetime/provider/pattern/runtime/
generic.rs1use super::{
6    super::{reference, PatternError},
7    super::{GenericPatternItem, PatternItem},
8    Pattern,
9};
10use alloc::vec::Vec;
11use core::str::FromStr;
12use icu_provider::prelude::*;
13use zerovec::ZeroVec;
14
15#[derive(Debug, PartialEq, Eq, Clone, yoke::Yokeable, zerofrom::ZeroFrom)]
27#[allow(clippy::exhaustive_structs)] #[cfg_attr(feature = "datagen", derive(databake::Bake))]
29#[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::pattern::runtime))]
30pub struct GenericPattern<'data> {
31    pub items: ZeroVec<'data, GenericPatternItem>,
33}
34
35pub(crate) const ZERO_ONE_TWO_SLICE: &zerovec::ZeroSlice<GenericPatternItem> = zerovec::zeroslice!(
37    GenericPatternItem;
38    GenericPatternItem::to_unaligned_const;
39    [
40        GenericPatternItem::Placeholder(0),
41        GenericPatternItem::Placeholder(1),
42        GenericPatternItem::Placeholder(2),
43    ]
44);
45
46impl<'data> GenericPattern<'data> {
47    pub fn combined(
69        self,
70        date: Pattern<'data>,
71        time: Pattern<'data>,
72    ) -> Result<Pattern<'static>, PatternError> {
73        let size = date.items.len() + time.items.len();
74        let mut result = Vec::with_capacity(self.items.len() + size);
75
76        for item in self.items.iter() {
77            match item {
78                GenericPatternItem::Placeholder(0) => {
79                    result.extend(time.items.iter());
80                }
81                GenericPatternItem::Placeholder(1) => {
82                    result.extend(date.items.iter());
83                }
84                GenericPatternItem::Placeholder(idx) => {
85                    #[allow(clippy::unwrap_used)] return Err(PatternError::UnknownSubstitution(
87                        char::from_digit(idx as u32, 10).unwrap(),
88                    ));
89                }
90                GenericPatternItem::Literal(ch) => result.push(PatternItem::Literal(ch)),
91            }
92        }
93
94        Ok(Pattern::from(result))
95    }
96}
97
98impl Default for GenericPattern<'_> {
99    fn default() -> Self {
100        Self {
101            items: ZeroVec::new(),
102        }
103    }
104}
105
106impl From<&reference::GenericPattern> for GenericPattern<'_> {
107    fn from(input: &reference::GenericPattern) -> Self {
108        Self {
109            items: ZeroVec::alloc_from_slice(&input.items),
110        }
111    }
112}
113
114impl From<&GenericPattern<'_>> for reference::GenericPattern {
115    fn from(input: &GenericPattern<'_>) -> Self {
116        Self {
117            items: input.items.to_vec(),
118        }
119    }
120}
121
122impl FromStr for GenericPattern<'_> {
123    type Err = PatternError;
124
125    fn from_str(s: &str) -> Result<Self, Self::Err> {
126        let reference = reference::GenericPattern::from_str(s)?;
127        Ok(Self::from(&reference))
128    }
129}
130
131#[cfg(test)]
132#[cfg(feature = "datagen")]
133mod test {
134    use super::*;
135
136    #[test]
137    fn test_runtime_generic_pattern_combine() {
138        let pattern: GenericPattern = "{1} 'at' {0}"
139            .parse()
140            .expect("Failed to parse a generic pattern.");
141
142        let date = "y/M/d".parse().expect("Failed to parse a date pattern.");
143
144        let time = "HH:mm".parse().expect("Failed to parse a time pattern.");
145
146        let pattern = pattern
147            .combined(date, time)
148            .expect("Failed to combine date and time.");
149
150        assert_eq!(pattern.to_string(), "y/M/d 'at' HH:mm");
151    }
152}