procmeta_core/
util.rs

1use proc_macro2::TokenStream;
2use proc_macro2::{Ident, Span};
3use quote::quote;
4use quote::{format_ident, ToTokens};
5use syn::parse::ParseStream;
6use syn::LitInt;
7use syn::{Expr, Field, GenericArgument, PathArguments, Token, Type, WhereClause};
8use syn::{ImplGenerics, Result};
9
10pub fn type_is_option(ty: &Type) -> bool {
11    type_of_option(ty).is_some()
12}
13
14pub fn type_of_option(ty: &Type) -> Option<&Type> {
15    let path = match ty {
16        Type::Path(ty) => &ty.path,
17        _ => return None,
18    };
19
20    let last = path.segments.last().unwrap();
21    if last.ident != "Option" {
22        return None;
23    }
24
25    let bracketed = match &last.arguments {
26        PathArguments::AngleBracketed(bracketed) => bracketed,
27        _ => return None,
28    };
29
30    if bracketed.args.len() != 1 {
31        return None;
32    }
33
34    match &bracketed.args[0] {
35        GenericArgument::Type(arg) => Some(arg),
36        _ => None,
37    }
38}
39
40pub fn type_add_colon2(ret: &mut Type) {
41    if let Type::Path(p) = ret {
42        let path = &mut p.path;
43        let segs = &mut path.segments;
44        for seg in segs {
45            if let PathArguments::AngleBracketed(ref mut ab) = &mut seg.arguments {
46                if ab.colon2_token.is_none() {
47                    ab.colon2_token = Some(<Token![::]>::default());
48                }
49            }
50        }
51    }
52}
53
54pub fn meta_list_to_fields(list: &syn::MetaList) -> Result<Vec<Field>> {
55    list.parse_args_with(|stream: ParseStream| -> Result<Vec<Field>> {
56        let mut fields: Vec<Field> = vec![];
57        let named = stream.parse_terminated(Field::parse_named, Token![,])?;
58        for field in named {
59            fields.push(field);
60        }
61        Ok(fields)
62    })
63}
64
65pub fn meta_list_to_expr(list: &syn::MetaList) -> Result<Vec<Expr>> {
66    list.parse_args_with(|stream: ParseStream| -> Result<Vec<Expr>> {
67        let mut exprs = vec![];
68        while !stream.is_empty() {
69            let field: Expr = stream.parse()?;
70            exprs.push(field);
71            if !stream.is_empty() {
72                stream.parse::<Token![,]>()?;
73            }
74        }
75        Ok(exprs)
76    })
77}
78
79pub fn get_unname_field_ident(index: usize) -> Ident {
80    format_ident!("unnamed_{}", index)
81}
82
83pub fn is_new_type(fields: &syn::Fields) -> bool {
84    if let syn::Fields::Unnamed(fields) = fields {
85        if fields.unnamed.len() == 1 {
86            return true;
87        }
88    }
89    false
90}
91
92pub fn get_index_lit(index: usize) -> LitInt {
93    LitInt::new(&index.to_string(), Span::call_site())
94}
95
96pub fn impl_generics_join_trait(impl_generics: ImplGenerics, ty: &str) -> Result<TokenStream> {
97    let mut generics_token = impl_generics.into_token_stream();
98    if !generics_token.is_empty() {
99        let generics_token_str = generics_token.to_string();
100        let mut generics_token_str = generics_token_str.trim().to_string();
101        generics_token_str.remove(0);
102        generics_token_str.remove(generics_token_str.len() - 1);
103        let mut split_generics: Vec<String> = generics_token_str
104            .split(',')
105            .map(|t| t.to_string())
106            .collect();
107        for item_ty in split_generics.iter_mut() {
108            if item_ty.contains('\'') {
109                continue;
110            }
111            if item_ty.contains(':') {
112                item_ty.push_str(" + ");
113                item_ty.push_str(ty);
114            } else {
115                item_ty.push_str(" : ");
116                item_ty.push_str(ty);
117            }
118        }
119        let mut generics_token_str = split_generics.join(",");
120        generics_token_str.insert(0, '<');
121        generics_token_str.push('>');
122        generics_token = generics_token_str.parse()?;
123    }
124    Ok(generics_token)
125}
126
127pub fn where_generics_add_constraint(
128    where_generics: Option<&WhereClause>,
129    constraints: Vec<&str>,
130) -> Result<TokenStream> {
131    let mut generics_token = where_generics.into_token_stream();
132    let mut exist_where = false;
133    let mut generics_token_str = String::default();
134    if !generics_token.is_empty() {
135        generics_token_str = generics_token.to_string();
136        generics_token_str = generics_token_str.trim().to_string();
137        if !generics_token_str.is_empty() {
138            let index = generics_token_str.find("where");
139            exist_where = index.is_some();
140        }
141    }
142    if !exist_where {
143        generics_token_str.push_str("where ");
144    } else if !generics_token_str.ends_with(',') {
145        generics_token_str.push(',');
146    }
147    for constraint in constraints {
148        generics_token_str.push_str(constraint);
149        generics_token_str.push(',');
150    }
151    generics_token = generics_token_str.parse()?;
152    Ok(quote! { #generics_token  })
153}