1use proc_macro2::TokenStream;
9use quote::{ToTokens, TokenStreamExt, quote};
10use syn::parse::{Parse, ParseStream, Result};
11use syn::punctuated::{Pair, Punctuated};
12use syn::token;
13use syn::{Attribute, ConstParam, LifetimeParam, PredicateLifetime};
14use syn::{BoundLifetimes, Ident, Lifetime, Token, Type};
15
16#[derive(Debug)]
21pub struct Generics {
22 pub lt_token: Option<Token![<]>,
24 pub params: Punctuated<GenericParam, Token![,]>,
26 pub gt_token: Option<Token![>]>,
28 pub where_clause: Option<WhereClause>,
30}
31
32impl Default for Generics {
33 fn default() -> Self {
34 Generics {
35 lt_token: None,
36 params: Punctuated::new(),
37 gt_token: None,
38 where_clause: None,
39 }
40 }
41}
42
43#[derive(Debug)]
48#[allow(clippy::large_enum_variant)]
49pub enum GenericParam {
50 Type(TypeParam),
52 Lifetime(LifetimeParam),
54 Const(ConstParam),
56}
57
58#[derive(Debug)]
63pub struct TypeParam {
64 pub attrs: Vec<Attribute>,
66 pub ident: Ident,
68 pub colon_token: Option<Token![:]>,
70 pub bounds: Punctuated<TypeParamBound, Token![+]>,
72 pub default: Option<(Token![=], Type)>,
74}
75
76#[derive(Debug)]
80pub enum TypeParamBound {
81 TraitSubst(Token![trait]),
83 Other(syn::TypeParamBound),
85}
86
87#[derive(Debug)]
92pub struct WhereClause {
93 pub where_token: Token![where],
95 pub predicates: Punctuated<WherePredicate, Token![,]>,
97}
98
99#[allow(clippy::large_enum_variant)]
104#[derive(Debug)]
105pub enum WherePredicate {
106 Type(PredicateType),
108
109 Lifetime(PredicateLifetime),
111}
112
113#[derive(Debug)]
118pub struct PredicateType {
119 pub lifetimes: Option<BoundLifetimes>,
121 pub bounded_ty: Type,
123 pub colon_token: Token![:],
125 pub bounds: Punctuated<TypeParamBound, Token![+]>,
127}
128
129mod parsing {
130 use super::*;
131 use syn::ext::IdentExt;
132
133 impl Parse for Generics {
134 fn parse(input: ParseStream) -> Result<Self> {
135 if !input.peek(Token![<]) {
136 return Ok(Generics::default());
137 }
138
139 let lt_token: Token![<] = input.parse()?;
140
141 let mut params = Punctuated::new();
142 loop {
143 if input.peek(Token![>]) {
144 break;
145 }
146
147 let attrs = input.call(Attribute::parse_outer)?;
148 let lookahead = input.lookahead1();
149 if lookahead.peek(Lifetime) {
150 params.push_value(GenericParam::Lifetime(LifetimeParam {
151 attrs,
152 ..input.parse()?
153 }));
154 } else if lookahead.peek(Ident) {
155 params.push_value(GenericParam::Type(TypeParam {
156 attrs,
157 ..input.parse()?
158 }));
159 } else if lookahead.peek(Token![const]) {
160 params.push_value(GenericParam::Const(ConstParam {
161 attrs,
162 ..input.parse()?
163 }));
164 } else if input.peek(Token![_]) {
165 params.push_value(GenericParam::Type(TypeParam {
166 attrs,
167 ident: input.call(Ident::parse_any)?,
168 colon_token: None,
169 bounds: Punctuated::new(),
170 default: None,
171 }));
172 } else {
173 return Err(lookahead.error());
174 }
175
176 if input.peek(Token![>]) {
177 break;
178 }
179 let punct = input.parse()?;
180 params.push_punct(punct);
181 }
182
183 let gt_token: Token![>] = input.parse()?;
184
185 Ok(Generics {
186 lt_token: Some(lt_token),
187 params,
188 gt_token: Some(gt_token),
189 where_clause: None,
190 })
191 }
192 }
193
194 impl Parse for TypeParam {
195 fn parse(input: ParseStream) -> Result<Self> {
196 let attrs = input.call(Attribute::parse_outer)?;
197 let ident: Ident = input.parse()?;
198 let colon_token: Option<Token![:]> = input.parse()?;
199
200 let mut bounds = Punctuated::new();
201 if colon_token.is_some() {
202 loop {
203 if input.peek(Token![,]) || input.peek(Token![>]) || input.peek(Token![=]) {
204 break;
205 }
206 let value: TypeParamBound = input.parse()?;
207 bounds.push_value(value);
208 if !input.peek(Token![+]) {
209 break;
210 }
211 let punct: Token![+] = input.parse()?;
212 bounds.push_punct(punct);
213 }
214 }
215
216 let eq_token: Option<Token![=]> = input.parse()?;
217 let default = if let Some(tok) = eq_token {
218 Some((tok, input.parse::<Type>()?))
219 } else {
220 None
221 };
222
223 Ok(TypeParam {
224 attrs,
225 ident,
226 colon_token,
227 bounds,
228 default,
229 })
230 }
231 }
232
233 impl Parse for TypeParamBound {
234 fn parse(input: ParseStream) -> Result<Self> {
235 if input.peek(Token![trait]) {
236 input.parse().map(TypeParamBound::TraitSubst)
237 } else {
238 syn::TypeParamBound::parse(input).map(TypeParamBound::Other)
239 }
240 }
241 }
242
243 impl Parse for WhereClause {
244 fn parse(input: ParseStream) -> Result<Self> {
245 Ok(WhereClause {
246 where_token: input.parse()?,
247 predicates: {
248 let mut predicates = Punctuated::new();
249 loop {
250 if input.is_empty()
251 || input.peek(token::Brace)
252 || input.peek(Token![,])
253 || input.peek(Token![;])
254 || input.peek(Token![:]) && !input.peek(Token![::])
255 || input.peek(Token![=])
256 {
257 break;
258 }
259 let value = input.parse()?;
260 predicates.push_value(value);
261 if !input.peek(Token![,]) {
262 break;
263 }
264 let punct = input.parse()?;
265 predicates.push_punct(punct);
266 }
267 predicates
268 },
269 })
270 }
271 }
272
273 impl Parse for WherePredicate {
274 fn parse(input: ParseStream) -> Result<Self> {
275 if input.peek(Lifetime) && input.peek2(Token![:]) {
276 Ok(WherePredicate::Lifetime(PredicateLifetime {
277 attrs: vec![],
278 lifetime: input.parse()?,
279 colon_token: input.parse()?,
280 bounds: {
281 let mut bounds = Punctuated::new();
282 loop {
283 if input.is_empty()
284 || input.peek(token::Brace)
285 || input.peek(Token![,])
286 || input.peek(Token![;])
287 || input.peek(Token![:])
288 || input.peek(Token![=])
289 {
290 break;
291 }
292 let value = input.parse()?;
293 bounds.push_value(value);
294 if !input.peek(Token![+]) {
295 break;
296 }
297 let punct = input.parse()?;
298 bounds.push_punct(punct);
299 }
300 bounds
301 },
302 }))
303 } else {
304 Ok(WherePredicate::Type(PredicateType {
305 lifetimes: input.parse()?,
306 bounded_ty: input.parse()?,
307 colon_token: input.parse()?,
308 bounds: {
309 let mut bounds = Punctuated::new();
310 loop {
311 if input.is_empty()
312 || input.peek(token::Brace)
313 || input.peek(Token![,])
314 || input.peek(Token![;])
315 || input.peek(Token![:]) && !input.peek(Token![::])
316 || input.peek(Token![=])
317 {
318 break;
319 }
320 let value = input.parse()?;
321 bounds.push_value(value);
322 if !input.peek(Token![+]) {
323 break;
324 }
325 let punct = input.parse()?;
326 bounds.push_punct(punct);
327 }
328 bounds
329 },
330 }))
331 }
332 }
333 }
334}
335
336pub trait ToTokensSubst {
341 fn to_tokens_subst(&self, tokens: &mut TokenStream, subst: &TokenStream);
343}
344
345mod printing_subst {
346 use super::*;
347 use syn::AttrStyle;
348
349 impl ToTokensSubst for Generics {
350 fn to_tokens_subst(&self, tokens: &mut TokenStream, subst: &TokenStream) {
351 if self.params.is_empty() {
352 return;
353 }
354
355 self.lt_token.unwrap_or_default().to_tokens(tokens);
356
357 let mut trailing_or_empty = true;
358 for pair in self.params.pairs() {
359 if let GenericParam::Lifetime(param) = *pair.value() {
360 param.to_tokens(tokens);
361 pair.punct().to_tokens(tokens);
362 trailing_or_empty = pair.punct().is_some();
363 }
364 }
365 for pair in self.params.pairs() {
366 match *pair.value() {
367 GenericParam::Type(param) => {
368 if !trailing_or_empty {
369 <Token![,]>::default().to_tokens(tokens);
370 trailing_or_empty = true;
371 }
372 param.to_tokens_subst(tokens, subst);
373 pair.punct().to_tokens(tokens);
374 }
375 GenericParam::Const(param) => {
376 if !trailing_or_empty {
377 <Token![,]>::default().to_tokens(tokens);
378 trailing_or_empty = true;
379 }
380 param.to_tokens(tokens);
381 pair.punct().to_tokens(tokens);
382 }
383 GenericParam::Lifetime(_) => {}
384 }
385 }
386
387 self.gt_token.unwrap_or_default().to_tokens(tokens);
388 }
389 }
390
391 impl ToTokensSubst for TypeParam {
392 fn to_tokens_subst(&self, tokens: &mut TokenStream, subst: &TokenStream) {
393 tokens.append_all(
394 self.attrs
395 .iter()
396 .filter(|attr| matches!(attr.style, AttrStyle::Outer)),
397 );
398 self.ident.to_tokens(tokens);
399 if !self.bounds.is_empty() {
400 self.colon_token.unwrap_or_default().to_tokens(tokens);
401 self.bounds.to_tokens_subst(tokens, subst);
402 }
403 if let Some((tok, default)) = &self.default {
404 tok.to_tokens(tokens);
405 default.to_tokens(tokens);
406 }
407 }
408 }
409
410 impl ToTokensSubst for WhereClause {
411 fn to_tokens_subst(&self, tokens: &mut TokenStream, subst: &TokenStream) {
412 if !self.predicates.is_empty() {
413 self.where_token.to_tokens(tokens);
414 self.predicates.to_tokens_subst(tokens, subst);
415 }
416 }
417 }
418
419 impl<T, P> ToTokensSubst for Punctuated<T, P>
420 where
421 T: ToTokensSubst,
422 P: ToTokens,
423 {
424 fn to_tokens_subst(&self, tokens: &mut TokenStream, subst: &TokenStream) {
425 for pair in self.pairs() {
426 pair.value().to_tokens_subst(tokens, subst);
427 if let Some(punct) = pair.punct() {
428 punct.to_tokens(tokens);
429 }
430 }
431 }
432 }
433
434 impl ToTokensSubst for WherePredicate {
435 fn to_tokens_subst(&self, tokens: &mut TokenStream, subst: &TokenStream) {
436 match self {
437 WherePredicate::Type(ty) => ty.to_tokens_subst(tokens, subst),
438 WherePredicate::Lifetime(lt) => lt.to_tokens(tokens),
439 }
440 }
441 }
442
443 impl ToTokensSubst for PredicateType {
444 fn to_tokens_subst(&self, tokens: &mut TokenStream, subst: &TokenStream) {
445 self.lifetimes.to_tokens(tokens);
446 self.bounded_ty.to_tokens(tokens);
447 self.colon_token.to_tokens(tokens);
448 self.bounds.to_tokens_subst(tokens, subst);
449 }
450 }
451
452 impl ToTokensSubst for TypeParamBound {
453 fn to_tokens_subst(&self, tokens: &mut TokenStream, subst: &TokenStream) {
454 match self {
455 TypeParamBound::TraitSubst(_) => tokens.append_all(quote! { #subst }),
456 TypeParamBound::Other(bound) => bound.to_tokens(tokens),
457 }
458 }
459 }
460}
461
462fn map_type_param_bound(bound: &syn::TypeParamBound) -> TypeParamBound {
463 TypeParamBound::Other(bound.clone())
464}
465
466fn map_generic_param(param: &syn::GenericParam) -> GenericParam {
467 match param {
468 syn::GenericParam::Type(ty) => GenericParam::Type(TypeParam {
469 attrs: ty.attrs.clone(),
470 ident: ty.ident.clone(),
471 colon_token: ty.colon_token,
472 bounds: Punctuated::from_iter(
473 ty.bounds
474 .pairs()
475 .map(|pair| map_pair(pair, map_type_param_bound)),
476 ),
477 default: ty.default.clone(),
478 }),
479 syn::GenericParam::Lifetime(lt) => GenericParam::Lifetime(lt.clone()),
480 syn::GenericParam::Const(c) => GenericParam::Const(c.clone()),
481 }
482}
483
484fn map_pair<U, V, P: Clone, F: Fn(U) -> V>(pair: Pair<U, &P>, f: F) -> Pair<V, P> {
485 match pair {
486 Pair::Punctuated(value, punct) => Pair::Punctuated(f(value), punct.clone()),
487 Pair::End(value) => Pair::End(f(value)),
488 }
489}
490
491impl Generics {
492 pub fn impl_generics(
503 mut self,
504 item_generics: &syn::Generics,
505 subst: &TokenStream,
506 ) -> (TokenStream, TokenStream) {
507 let mut impl_generics = quote! {};
508 if self.params.is_empty() {
509 item_generics.to_tokens(&mut impl_generics);
510 } else {
511 if !self.params.empty_or_trailing() {
512 self.params.push_punct(Default::default());
513 }
514 self.params.extend(
515 item_generics
516 .params
517 .pairs()
518 .map(|pair| map_pair(pair, map_generic_param)),
519 );
520 self.to_tokens_subst(&mut impl_generics, subst);
521 }
522
523 let where_clause = clause_to_toks(
524 &self.where_clause,
525 item_generics.where_clause.as_ref(),
526 subst,
527 );
528 (impl_generics, where_clause)
529 }
530 pub fn ty_generics(&self, item_generics: &syn::Generics) -> TokenStream {
537 let mut toks = TokenStream::new();
538 let tokens = &mut toks;
539
540 if self.params.is_empty() {
541 let (_, ty_generics, _) = item_generics.split_for_impl();
542 ty_generics.to_tokens(tokens);
543 return toks;
544 }
545
546 self.lt_token.unwrap_or_default().to_tokens(tokens);
547
548 for (def, punct) in self
550 .params
551 .pairs()
552 .filter_map(|param| {
553 if let GenericParam::Lifetime(def) = *param.value() {
554 Some((def, param.punct().map(|p| **p).unwrap_or_default()))
555 } else {
556 None
557 }
558 })
559 .chain(item_generics.params.pairs().filter_map(|param| {
560 if let syn::GenericParam::Lifetime(def) = *param.value() {
561 Some((def, param.punct().map(|p| **p).unwrap_or_default()))
562 } else {
563 None
564 }
565 }))
566 {
567 def.lifetime.to_tokens(tokens);
569 punct.to_tokens(tokens);
570 }
571
572 for param in self.params.pairs() {
573 match *param.value() {
574 GenericParam::Lifetime(_) => continue,
575 GenericParam::Type(param) => {
576 param.ident.to_tokens(tokens);
578 }
579 GenericParam::Const(param) => {
580 param.ident.to_tokens(tokens);
582 }
583 }
584 param
585 .punct()
586 .map(|p| **p)
587 .unwrap_or_default()
588 .to_tokens(tokens);
589 }
590 for param in item_generics.params.pairs() {
591 match *param.value() {
592 syn::GenericParam::Lifetime(_) => continue,
593 syn::GenericParam::Type(param) => {
594 param.ident.to_tokens(tokens);
596 }
597 syn::GenericParam::Const(param) => {
598 param.ident.to_tokens(tokens);
600 }
601 }
602 param
603 .punct()
604 .map(|p| **p)
605 .unwrap_or_default()
606 .to_tokens(tokens);
607 }
608
609 self.gt_token.unwrap_or_default().to_tokens(tokens);
610
611 toks
612 }
613}
614
615pub fn clause_to_toks(
620 wc: &Option<WhereClause>,
621 item_wc: Option<&syn::WhereClause>,
622 subst: &TokenStream,
623) -> TokenStream {
624 match (wc, item_wc) {
625 (None, None) => quote! {},
626 (Some(wc), None) => {
627 let mut toks = quote! {};
628 wc.to_tokens_subst(&mut toks, subst);
629 toks
630 }
631 (None, Some(wc)) => quote! { #wc },
632 (Some(wc), Some(item_wc)) => {
633 let mut toks = quote! { #item_wc };
634 if !item_wc.predicates.empty_or_trailing() {
635 toks.append_all(quote! { , });
636 }
637 wc.predicates.to_tokens_subst(&mut toks, subst);
638 toks
639 }
640 }
641}