local_fmt_macros_internal/parse/
mod.rs

1use std::str::FromStr;
2
3use proc_macro2::TokenStream;
4use syn::Ident;
5
6pub enum MessageTokenValue {
7    StaticText(String),
8    PlaceholderArg(usize),
9
10    // in const, it's expected to be a &'static str
11    // in not const, it's expected to be a String
12    PlaceholderIdent(Ident),
13}
14
15impl MessageTokenValue {
16    fn to_token_stream(&self, ident_placeholder: fn(&Ident) -> TokenStream) -> TokenStream {
17        match self {
18            MessageTokenValue::StaticText(s) => {
19                let s = s.as_str();
20                quote::quote! {
21                    local_fmt::MessageFormat::StaticText(#s),
22                }
23            }
24            MessageTokenValue::PlaceholderArg(n) => {
25                let n = *n;
26                quote::quote! {
27                    local_fmt::MessageFormat::Arg(#n),
28                }
29            }
30            MessageTokenValue::PlaceholderIdent(ident) => ident_placeholder(ident),
31        }
32    }
33
34    pub fn to_alloc_token_stream(&self) -> TokenStream {
35        self.to_token_stream(|ident| {
36            quote::quote! {
37                local_fmt::MessageFormat::Text(#ident),
38            }
39        })
40    }
41
42    pub fn to_static_token_stream(&self) -> TokenStream {
43        self.to_token_stream(|ident| {
44            quote::quote! {
45                local_fmt::MessageFormat::StaticText(#ident),
46            }
47        })
48    }
49}
50
51#[derive(Debug, thiserror::Error)]
52pub enum MessageTokenValueError {
53    #[error("Placeholder number {0} is not found in the message. The hiest number found is {1}")]
54    NotFound(usize, usize),
55    #[error("not found placeholder value in braces")]
56    EmptyPlaceholder,
57}
58
59pub struct MessageToken {
60    pub values: Vec<MessageTokenValue>,
61    pub placeholder_max: Option<usize>,
62}
63
64impl MessageToken {
65    pub fn new(values: Vec<MessageTokenValue>) -> Result<Self, MessageTokenValueError> {
66        let max = values
67            .iter()
68            .filter_map(|v| match v {
69                MessageTokenValue::PlaceholderArg(n) => Some(*n),
70                _ => None,
71            })
72            .max();
73
74        if let Some(max) = max {
75            let mut flag = vec![false; max + 1];
76            for v in &values {
77                if let MessageTokenValue::PlaceholderArg(n) = v {
78                    flag[*n] = true;
79                }
80            }
81            for (i, v) in flag.iter().enumerate() {
82                if !v {
83                    return Err(MessageTokenValueError::NotFound(i, max));
84                }
85            }
86        }
87
88        Ok(Self {
89            values,
90            placeholder_max: max,
91        })
92    }
93
94    pub fn to_vec_token_stream(&self) -> TokenStream {
95        let count = self.placeholder_max.map_or(0, |v| v + 1);
96        let values = self
97            .values
98            .iter()
99            .map(|v| v.to_alloc_token_stream())
100            .collect::<Vec<TokenStream>>();
101
102        quote::quote! {
103            local_fmt::ConstMessage::<#count>::Vec(vec![
104                #(
105                    #values
106                )*
107            ])
108        }
109    }
110
111    pub fn to_static_token_stream(&self) -> TokenStream {
112        let count = self.placeholder_max.map_or(0, |v| v + 1);
113        let values = self
114            .values
115            .iter()
116            .map(|v| v.to_static_token_stream())
117            .collect::<Vec<TokenStream>>();
118
119        quote::quote! {
120            local_fmt::ConstMessage::<#count>::Static(&[
121                #(
122                    #values
123                )*
124            ])
125        }
126    }
127}
128
129impl FromStr for MessageToken {
130    type Err = MessageTokenValueError;
131
132    fn from_str(s: &str) -> Result<Self, Self::Err> {
133        let mut values = Vec::<MessageTokenValue>::new();
134
135        let mut buffer = Vec::<u8>::new();
136
137        let mut bytes = s.bytes();
138
139        while let Some(byte) = bytes.next() {
140            match byte {
141                b'{' => {
142                    if !buffer.is_empty() {
143                        values.push(MessageTokenValue::StaticText(unsafe {
144                            String::from_utf8_unchecked(std::mem::take(&mut buffer))
145                        }));
146                    }
147
148                    let mut placeholder = Vec::new();
149
150                    loop {
151                        match bytes.next() {
152                            Some(byte) => match byte {
153                                b'}' => {
154                                    if placeholder.is_empty() {
155                                        return Err(MessageTokenValueError::EmptyPlaceholder);
156                                    }
157                                    let placeholder =
158                                        unsafe { std::str::from_utf8_unchecked(&placeholder) };
159                                    let number = usize::from_str(placeholder);
160                                    match number {
161                                        Ok(ok) => {
162                                            values.push(MessageTokenValue::PlaceholderArg(ok));
163                                        }
164                                        Err(_) => {
165                                            values.push(MessageTokenValue::PlaceholderIdent(
166                                                Ident::new(
167                                                    placeholder,
168                                                    proc_macro2::Span::call_site(),
169                                                ),
170                                            ));
171                                        }
172                                    }
173                                    break;
174                                }
175                                byte => placeholder.push(byte),
176                            },
177                            None => {
178                                return Err(MessageTokenValueError::EmptyPlaceholder);
179                            }
180                        }
181                    }
182                }
183                b'\\' => {
184                    if let Some(byte) = bytes.next() {
185                        match byte {
186                            b'{' => buffer.push(b'{'),
187                            _ => {
188                                buffer.push(b'\\');
189                                buffer.push(byte);
190                            }
191                        }
192                    } else {
193                        buffer.push(b'\\');
194                    }
195                }
196                _ => buffer.push(byte),
197            }
198        }
199
200        if !buffer.is_empty() {
201            values.push(MessageTokenValue::StaticText(unsafe {
202                String::from_utf8_unchecked(buffer)
203            }));
204        }
205
206        Self::new(values)
207    }
208}