taitan_orm_parser/info_parser/
attr_parser.rs1use quote::ToTokens;
2use std::borrow::Cow;
3use syn::punctuated::Punctuated;
4use syn::{Attribute, Expr, Lit, Meta, Path, Token};
5
6pub struct AttrParser;
22
23#[derive(Debug, Clone, PartialOrd, PartialEq)]
24pub struct NamedAttribute<'a> {
25 pub name: Cow<'a, str>,
26 pub values: Vec<Cow<'a, str>>,
27}
28#[derive(Debug, Clone, PartialOrd, PartialEq)]
29pub struct NamedAttributes<'a> {
30 pub name: Cow<'a, str>,
31 pub attrs: Vec<NamedAttribute<'a>>,
32}
33
34impl<'a> NamedAttribute<'a> {
35 pub fn from_str<N, F>(name: N, val_str: F) -> Self
36 where
37 N: Into<Cow<'a, str>>,
38 F: Into<Cow<'a, str>>,
39 {
40 let value_str: String = val_str.into().into_owned();
41 let values: Vec<Cow<'a, str>> = value_str
42 .split(|c| c == ' ' || c == ',')
43 .filter(|s| !s.is_empty())
44 .map(|s| Cow::Owned(s.to_string()))
45 .collect();
46 Self {
47 name: name.into(),
48 values,
49 }
50 }
51
52 pub fn from_origin<N, F>(name: N, val_str: F) -> Self
53 where
54 N: Into<Cow<'a, str>>,
55 F: Into<Cow<'a, str>>,
56 {
57 Self {
58 name: name.into(),
59 values: vec![val_str.into()],
60 }
61 }
62 pub fn from_vec<N>(name: N, values: Vec<Cow<'a, str>>) -> Self
63 where
64 N: Into<Cow<'a, str>>,
65 {
66 Self {
67 name: name.into(),
68 values,
69 }
70 }
71
72 pub fn get_single_value(&self) -> &Cow<'a, str> {
73 if self.values.len() != 1 {
74 panic!("attribute must have a single value");
75 }
76 &self.values[0]
77 }
78
79}
80impl AttrParser {
81 pub fn is_attr(attr: &Attribute, name: &str) -> bool {
82 let path: &Path = attr.path();
83 let path_ident = path.get_ident().unwrap();
84 let attr_path_name = path_ident.to_string();
85 attr_path_name == name
86 }
87 pub fn has_attr(attrs: &[Attribute], name: &str) -> bool {
88 attrs.iter().any(|attr| Self::is_attr(attr, name))
89 }
90
91 pub fn get_attr<'a>(attrs: &'a [Attribute], name: &'a str) -> Option<&'a Attribute> {
92 attrs.iter().find(|a| Self::is_attr(a, name))
93 }
94 pub fn get_attrs<'a>(attrs: &'a [Attribute], name: &'a str) -> Vec<&'a Attribute> {
95 attrs
96 .iter()
97 .filter(|a| Self::is_attr(a, name))
98 .collect()
99 }
100
101
102 pub fn parse<'a>(attr: &'a Attribute) -> Option<NamedAttribute<'a>> {
103 let path: &Path = attr.path();
104 let attr_name = path.get_ident().unwrap().to_string();
105 match &attr.meta {
106 Meta::NameValue(name_value) => match &name_value.value {
107 Expr::Lit(s) => match &s.lit {
108 Lit::Str(s) => Some(NamedAttribute::from_str(attr_name, s.value())),
109 _ => None,
110 },
111 Expr::Path(expr_path) => {
112 let segments = &expr_path.path.segments;
113 if segments.is_empty() {
114 return None;
115 }
116 let first_segment = segments.first().unwrap();
117 Some(NamedAttribute::from_str(
118 attr_name,
119 first_segment.ident.to_string(),
120 ))
121 }
122 _ => None,
123 },
124 Meta::List(list) => {
125 if let Ok(expr) = list.parse_args::<Expr>() {
126 return match expr {
127 Expr::Lit(expr_lit) => {
128 if let Lit::Str(s) = expr_lit.lit {
130 return Some(NamedAttribute::from_str(attr_name, s.value()));
131 }
132 None
133 }
134 Expr::Path(expr_path) => {
135 let segments = expr_path.path.segments;
136 if segments.is_empty() {
137 return None;
138 }
139 let first_segment = segments.first().unwrap();
140 Some(NamedAttribute::from_str(
141 attr_name,
142 first_segment.ident.to_string(),
143 ))
144 }
145 _ => None,
146 };
147 }
148 if let Ok(value_list) =
149 list.parse_args_with(Punctuated::<Expr, Token![,]>::parse_terminated)
150 {
151 let values = value_list
152 .into_iter()
153 .map(|v| Cow::Owned(v.to_token_stream().to_string()))
154 .collect();
155 return Some(NamedAttribute::from_vec(attr_name, values));
156 }
157
158 None
159 }
160 _ => None,
161 }
162 }
163
164 pub fn parse_one<'a>(attrs: &'a Attribute) -> NamedAttribute<'a> {
165 let attr_opt = Self::parse(attrs);
166 if let Some(attr) = attr_opt {
167 attr
168 } else {
169 panic!("cannot parse attribute")
170 }
171 }
172
173 pub fn parse_one_single<'a>(attrs: &'a Attribute) -> NamedAttribute<'a> {
174 let attr_opt = Self::parse(attrs);
175 if let Some(attr) = attr_opt {
176 if attr.values.len() != 1 {
177 panic!("cannot parse attribute to one single value")
178 }
179 attr
180 } else {
181 panic!("cannot parse attribute")
182 }
183 }
184
185 pub fn parse_list<'a>(attr: &'a Attribute) -> Vec<NamedAttribute<'a>> {
186 let path: &Path = attr.path();
187 let attr_name = path.get_ident().unwrap().to_string();
188 match &attr.meta {
189 Meta::NameValue(name_value) => match &name_value.value {
190 Expr::Lit(s) => match &s.lit {
191 Lit::Str(s) => vec![NamedAttribute::from_str(attr_name, s.value())],
192 _ => vec![],
193 },
194 Expr::Path(expr_path) => {
195 let segments = &expr_path.path.segments;
196 if segments.is_empty() {
197 return vec![];
198 }
199 let first_segment = segments.first().unwrap();
200 vec![NamedAttribute::from_str(
201 attr_name,
202 first_segment.ident.to_string(),
203 )]
204 }
205 _ => vec![],
206 },
207 Meta::List(list) => {
208 if let Ok(expr_list) =
209 list.parse_args_with(Punctuated::<Expr, Token![,]>::parse_terminated)
210 {
211 let values: Vec<NamedAttribute> = expr_list
212 .into_iter()
213 .map(|expr| {
214 if let Expr::Assign(assign) = expr {
215 let name = assign.left.into_token_stream().to_string();
216 let values_str = assign.right.into_token_stream().to_string();
217 return if name == "generated" {
219 let values_inner_str = extract_quote_string(values_str.as_str());
220 Some(NamedAttribute::from_origin(name, values_inner_str))
221 } else {
222 let values_inner_str = extract_inner_string(values_str.as_str());
223 Some(NamedAttribute::from_str(name, values_inner_str))
224 }
225 }
226 if let Expr::Call(call_expr) = expr {
227 let name = call_expr.func.to_token_stream().to_string();
228 let args = call_expr.args.into_token_stream().to_string();
229 return Some(NamedAttribute::from_str(name, args));
230 }
231 return None;
232 })
233 .filter(|v| v.is_some())
234 .map(|v| v.unwrap())
235 .collect();
236 return values;
237 }
238
239
240 if let Ok(expr) = list.parse_args::<Expr>() {
241 return match expr {
242 Expr::Lit(expr_lit) => {
243 if let Lit::Str(s) = expr_lit.lit {
245 return vec![NamedAttribute::from_str(attr_name, s.value())];
246 }
247 vec![]
248 }
249 Expr::Path(expr_path) => {
250 let segments = expr_path.path.segments;
251 if segments.is_empty() {
252 return vec![];
253 }
254 let first_segment = segments.first().unwrap();
255 return vec![NamedAttribute::from_str(
256 attr_name,
257 first_segment.ident.to_string(),
258 )];
259 }
260 _ => vec![],
261 };
262 }
263 if let Ok(value_list) =
264 list.parse_args_with(Punctuated::<Expr, Token![,]>::parse_terminated)
265 {
266 let values = value_list
267 .into_iter()
268 .map(|v| Cow::Owned(v.to_token_stream().to_string()))
269 .collect();
270 return vec![NamedAttribute::from_vec(attr_name, values)];
271 }
272 vec![]
273 }
274 _ => vec![],
275 }
276 }
277
278 pub fn extract<'a>(attrs: &'a [Attribute], name: &'a str) -> Option<NamedAttribute<'a>> {
279 let attr_opt = attrs.iter().find(|a| Self::is_attr(a, name));
280 if let Some(attr) = attr_opt {
281 let attr_opt = Self::parse(&attr);
282 if let Some(named) = attr_opt {
283 Some(named)
284 } else {
285 panic!("cannot parse attribute")
286 }
287 } else {
288 None
289 }
290 }
291
292 pub fn extract_one<'a>(attrs: &'a [Attribute], name: &'a str) -> NamedAttribute<'a> {
293 let attr_opt = Self::extract(attrs, name);
294 if let Some(attr) = attr_opt {
295 attr
296 } else {
297 panic!("cannot extract attribute")
298 }
299 }
300
301 pub fn extract_one_single<'a>(attrs: &'a [Attribute], name: &'a str) -> NamedAttribute<'a> {
302 let attr_opt = Self::extract(attrs, name);
303 if let Some(attr) = attr_opt {
304 if attr.values.len() != 1 {
305 panic!("cannot extract attribute to one single value")
306 }
307 attr
308 } else {
309 panic!("cannot extract attribute")
310 }
311 }
312
313 pub fn extract_list<'a>(attrs: &'a [Attribute], name: &str) -> Vec<NamedAttribute<'a>> {
314 let attr_opt = attrs.iter().find(|a| Self::is_attr(a, name));
315 if let Some(attr) = attr_opt {
316 Self::parse_list(&attr)
317 } else {
318 Vec::new()
319 }
320 }
321
322 pub fn extract_multi_one<'a>(attrs: &'a [Attribute], name: &'a str) -> Vec<NamedAttribute<'a>> {
323 let attrs: Vec<&Attribute> = attrs
324 .iter()
325 .filter(|a| Self::is_attr(a, name))
326 .collect();
327 let mut attr_list = Vec::new();
328 for attr in attrs {
329 if let Some(named) = Self::parse(&attr) {
330 attr_list.push(named.clone());
331 }
332 }
333 attr_list
334 }
335
336 pub fn extract_multi_list<'a>(attrs: &'a [Attribute], name: &'a str) -> Vec<NamedAttributes<'a>> {
337 let attrs: Vec<&Attribute> = attrs
338 .iter()
339 .filter(|a| Self::is_attr(a, name))
340 .collect();
341 let mut attr_list = Vec::new();
342 for attr in attrs {
343 let list = Self::parse_list(&attr);
344 let named_attrs = NamedAttributes {
345 name: Cow::Borrowed(name),
346 attrs: list
347 };
348 attr_list.push(named_attrs);
349 }
350 attr_list
351 }
352}
353
354fn extract_quote_string(s: &str) -> String {
355 let trimmed = s.trim();
356 if trimmed.starts_with('"') && trimmed.ends_with('"') {
357 trimmed[1..trimmed.len() - 1].trim().to_string()
358 } else {
359 trimmed.to_string()
360 }
361}
362fn extract_inner_string(s: &str) -> String {
363 let trimmed = s.trim();
364 if trimmed.starts_with('(') && trimmed.ends_with(')') {
365 trimmed[1..trimmed.len() - 1].trim().to_string()
366 } else if trimmed.starts_with('"') && trimmed.ends_with('"') {
367 trimmed[1..trimmed.len() - 1].trim().to_string()
368 } else {
369 trimmed.to_string()
370 }
371}