-
Notifications
You must be signed in to change notification settings - Fork 50
/
util.rs
127 lines (112 loc) · 3.46 KB
/
util.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use quote::ToTokens;
use syn::{parse::Parser, Error};
pub fn path_to_single_string(path: &syn::Path) -> Option<String> {
if path.leading_colon.is_some() {
return None;
}
let mut it = path.segments.iter();
let segment = it.next()?;
if it.next().is_some() {
// Multipart path
return None;
}
if segment.arguments != syn::PathArguments::None {
return None;
}
Some(segment.ident.to_string())
}
pub fn expr_to_single_string(expr: &syn::Expr) -> Option<String> {
if let syn::Expr::Path(path) = expr {
path_to_single_string(&path.path)
} else {
None
}
}
pub fn ident_to_type(ident: syn::Ident) -> syn::Type {
let mut path = syn::Path {
leading_colon: None,
segments: Default::default(),
};
path.segments.push(syn::PathSegment {
ident,
arguments: Default::default(),
});
syn::Type::Path(syn::TypePath { qself: None, path })
}
pub fn empty_type() -> syn::Type {
syn::TypeTuple {
paren_token: Default::default(),
elems: Default::default(),
}
.into()
}
pub fn type_tuple(elems: impl Iterator<Item = syn::Type>) -> syn::TypeTuple {
let mut result = syn::TypeTuple {
paren_token: Default::default(),
elems: elems.collect(),
};
if !result.elems.empty_or_trailing() {
result.elems.push_punct(Default::default());
}
result
}
pub fn empty_type_tuple() -> syn::TypeTuple {
syn::TypeTuple {
paren_token: Default::default(),
elems: Default::default(),
}
}
pub fn modify_types_generics_hack<F>(ty_generics: &syn::TypeGenerics, mut mutator: F) -> syn::AngleBracketedGenericArguments
where
F: FnMut(&mut syn::punctuated::Punctuated<syn::GenericArgument, syn::token::Comma>),
{
let mut abga: syn::AngleBracketedGenericArguments =
syn::parse2(ty_generics.to_token_stream()).unwrap_or_else(|_| syn::AngleBracketedGenericArguments {
colon2_token: None,
lt_token: Default::default(),
args: Default::default(),
gt_token: Default::default(),
});
mutator(&mut abga.args);
abga
}
pub fn strip_raw_ident_prefix(mut name: String) -> String {
if name.starts_with("r#") {
name.replace_range(0..2, "");
}
name
}
pub fn first_visibility(visibilities: &[Option<&syn::Visibility>]) -> proc_macro2::TokenStream {
let vis = visibilities
.iter()
.flatten()
.next()
.expect("need at least one visibility in the list");
vis.to_token_stream()
}
pub fn public_visibility() -> syn::Visibility {
syn::Visibility::Public(syn::token::Pub::default())
}
pub fn apply_subsections(
list: &syn::MetaList,
mut applier: impl FnMut(syn::Expr) -> Result<(), syn::Error>,
) -> Result<(), syn::Error> {
if list.tokens.is_empty() {
return Err(syn::Error::new_spanned(list, "Expected builder(…)"));
}
let parser = syn::punctuated::Punctuated::<_, syn::token::Comma>::parse_terminated;
let exprs = parser.parse2(list.tokens.clone())?;
for expr in exprs {
applier(expr)?;
}
Ok(())
}
pub fn expr_to_lit_string(expr: &syn::Expr) -> Result<String, Error> {
match expr {
syn::Expr::Lit(lit) => match &lit.lit {
syn::Lit::Str(str) => Ok(str.value()),
_ => Err(Error::new_spanned(expr, "attribute only allows str values")),
},
_ => Err(Error::new_spanned(expr, "attribute only allows str values")),
}
}