as_derive_utils/
gen_params_in.rs
1use syn::{
4 token::{Colon, Comma, Const, Star},
5 GenericParam, Generics,
6};
7
8use proc_macro2::TokenStream;
9use quote::{quote, ToTokens};
10
11use crate::utils::NoTokens;
12
13#[derive(Debug, Copy, Clone)]
18pub struct GenParamsIn<'a, AL = NoTokens> {
19 pub generics: &'a Generics,
20 pub in_what: InWhat,
22 pub unsized_types: bool,
24 pub with_bounds: bool,
26 skip_lifetimes: bool,
27 after_lifetimes: Option<AL>,
29 after_types: Option<AL>,
31 skip_consts: bool,
32 skip_unbounded: bool,
33}
34
35#[derive(Debug, Copy, Clone, PartialEq, Eq)]
37pub enum InWhat {
38 ImplHeader,
40 ItemDecl,
42 ItemUse,
44 DummyStruct,
47}
48
49impl<'a> GenParamsIn<'a> {
50 #[allow(dead_code)]
51 pub fn new(generics: &'a Generics, in_what: InWhat) -> Self {
52 Self {
53 generics,
54 in_what,
55 unsized_types: false,
56 with_bounds: true,
57 skip_lifetimes: false,
58 after_lifetimes: None,
59 after_types: None,
60 skip_consts: false,
61 skip_unbounded: false,
62 }
63 }
64}
65
66impl<'a, AL> GenParamsIn<'a, AL> {
67 pub fn with_after_lifetimes(
69 generics: &'a Generics,
70 in_what: InWhat,
71 after_lifetimes: AL,
72 ) -> Self {
73 Self {
74 generics,
75 in_what,
76 unsized_types: false,
77 with_bounds: true,
78 skip_lifetimes: false,
79 after_lifetimes: Some(after_lifetimes),
80 after_types: None,
81 skip_consts: false,
82 skip_unbounded: false,
83 }
84 }
85 pub fn with_after_types(generics: &'a Generics, in_what: InWhat, after_types: AL) -> Self {
87 Self {
88 generics,
89 in_what,
90 unsized_types: false,
91 with_bounds: true,
92 skip_lifetimes: false,
93 after_lifetimes: None,
94 after_types: Some(after_types),
95 skip_consts: false,
96 skip_unbounded: false,
97 }
98 }
99 pub fn set_no_bounds(&mut self) {
101 self.with_bounds = false;
102 }
103 #[allow(dead_code)]
105 pub fn set_unsized_types(&mut self) {
106 self.unsized_types = true;
107 }
108
109 pub fn skip_lifetimes(&mut self) {
110 self.skip_lifetimes = true;
111 }
112
113 pub fn skip_consts(&mut self) {
114 self.skip_consts = true;
115 }
116 pub fn skip_unbounded(&mut self) {
117 self.skip_unbounded = true;
118 self.skip_consts();
119 self.skip_lifetimes();
120 }
121
122 pub fn skips_unbounded(&self) -> bool {
123 self.skip_unbounded
124 }
125
126 pub fn outputs_bounds(&self) -> bool {
128 self.with_bounds && matches!(self.in_what, InWhat::ImplHeader | InWhat::ItemDecl)
129 }
130
131 pub fn are_types_unsized(&self) -> bool {
133 self.unsized_types && matches!(self.in_what, InWhat::ItemDecl | InWhat::ImplHeader)
134 }
135}
136
137impl<'a, AL> ToTokens for GenParamsIn<'a, AL>
138where
139 AL: ToTokens,
140{
141 fn to_tokens(&self, ts: &mut TokenStream) {
142 let with_bounds = self.outputs_bounds();
143
144 let with_default = self.in_what == InWhat::ItemDecl;
145
146 let in_dummy_struct = self.in_what == InWhat::DummyStruct;
147
148 let unsized_types = self.are_types_unsized();
149
150 let mut iter = self.generics.params.iter().peekable();
151
152 let comma = Comma::default();
153 let brace = syn::token::Brace::default();
154
155 if self.skip_lifetimes {
156 while let Some(GenericParam::Lifetime { .. }) = iter.peek() {
157 iter.next();
158 }
159 } else {
160 while let Some(GenericParam::Lifetime(gen)) = iter.peek() {
161 iter.next();
162
163 if in_dummy_struct {
164 syn::token::And::default().to_tokens(ts);
165 gen.lifetime.to_tokens(ts);
166 syn::token::Paren::default().surround(ts, |_| ());
167 } else {
168 gen.lifetime.to_tokens(ts);
169 if with_bounds {
170 gen.colon_token.to_tokens(ts);
171 gen.bounds.to_tokens(ts);
172 }
173 }
174
175 comma.to_tokens(ts);
176 }
177 }
178
179 self.after_lifetimes.to_tokens(ts);
180
181 while let Some(GenericParam::Type(gen)) = iter.peek() {
182 iter.next();
183 if gen.bounds.is_empty() && self.skip_unbounded {
184 continue;
185 }
186
187 if in_dummy_struct {
188 Star::default().to_tokens(ts);
189 Const::default().to_tokens(ts);
190 }
191 gen.ident.to_tokens(ts);
192
193 if (with_bounds && gen.colon_token.is_some()) || unsized_types {
194 Colon::default().to_tokens(ts);
195 if unsized_types {
196 quote!(?Sized+).to_tokens(ts);
197 }
198 if with_bounds {
199 gen.bounds.to_tokens(ts);
200 }
201 }
202
203 if with_default {
204 gen.eq_token.to_tokens(ts);
205 gen.default.to_tokens(ts);
206 }
207
208 comma.to_tokens(ts);
209 }
210
211 self.after_types.to_tokens(ts);
212
213 if !in_dummy_struct && !self.skip_consts {
214 while let Some(GenericParam::Const(gen)) = iter.peek() {
215 iter.next();
216
217 if self.in_what != InWhat::ItemUse {
218 gen.const_token.to_tokens(ts);
219 }
220 if self.in_what == InWhat::ItemUse {
221 brace.surround(ts, |ts| {
226 gen.ident.to_tokens(ts);
227 });
228 } else {
229 gen.ident.to_tokens(ts);
230 }
231 if self.in_what != InWhat::ItemUse {
232 Colon::default().to_tokens(ts);
233 gen.ty.to_tokens(ts);
234 }
235 if with_default {
236 gen.eq_token.to_tokens(ts);
237 gen.default.to_tokens(ts);
238 }
239
240 comma.to_tokens(ts);
241 }
242 }
243 }
244}