macro_tools/
struct_like.rs

1//!
2//! Parse structures, like `struct { a : i32 }`.
3//!
4
5/// Define a private namespace for all its items.
6mod private
7{
8  #[ allow( clippy::wildcard_imports ) ]
9  use crate::*;
10
11  /// Enum to encapsulate either a field from a struct or a variant from an enum.
12  #[ derive( Debug, PartialEq, Clone ) ]
13  pub enum FieldOrVariant< 'a >
14  {
15    /// Represents a field within a struct or union.
16    Field( &'a syn::Field ),
17    /// Represents a variant within an enum.
18    Variant( &'a syn::Variant ),
19  }
20
21  impl Copy for FieldOrVariant< '_ >
22  {
23  }
24
25  impl< 'a > From< &'a syn::Field > for FieldOrVariant< 'a >
26  {
27    fn from( field : &'a syn::Field ) -> Self
28    {
29      FieldOrVariant::Field( field )
30    }
31  }
32
33  impl< 'a > From< &'a syn::Variant > for FieldOrVariant< 'a >
34  {
35    fn from( variant : &'a syn::Variant ) -> Self
36    {
37      FieldOrVariant::Variant( variant )
38    }
39  }
40
41  impl quote::ToTokens for FieldOrVariant< '_ >
42  {
43    fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream )
44    {
45      match self
46      {
47        FieldOrVariant::Field( item ) =>
48        {
49          item.to_tokens( tokens );
50        },
51        FieldOrVariant::Variant( item ) =>
52        {
53          item.to_tokens( tokens );
54        },
55      }
56    }
57  }
58
59  impl FieldOrVariant< '_ >
60  {
61
62    /// Returns a reference to the attributes of the item.
63    #[ must_use ]
64    pub fn attrs( &self ) -> &Vec< syn::Attribute >
65    {
66      match self
67      {
68        FieldOrVariant::Field( e ) => &e.attrs,
69        FieldOrVariant::Variant( e ) => &e.attrs,
70      }
71    }
72
73    /// Returns a reference to the visibility of the item.
74    #[ must_use ]
75    pub fn vis( &self ) -> Option< &syn::Visibility >
76    {
77      match self
78      {
79        FieldOrVariant::Field( e ) => Some( &e.vis ),
80        FieldOrVariant::Variant( _ ) => None,
81      }
82    }
83
84    /// Returns a reference to the mutability of the item.
85    #[ must_use ]
86    pub fn mutability( &self ) -> Option< &syn::FieldMutability >
87    {
88      match self
89      {
90        FieldOrVariant::Field( e ) => Some( &e.mutability ),
91        FieldOrVariant::Variant( _ ) => None,
92      }
93    }
94
95    /// Returns a reference to the identifier of the item.
96    #[ must_use]
97    pub fn ident( &self ) -> Option< &syn::Ident >
98    {
99      match self
100      {
101        FieldOrVariant::Field( e ) => e.ident.as_ref(),
102        FieldOrVariant::Variant( e ) => Some( &e.ident ),
103      }
104    }
105
106    /// Returns an iterator over elements of the item.
107    #[ must_use ]
108    pub fn typ( &self ) -> Option< &syn::Type >
109    {
110      match self
111      {
112        FieldOrVariant::Field( e ) =>
113        {
114          Some( &e.ty )
115        },
116        FieldOrVariant::Variant( _e ) =>
117        {
118          None
119        },
120      }
121    }
122
123    /// Returns a reference to the fields of the item.
124    #[ must_use ]
125    pub fn fields( &self ) -> Option< &syn::Fields >
126    {
127      match self
128      {
129        FieldOrVariant::Field( _ ) => None,
130        FieldOrVariant::Variant( e ) => Some( &e.fields ),
131      }
132    }
133
134    /// Returns a reference to the discriminant of the item.
135    #[ must_use ]
136    pub fn discriminant( &self ) -> Option< &( syn::token::Eq, syn::Expr ) >
137    {
138      match self
139      {
140        FieldOrVariant::Field( _ ) => None,
141        FieldOrVariant::Variant( e ) => e.discriminant.as_ref(),
142      }
143    }
144
145  }
146
147  /// Represents various struct-like constructs in Rust code.
148  ///
149  /// This enum enables differentiation among unit types, structs, and enums, allowing
150  /// for syntactic analysis and manipulation within macros. `StructLike` is designed to be
151  /// used in macro contexts where behaviors may vary based on the struct-like type being processed.
152  ///
153  /// Variants:
154  /// - `Unit`: Represents unit structs, which are types without any fields or data. Useful in scenarios where
155  ///   a type needs to exist but does not hold any data itself, typically used for type-safe markers.
156  /// - `Struct`: Represents regular Rust structs that contain fields. This variant is used to handle data structures
157  ///   that hold multiple related data pieces together in a named format.
158  /// - `Enum`: Represents enums in Rust, which are types that can hold one of multiple possible variants. This is particularly
159  ///   useful for type-safe state or option handling without the use of external discriminators.
160  ///
161  #[ derive( Debug, PartialEq ) ]
162  pub enum StructLike
163  {
164    /// A unit struct with no fields.
165    Unit( syn::ItemStruct ),
166    /// A typical Rust struct with named fields.
167    Struct( syn::ItemStruct ),
168    /// A Rust enum, which can be one of several defined variants.
169    Enum( syn::ItemEnum ),
170  }
171
172  impl From< syn::ItemStruct > for StructLike
173  {
174    fn from( item_struct : syn::ItemStruct ) -> Self
175    {
176      if item_struct.fields.is_empty()
177      {
178        StructLike::Unit( item_struct )
179      }
180      else
181      {
182        StructLike::Struct( item_struct )
183      }
184    }
185  }
186
187  impl From< syn::ItemEnum > for StructLike
188  {
189    fn from( item_enum : syn::ItemEnum ) -> Self
190    {
191      StructLike::Enum( item_enum )
192    }
193  }
194
195  impl syn::parse::Parse for StructLike
196  {
197    fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self >
198    {
199      use syn::{ ItemStruct, ItemEnum, Visibility, Attribute };
200
201      // Parse attributes
202      let attributes : Vec< Attribute > = input.call( Attribute::parse_outer )?;
203      // Parse visibility
204      let visibility : Visibility = input.parse().unwrap_or( syn::Visibility::Inherited );
205
206      // Fork input stream to handle struct/enum keyword without consuming
207      let lookahead = input.lookahead1();
208      if lookahead.peek( syn::Token![ struct ] )
209      {
210        // Parse ItemStruct
211        let mut item_struct : ItemStruct = input.parse()?;
212        item_struct.vis = visibility;
213        item_struct.attrs = attributes;
214        if item_struct.fields.is_empty()
215        {
216          Ok( StructLike::Unit( item_struct ) )
217        }
218        else
219        {
220          Ok( StructLike::Struct( item_struct ) )
221        }
222      }
223      else if lookahead.peek( syn::Token![ enum ] )
224      {
225        // Parse ItemEnum
226        let mut item_enum : ItemEnum = input.parse()?;
227        item_enum.vis = visibility;
228        item_enum.attrs = attributes;
229        Ok( StructLike::Enum( item_enum ) )
230      }
231      else
232      {
233        Err( lookahead.error() )
234      }
235    }
236  }
237
238  impl quote::ToTokens for StructLike
239  {
240    fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream )
241    {
242      match self
243      {
244        StructLike::Unit( item ) | StructLike::Struct( item ) =>
245        {
246          item.to_tokens( tokens );
247        },
248        StructLike::Enum( item ) =>
249        {
250          item.to_tokens( tokens );
251        },
252      }
253    }
254  }
255
256  impl StructLike
257  {
258
259
260    /// Returns an iterator over elements of the item.
261    // pub fn elements< 'a >( &'a self ) -> impl IterTrait< 'a, FieldOrVariant< 'a > > + 'a
262    pub fn elements< 'a >( &'a self ) -> BoxedIter< 'a, FieldOrVariant< 'a > >
263    {
264      match self
265      {
266        StructLike::Unit( _ ) =>
267        {
268          let empty : Vec< FieldOrVariant< 'a > > = vec![];
269          Box::new( empty.into_iter() )
270        },
271        StructLike::Struct( item ) =>
272        {
273          let fields = item.fields.iter().map( FieldOrVariant::from );
274          Box::new( fields )
275        },
276        StructLike::Enum( item ) =>
277        {
278          let variants = item.variants.iter().map( FieldOrVariant::from );
279          Box::new( variants )
280        },
281      }
282    }
283
284    /// Returns an iterator over elements of the item.
285    #[ must_use ]
286    pub fn attrs( &self ) -> &Vec< syn::Attribute >
287    {
288      match self
289      {
290        StructLike::Unit( item ) |
291        StructLike::Struct( item ) =>
292        {
293          &item.attrs
294        },
295        StructLike::Enum( item ) =>
296        {
297          &item.attrs
298        },
299      }
300    }
301
302    /// Returns an iterator over elements of the item.
303    #[ must_use ]
304    pub fn vis( &self ) -> &syn::Visibility
305    {
306      match self
307      {
308        StructLike::Unit( item ) |
309        StructLike::Struct( item ) =>
310        {
311          &item.vis
312        },
313        StructLike::Enum( item ) =>
314        {
315          &item.vis
316        },
317      }
318    }
319
320    /// Returns an iterator over elements of the item.
321    #[ must_use ]
322    pub fn ident( &self ) -> &syn::Ident
323    {
324      match self
325      {
326        StructLike::Unit( item ) |
327        StructLike::Struct( item ) =>
328        {
329          &item.ident
330        },
331        StructLike::Enum( item ) =>
332        {
333          &item.ident
334        },
335      }
336    }
337
338    /// Returns an iterator over elements of the item.
339    #[ must_use ]
340    pub fn generics( &self ) -> &syn::Generics
341    {
342      match self
343      {
344        StructLike::Unit( item ) |
345        StructLike::Struct( item ) =>
346        {
347          &item.generics
348        },
349        StructLike::Enum( item ) =>
350        {
351          &item.generics
352        },
353      }
354    }
355
356    /// Returns an iterator over fields of the item.
357    // pub fn fields< 'a >( &'a self ) -> impl IterTrait< 'a, &'a syn::Field >
358    #[ must_use ]
359    pub fn fields< 'a >( &'a self ) -> BoxedIter< 'a, &'a syn::Field >
360    {
361      let result : BoxedIter< 'a, &'a syn::Field > = match self
362      {
363        StructLike::Unit( _item ) =>
364        {
365          Box::new( core::iter::empty() )
366        },
367        StructLike::Struct( item ) =>
368        {
369          Box::new( item.fields.iter() )
370        },
371        StructLike::Enum( _item ) =>
372        {
373          Box::new( core::iter::empty() )
374        },
375      };
376      result
377    }
378
379    /// Extracts the name of each field.
380    /// # Panics
381    /// qqq: docs
382    // pub fn field_names< 'a >( &'a self ) -> Option< impl IterTrait< 'a, &'a syn::Ident > + '_ >
383    #[ must_use ]
384    pub fn field_names( &self ) -> Option< BoxedIter< '_, &syn::Ident >>
385    {
386      match self
387      {
388        StructLike::Unit( item ) |
389        StructLike::Struct( item ) =>
390        {
391          item_struct::field_names( item )
392        },
393        StructLike::Enum( _item ) =>
394        {
395          let iter = Box::new( self.fields().map( | field | field.ident.as_ref().unwrap() ) );
396          Some( iter )
397        },
398      }
399    }
400
401    /// Extracts the type of each field.
402    #[ must_use ]
403    pub fn field_types( & self )
404    -> BoxedIter< '_, & syn::Type >
405    // -> std::iter::Map
406    // <
407    //   std::boxed::Box< dyn _IterTrait< '_, &syn::Field > + 'a >,
408    //   impl FnMut( &'a syn::Field ) -> &'a syn::Type + 'a,
409    // >
410    {
411      Box::new( self.fields().map( move | field | &field.ty ) )
412    }
413
414    /// Extracts the name of each field.
415    // pub fn field_attrs< 'a >( &'a self ) -> impl IterTrait< 'a, &'a Vec< syn::Attribute > >
416    #[ must_use ]
417    pub fn field_attrs( & self )
418    -> BoxedIter< '_, &Vec< syn::Attribute > >
419    // -> std::iter::Map
420    // <
421    //   std::boxed::Box< dyn _IterTrait< '_, &syn::Field > + 'a >,
422    //   impl FnMut( &'a syn::Field ) -> &'a Vec< syn::Attribute > + 'a,
423    // >
424    {
425      Box::new( self.fields().map( | field | &field.attrs ) )
426    }
427
428    /// Extract the first field.
429    #[ must_use ]
430    pub fn first_field( &self ) -> Option< &syn::Field >
431    {
432      self.fields().next()
433      // .ok_or( syn_err!( self.span(), "Expects at least one field" ) )
434    }
435
436  }
437
438  //
439
440}
441
442#[ doc( inline ) ]
443#[ allow( unused_imports ) ]
444pub use own::*;
445
446/// Own namespace of the module.
447#[ allow( unused_imports ) ]
448pub mod own
449{
450  #[ allow( clippy::wildcard_imports ) ]
451  use super::*;
452  #[ doc( inline ) ]
453  pub use orphan::*;
454  #[ doc( inline ) ]
455  pub use private::
456  {
457    StructLike,
458    FieldOrVariant,
459  };
460}
461
462/// Orphan namespace of the module.
463#[ allow( unused_imports ) ]
464pub mod orphan
465{
466  #[ allow( clippy::wildcard_imports ) ]
467  use super::*;
468  #[ doc( inline ) ]
469  pub use exposed::*;
470}
471
472/// Exposed namespace of the module.
473#[ allow( unused_imports ) ]
474pub mod exposed
475{
476  #[ allow( clippy::wildcard_imports ) ]
477  use super::*;
478  pub use super::super::struct_like;
479
480  #[ doc( inline ) ]
481  pub use prelude::*;
482}
483
484/// Prelude to use essentials: `use my_module::prelude::*`.
485#[ allow( unused_imports ) ]
486pub mod prelude
487{
488  use super::*;
489}