pin_init_internal/
util.rs1use proc_macro2::{Ident, TokenStream};
4use quote::{format_ident, ToTokens};
5use syn::{Attribute, GenericParam, Generics, Index, Member, Token};
6
7use crate::DiagCtxt;
8
9pub(crate) trait AttrListExt {
10 fn extract_cfg_attrs(&mut self) -> Vec<TokenStream>;
11
12 fn extract_single_attr(&mut self, dcx: &DiagCtxt, path: &str) -> Option<Attribute>;
16}
17
18impl AttrListExt for Vec<Attribute> {
19 fn extract_cfg_attrs(&mut self) -> Vec<TokenStream> {
20 let cfg: Vec<_> = self
21 .iter()
22 .filter(|a| a.path().is_ident("cfg"))
23 .map(|a| {
24 a.parse_args::<TokenStream>()
25 .expect("parse as token stream cannot fail")
26 })
27 .collect();
28
29 if !cfg.is_empty() {
30 self.retain(|a| !a.path().is_ident("cfg"));
31 }
32
33 cfg
34 }
35
36 fn extract_single_attr(&mut self, dcx: &DiagCtxt, path: &str) -> Option<Attribute> {
37 let attr_pos = self.iter().position(|attr| attr.path().is_ident(path))?;
39 let attr = self.remove(attr_pos);
40 self.retain(|attr| {
41 if !attr.path().is_ident(path) {
42 return true;
43 }
44
45 dcx.error(
46 attr,
47 format!("`#[{path}]` attribute specified more than once"),
48 );
49 false
50 });
51 Some(attr)
52 }
53}
54
55pub(crate) trait MemberExt {
56 fn as_ident(&self) -> Ident;
60
61 fn display_name(&self) -> String;
63}
64
65impl MemberExt for Member {
66 fn as_ident(&self) -> Ident {
67 match self {
68 Member::Named(ident) => ident.clone(),
69 Member::Unnamed(Index { index, span }) => format_ident!("_{index}", span = *span),
70 }
71 }
72
73 fn display_name(&self) -> String {
74 match self {
75 Member::Named(ident) => format!("`{ident}`"),
76 Member::Unnamed(Index { index, .. }) => format!("index `{index}`"),
77 }
78 }
79}
80
81pub(crate) struct CombinedGenerics<'a>(pub(crate) Vec<&'a Generics>);
82pub(crate) struct CombinedImplGenerics<'a>(&'a CombinedGenerics<'a>);
83pub(crate) struct CombinedTypeGenerics<'a>(&'a CombinedGenerics<'a>);
84
85impl CombinedGenerics<'_> {
86 pub(crate) fn split_for_impl(
87 &self,
88 ) -> (
89 CombinedImplGenerics<'_>,
90 CombinedTypeGenerics<'_>,
91 impl Sized,
93 ) {
94 (CombinedImplGenerics(self), CombinedTypeGenerics(self), ())
95 }
96}
97
98impl ToTokens for CombinedGenerics<'_> {
99 fn to_tokens(&self, tokens: &mut TokenStream) {
100 self.0
103 .last()
104 .and_then(|x| x.lt_token)
105 .unwrap_or_default()
106 .to_tokens(tokens);
107
108 let comma: Token![,] = Default::default();
109
110 for generics in self.0.iter() {
112 for param in generics.params.pairs() {
113 if let GenericParam::Lifetime(lt) = param.value() {
114 lt.to_tokens(tokens);
115 param.punct().unwrap_or(&&comma).to_tokens(tokens);
116 }
117 }
118 }
119
120 for generics in self.0.iter() {
121 for param in generics.params.pairs() {
122 if let GenericParam::Lifetime(_) = param.value() {
123 continue;
124 };
125 param.value().to_tokens(tokens);
126 param.punct().unwrap_or(&&comma).to_tokens(tokens);
127 }
128 }
129
130 self.0
131 .last()
132 .and_then(|x| x.gt_token)
133 .unwrap_or_default()
134 .to_tokens(tokens);
135 }
136}
137
138impl ToTokens for CombinedImplGenerics<'_> {
139 fn to_tokens(&self, tokens: &mut TokenStream) {
140 self.0
141 .0
142 .last()
143 .and_then(|x| x.lt_token)
144 .unwrap_or_default()
145 .to_tokens(tokens);
146
147 let comma: Token![,] = Default::default();
148
149 for generics in self.0 .0.iter() {
151 for param in generics.params.pairs() {
152 if let GenericParam::Lifetime(lt) = param.value() {
153 lt.to_tokens(tokens);
154 param.punct().unwrap_or(&&comma).to_tokens(tokens);
155 }
156 }
157 }
158
159 for generics in self.0 .0.iter() {
160 for param in generics.params.pairs() {
161 match param.value() {
163 GenericParam::Lifetime(_) => continue,
164 GenericParam::Type(param) => {
165 param.ident.to_tokens(tokens);
166 if !param.bounds.is_empty() {
167 param
168 .colon_token
169 .unwrap_or_else(Default::default)
170 .to_tokens(tokens);
171 param.bounds.to_tokens(tokens);
172 }
173 }
174 GenericParam::Const(param) => {
175 param.const_token.to_tokens(tokens);
176 param.ident.to_tokens(tokens);
177 param.colon_token.to_tokens(tokens);
178 param.ty.to_tokens(tokens);
179 }
180 }
181 param.punct().unwrap_or(&&comma).to_tokens(tokens);
182 }
183 }
184
185 self.0
186 .0
187 .last()
188 .and_then(|x| x.gt_token)
189 .unwrap_or_default()
190 .to_tokens(tokens);
191 }
192}
193
194impl ToTokens for CombinedTypeGenerics<'_> {
195 fn to_tokens(&self, tokens: &mut TokenStream) {
196 self.0
197 .0
198 .last()
199 .and_then(|x| x.lt_token)
200 .unwrap_or_default()
201 .to_tokens(tokens);
202
203 let comma: Token![,] = Default::default();
204
205 for generics in self.0 .0.iter() {
207 for param in generics.params.pairs() {
208 if let GenericParam::Lifetime(lt) = param.value() {
209 lt.lifetime.to_tokens(tokens);
211 param.punct().unwrap_or(&&comma).to_tokens(tokens);
212 }
213 }
214 }
215
216 for generics in self.0 .0.iter() {
217 for param in generics.params.pairs() {
218 match param.value() {
220 GenericParam::Lifetime(_) => continue,
221 GenericParam::Type(param) => {
222 param.ident.to_tokens(tokens);
223 }
224 GenericParam::Const(param) => {
225 param.ident.to_tokens(tokens);
226 }
227 }
228 param.punct().unwrap_or(&&comma).to_tokens(tokens);
229 }
230 }
231
232 self.0
233 .0
234 .last()
235 .and_then(|x| x.gt_token)
236 .unwrap_or_default()
237 .to_tokens(tokens);
238 }
239}