1use syn::Item;
20
21pub trait ItemExt {
38 fn is_struct(&self) -> bool;
40 fn is_enum(&self) -> bool;
42 fn is_union(&self) -> bool;
44 fn is_fn(&self) -> bool;
46 fn is_trait(&self) -> bool;
48 fn is_impl(&self) -> bool;
50 fn is_mod(&self) -> bool;
52 fn is_type(&self) -> bool;
54 fn is_const(&self) -> bool;
56 fn is_static(&self) -> bool;
58 fn is_use(&self) -> bool;
60 fn as_struct(&self) -> Option<&syn::ItemStruct>;
62 fn as_enum(&self) -> Option<&syn::ItemEnum>;
64 fn as_union(&self) -> Option<&syn::ItemUnion>;
66 fn as_fn(&self) -> Option<&syn::ItemFn>;
68 fn as_trait(&self) -> Option<&syn::ItemTrait>;
70 fn as_impl(&self) -> Option<&syn::ItemImpl>;
72 fn as_mod(&self) -> Option<&syn::ItemMod>;
74 fn as_type(&self) -> Option<&syn::ItemType>;
76 fn as_const(&self) -> Option<&syn::ItemConst>;
78 fn as_static(&self) -> Option<&syn::ItemStatic>;
80 fn as_use(&self) -> Option<&syn::ItemUse>;
82 fn attrs(&self) -> &[syn::Attribute];
84 fn ident(&self) -> Option<&syn::Ident>;
87 fn generics(&self) -> Option<&syn::Generics>;
90 fn vis(&self) -> Option<&syn::Visibility>;
93 fn span(&self) -> proc_macro2::Span;
95}
96
97impl ItemExt for Item {
98 fn is_struct(&self) -> bool {
99 matches!(self, Self::Struct(_))
100 }
101
102 fn is_enum(&self) -> bool {
103 matches!(self, Self::Enum(_))
104 }
105
106 fn is_union(&self) -> bool {
107 matches!(self, Self::Union(_))
108 }
109
110 fn is_fn(&self) -> bool {
111 matches!(self, Self::Fn(_))
112 }
113
114 fn is_trait(&self) -> bool {
115 matches!(self, Self::Trait(_))
116 }
117
118 fn is_impl(&self) -> bool {
119 matches!(self, Self::Impl(_))
120 }
121
122 fn is_mod(&self) -> bool {
123 matches!(self, Self::Mod(_))
124 }
125
126 fn is_type(&self) -> bool {
127 matches!(self, Self::Type(_))
128 }
129
130 fn is_const(&self) -> bool {
131 matches!(self, Self::Const(_))
132 }
133
134 fn is_static(&self) -> bool {
135 matches!(self, Self::Static(_))
136 }
137
138 fn is_use(&self) -> bool {
139 matches!(self, Self::Use(_))
140 }
141
142 fn as_struct(&self) -> Option<&syn::ItemStruct> {
143 match self {
144 Self::Struct(v) => Some(v),
145 _ => None,
146 }
147 }
148
149 fn as_enum(&self) -> Option<&syn::ItemEnum> {
150 match self {
151 Self::Enum(v) => Some(v),
152 _ => None,
153 }
154 }
155
156 fn as_union(&self) -> Option<&syn::ItemUnion> {
157 match self {
158 Self::Union(v) => Some(v),
159 _ => None,
160 }
161 }
162
163 fn as_fn(&self) -> Option<&syn::ItemFn> {
164 match self {
165 Self::Fn(v) => Some(v),
166 _ => None,
167 }
168 }
169
170 fn as_trait(&self) -> Option<&syn::ItemTrait> {
171 match self {
172 Self::Trait(v) => Some(v),
173 _ => None,
174 }
175 }
176
177 fn as_impl(&self) -> Option<&syn::ItemImpl> {
178 match self {
179 Self::Impl(v) => Some(v),
180 _ => None,
181 }
182 }
183
184 fn as_mod(&self) -> Option<&syn::ItemMod> {
185 match self {
186 Self::Mod(v) => Some(v),
187 _ => None,
188 }
189 }
190
191 fn as_type(&self) -> Option<&syn::ItemType> {
192 match self {
193 Self::Type(v) => Some(v),
194 _ => None,
195 }
196 }
197
198 fn as_const(&self) -> Option<&syn::ItemConst> {
199 match self {
200 Self::Const(v) => Some(v),
201 _ => None,
202 }
203 }
204
205 fn as_static(&self) -> Option<&syn::ItemStatic> {
206 match self {
207 Self::Static(v) => Some(v),
208 _ => None,
209 }
210 }
211
212 fn as_use(&self) -> Option<&syn::ItemUse> {
213 match self {
214 Self::Use(v) => Some(v),
215 _ => None,
216 }
217 }
218
219 fn attrs(&self) -> &[syn::Attribute] {
220 match self {
221 Self::Const(v) => &v.attrs,
222 Self::Enum(v) => &v.attrs,
223 Self::ExternCrate(v) => &v.attrs,
224 Self::Fn(v) => &v.attrs,
225 Self::ForeignMod(v) => &v.attrs,
226 Self::Impl(v) => &v.attrs,
227 Self::Mod(v) => &v.attrs,
228 Self::Static(v) => &v.attrs,
229 Self::Struct(v) => &v.attrs,
230 Self::Trait(v) => &v.attrs,
231 Self::Type(v) => &v.attrs,
232 Self::Union(v) => &v.attrs,
233 Self::Use(v) => &v.attrs,
234 _ => &[],
235 }
236 }
237
238 fn ident(&self) -> Option<&syn::Ident> {
239 match self {
240 Self::Const(v) => Some(&v.ident),
241 Self::Enum(v) => Some(&v.ident),
242 Self::ExternCrate(v) => Some(&v.ident),
243 Self::Fn(v) => Some(&v.sig.ident),
244 Self::Mod(v) => Some(&v.ident),
245 Self::Static(v) => Some(&v.ident),
246 Self::Struct(v) => Some(&v.ident),
247 Self::Trait(v) => Some(&v.ident),
248 Self::Type(v) => Some(&v.ident),
249 Self::Union(v) => Some(&v.ident),
250 _ => None,
251 }
252 }
253
254 fn generics(&self) -> Option<&syn::Generics> {
255 match self {
256 Self::Enum(v) => Some(&v.generics),
257 Self::Fn(v) => Some(&v.sig.generics),
258 Self::Impl(v) => Some(&v.generics),
259 Self::Struct(v) => Some(&v.generics),
260 Self::Trait(v) => Some(&v.generics),
261 Self::Type(v) => Some(&v.generics),
262 Self::Union(v) => Some(&v.generics),
263 _ => None,
264 }
265 }
266
267 fn vis(&self) -> Option<&syn::Visibility> {
268 match self {
269 Self::Const(v) => Some(&v.vis),
270 Self::Enum(v) => Some(&v.vis),
271 Self::ExternCrate(v) => Some(&v.vis),
272 Self::Fn(v) => Some(&v.vis),
273 Self::Mod(v) => Some(&v.vis),
274 Self::Static(v) => Some(&v.vis),
275 Self::Struct(v) => Some(&v.vis),
276 Self::Trait(v) => Some(&v.vis),
277 Self::Type(v) => Some(&v.vis),
278 Self::Union(v) => Some(&v.vis),
279 Self::Use(v) => Some(&v.vis),
280 _ => None,
281 }
282 }
283
284 fn span(&self) -> proc_macro2::Span {
285 use syn::spanned::Spanned;
286 Spanned::span(self)
287 }
288}
289
290#[cfg(test)]
291mod tests {
292 use super::*;
293
294 fn item_from(input: &str) -> Item {
295 syn::parse_str(input).unwrap()
296 }
297
298 mod predicates {
299 use super::*;
300
301 #[test]
302 fn struct_variant() {
303 let item = item_from("struct Foo;");
304 assert!(item.is_struct());
305 assert!(!item.is_enum());
306 assert!(!item.is_fn());
307 }
308
309 #[test]
310 fn enum_variant() {
311 let item = item_from("enum Foo { A, B }");
312 assert!(item.is_enum());
313 assert!(!item.is_struct());
314 }
315
316 #[test]
317 fn fn_variant() {
318 let item = item_from("fn foo() {}");
319 assert!(item.is_fn());
320 assert!(!item.is_struct());
321 }
322
323 #[test]
324 fn impl_variant() {
325 let item = item_from("impl Foo {}");
326 assert!(item.is_impl());
327 }
328
329 #[test]
330 fn trait_variant() {
331 let item = item_from("trait Foo {}");
332 assert!(item.is_trait());
333 }
334
335 #[test]
336 fn mod_variant() {
337 let item = item_from("mod foo {}");
338 assert!(item.is_mod());
339 }
340
341 #[test]
342 fn type_variant() {
343 let item = item_from("type Foo = Bar;");
344 assert!(item.is_type());
345 }
346
347 #[test]
348 fn const_variant() {
349 let item = item_from("const X: i32 = 0;");
350 assert!(item.is_const());
351 }
352
353 #[test]
354 fn static_variant() {
355 let item = item_from("static X: i32 = 0;");
356 assert!(item.is_static());
357 }
358
359 #[test]
360 fn use_variant() {
361 let item = item_from("use std::fmt;");
362 assert!(item.is_use());
363 }
364 }
365
366 mod conversions {
367 use super::*;
368
369 #[test]
370 fn as_struct_some() {
371 let item = item_from("struct Foo;");
372 assert!(item.as_struct().is_some());
373 }
374
375 #[test]
376 fn as_struct_none() {
377 let item = item_from("enum Foo { A }");
378 assert!(item.as_struct().is_none());
379 }
380
381 #[test]
382 fn as_enum_some() {
383 let item = item_from("enum Foo { A }");
384 assert!(item.as_enum().is_some());
385 }
386
387 #[test]
388 fn as_fn_some() {
389 let item = item_from("fn foo() {}");
390 assert!(item.as_fn().is_some());
391 }
392
393 #[test]
394 fn as_impl_some() {
395 let item = item_from("impl Foo {}");
396 assert!(item.as_impl().is_some());
397 }
398 }
399
400 mod accessors {
401 use super::*;
402
403 #[test]
404 fn attrs_on_struct() {
405 let item = item_from("#[derive(Clone)] struct Foo;");
406 assert_eq!(item.attrs().len(), 1);
407 }
408
409 #[test]
410 fn attrs_on_fn() {
411 let item = item_from("#[inline] fn foo() {}");
412 assert_eq!(item.attrs().len(), 1);
413 }
414
415 #[test]
416 fn ident_on_struct() {
417 let item = item_from("struct Foo;");
418 assert_eq!(item.ident().unwrap().to_string(), "Foo");
419 }
420
421 #[test]
422 fn ident_on_fn() {
423 let item = item_from("fn bar() {}");
424 assert_eq!(item.ident().unwrap().to_string(), "bar");
425 }
426
427 #[test]
428 fn ident_on_impl_is_none() {
429 let item = item_from("impl Foo {}");
430 assert!(item.ident().is_none());
431 }
432
433 #[test]
434 fn generics_on_struct() {
435 let item = item_from("struct Foo<T> { x: T }");
436 assert!(item.generics().is_some());
437 }
438
439 #[test]
440 fn generics_on_const_is_none() {
441 let item = item_from("const X: i32 = 0;");
442 assert!(item.generics().is_none());
443 }
444
445 #[test]
446 fn vis_on_pub_struct() {
447 let item = item_from("pub struct Foo;");
448 let vis = item.vis().unwrap();
449 assert!(matches!(vis, syn::Visibility::Public(_)));
450 }
451
452 #[test]
453 fn vis_on_impl_is_none() {
454 let item = item_from("impl Foo {}");
455 assert!(item.vis().is_none());
456 }
457 }
458}