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