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}