wproc_macro/
lib.rs

1#![ warn( missing_docs ) ]
2#![ warn( missing_debug_implementations ) ]
3// #![ feature( type_name_of_val ) ]
4
5//!
6//! Tools for writing procedural macroses.
7//!
8
9// mod num;
10// mod interval;
11
12///
13/// Macro for diagnostics purpose to print both syntax tree and source code behind it.
14///
15/// # Sample
16/// ```
17/// use wproc_macro::*;
18/// use quote::quote;
19///
20/// let code = quote!( std::collections::HashMap< i32, i32 > );
21/// let tree_type = syn::parse2::< syn::Type >( code ).unwrap();
22/// tree_print!( tree_type );
23/// ```
24///
25
26#[ macro_export ]
27macro_rules! tree_print
28{
29  ( $src : expr ) =>
30  {{
31    let result = $crate::tree_export_str!( $src );
32    println!( "{}", result );
33    result
34  }};
35  ( $( $src : expr ),+ $(,)? ) =>
36  {{
37    $( $crate::tree_print!( $src ) );+
38  }};
39}
40
41///
42/// Macro for diagnostics purpose to export both syntax tree and source code behind it into string.
43///
44
45#[ macro_export ]
46macro_rules! tree_export_str
47{
48  ( $src : expr ) =>
49  {{
50    let src2 = &$src;
51    format!( "{} : {} :\n{:#?}", stringify!( $src ), quote!{ #src2 }, $src )
52  }};
53}
54
55///
56/// Macro to generate syn error either with span of a syntax tree element or with default one `proc_macro2::Span::call_site()`.
57///
58/// # Sample
59/// ```
60/// # use wproc_macro::*;
61/// syn_err!( "No attr" );
62/// # ()
63/// ```
64///
65
66#[ macro_export ]
67macro_rules! syn_err
68{
69
70  ( $msg : expr ) =>
71  {
72    syn::Error::new( proc_macro2::Span::call_site(), $msg )
73  };
74  ( _, $msg : expr ) =>
75  {
76    syn::Error::new( proc_macro2::Span::call_site(), $msg )
77  };
78  ( $span : expr, $msg : expr ) =>
79  {
80    // syn::Error::new( ( $span ).span(), $msg )
81    syn::Error::new( syn::spanned::Spanned::span( &( $span ) ), $msg )
82  };
83  ( $span : expr, $msg : expr, $( $arg : expr ),+ ) =>
84  {
85    // syn::Error::new( ( $span ).span(), format!( $msg, $( $arg ),+ ) )
86    syn::Error::new( syn::spanned::Spanned::span( &( $span ) ), format!( $msg, $( $arg ),+ ) )
87  };
88  ( _, $msg : expr, $( $arg : expr ),+ ) =>
89  {
90    syn::Error::new( proc_macro2::Span::call_site(), format!( $msg, $( $arg ),+ ) )
91  };
92
93}
94
95///
96/// Kind of container.
97///
98
99#[derive( Debug, PartialEq, Copy, Clone )]
100pub enum ContainerKind
101{
102  /// Not a container.
103  No,
104  /// Vector-like.
105  Vector,
106  /// Hash map-like.
107  HashMap,
108  /// Hash set-like.
109  HashSet,
110}
111
112/// Return kind of container specified by type.
113///
114/// Good to verify `alloc::vec::Vec< i32 >` is vector.
115/// Good to verify `std::collections::HashMap< i32, i32 >` is hash map.
116///
117/// # Sample
118/// ```
119/// use wproc_macro::*;
120/// use quote::quote;
121///
122/// let code = quote!( std::collections::HashMap< i32, i32 > );
123/// let tree_type = syn::parse2::< syn::Type >( code ).unwrap();
124/// let kind = type_container_kind( &tree_type );
125/// assert_eq!( kind, ContainerKind::HashMap );
126/// ```
127
128pub fn type_container_kind( ty : &syn::Type ) -> ContainerKind
129{
130
131  if let syn::Type::Path( path ) = ty
132  {
133    let last = &path.path.segments.last();
134    if last.is_none()
135    {
136      return ContainerKind::No
137    }
138    match last.unwrap().ident.to_string().as_ref()
139    {
140      "Vec" => { return ContainerKind::Vector }
141      "HashMap" => { return ContainerKind::HashMap }
142      "HashSet" => { return ContainerKind::HashSet }
143      _ => { return ContainerKind::No }
144    }
145  }
146  ContainerKind::No
147}
148
149/// Return kind of container specified by type. Unlike [type_container_kind] it also understand optional types.
150///
151/// Good to verify `Option< alloc::vec::Vec< i32 > >` is optional vector.
152///
153/// # Sample
154/// ```
155/// use wproc_macro::*;
156/// use quote::quote;
157///
158/// let code = quote!( Option< std::collections::HashMap< i32, i32 > > );
159/// let tree_type = syn::parse2::< syn::Type >( code ).unwrap();
160/// let ( kind, optional ) = type_optional_container_kind( &tree_type );
161/// assert_eq!( kind, ContainerKind::HashMap );
162/// assert_eq!( optional, true );
163/// ```
164
165pub fn type_optional_container_kind( ty : &syn::Type ) -> ( ContainerKind, bool )
166{
167
168  // use inspect_type::*;
169
170  if type_rightmost( ty ) == Some( "Option".to_string() )
171  {
172    let ty2 = type_parameters( ty, 0 ..= 0 ).first().map( | e | *e );
173    // inspect_type::inspect_type_of!( ty2 );
174    if ty2.is_none()
175    {
176      return ( ContainerKind::No, false )
177    }
178    let ty2 = ty2.unwrap();
179    return ( type_container_kind( ty2 ), true );
180  }
181
182  return ( type_container_kind( ty ), false );
183}
184
185/// Check is the rightmost item of path refering a type is specified type.
186///
187/// Good to verify `core::option::Option< i32 >` is optional.
188/// Good to verify `alloc::vec::Vec< i32 >` is vector.
189///
190/// # Sample
191/// ```
192/// use wproc_macro::*;
193/// use quote::quote;
194///
195/// let code = quote!( core::option::Option< i32 > );
196/// let tree_type = syn::parse2::< syn::Type >( code ).unwrap();
197/// let got = type_rightmost( &tree_type );
198/// assert_eq!( got, Some( "Option".to_string() ) );
199/// ```
200
201pub fn type_rightmost( ty : &syn::Type ) -> Option< String >
202{
203  if let syn::Type::Path( path ) = ty
204  {
205    let last = &path.path.segments.last();
206    if last.is_none()
207    {
208      return None;
209    }
210    return Some( last.unwrap().ident.to_string() );
211  }
212  None
213}
214
215use winterval::*;
216
217/// Return the specified number of parameters of the type.
218///
219/// Good to getting `i32` from `core::option::Option< i32 >` or `alloc::vec::Vec< i32 >`
220///
221/// # Sample
222/// ```
223/// use wproc_macro::*;
224/// use quote::quote;
225///
226/// let code = quote!( core::option::Option< i8, i16, i32, i64 > );
227/// let tree_type = syn::parse2::< syn::Type >( code ).unwrap();
228/// let got = type_parameters( &tree_type, 0..=2 );
229/// got.iter().for_each( | e | println!( "{}", quote!( #e ) ) );
230/// // < i8
231/// // < i16
232/// // < i32
233/// ```
234
235pub fn type_parameters< R >( ty : &syn::Type, range : R ) -> Vec< &syn::Type >
236where
237  R : std::convert::Into< Interval >
238{
239  let range = range.into();
240  if let syn::Type::Path( syn::TypePath{ path : syn::Path { ref segments, .. }, .. } ) = ty
241  {
242    let last = &segments.last();
243    if last.is_none()
244    {
245      return vec![ &ty ]
246    }
247    let args = &last.unwrap().arguments;
248    if let syn::PathArguments::AngleBracketed( ref args2 ) = args
249    {
250      let args3 = &args2.args;
251      let selected : Vec< &syn::Type > = args3
252      .iter()
253      .skip_while( | e | if let syn::GenericArgument::Type( _ ) = e { false } else { true } )
254      .skip( range.first().try_into().unwrap() )
255      .take( range.len().try_into().unwrap() )
256      .map( | e | if let syn::GenericArgument::Type( ty ) = e { ty } else { unreachable!( "Expects Type" ) } )
257      .collect();
258      return selected;
259    }
260  }
261  vec![ &ty ]
262}
263
264///
265/// For attribute like `#[former( default = 31 )]` return key `default` and value `31`,
266/// as well as syn::Meta as the last element of result tuple.
267///
268/// # Sample
269/// ``` ignore
270/// let ( key, val, meta ) = attr_pair_single( &attr )?;
271/// ```
272
273pub fn attr_pair_single( attr : &syn::Attribute ) -> Result< ( String, syn::Lit, syn::Meta ), syn::Error >
274{
275  use syn::spanned::Spanned;
276  let meta = attr.parse_meta()?;
277
278  let ( key, val );
279  match meta
280  {
281    syn::Meta::List( ref meta_list ) =>
282    match meta_list.nested.first()
283    {
284      Some( nested_meta ) => match nested_meta
285      {
286        syn::NestedMeta::Meta( meta2 ) => match meta2
287        {
288          syn::Meta::NameValue( name_value ) => // match &name_value.lit
289          {
290            if meta_list.nested.len() != 1
291            {
292              return Err( syn::Error::new( attr.span(), format!( "Expected single element of the list, but got {}", meta_list.nested.len() ) ) );
293            }
294            key = name_value.path.get_ident().unwrap().to_string();
295            val = name_value.lit.clone();
296          },
297          _ => return Err( syn::Error::new( attr.span(), "Unknown format of attribute, expected syn::Meta::NameValue( name_value )" ) ),
298        },
299        _ => return Err( syn::Error::new( attr.span(), "Unknown format of attribute, expected syn::NestedMeta::Meta( meta2 )" ) ),
300      },
301      _ => return Err( syn::Error::new( attr.span(), "Unknown format of attribute, expected Some( nested_meta )" ) ),
302    },
303    _ => return Err( syn::Error::new( attr.span(), "Unknown format of attribute, expected syn::Meta::List( meta_list )" ) ),
304  };
305
306  Ok( ( key, val, meta ) )
307}
308
309// ///
310// /// Canonize path and return it in string format.
311// ///
312//
313// pub fn path_of( syn_path : &syn::Path ) -> String
314// {
315//   // use quote::*;
316//   use syn::*;
317//   let result : String = format!( "{}", syn_path.to_token_stream() );
318//   // let result : String = format!( "{}", quote!{ #syn_path } );
319//   result
320// }
321
322//
323
324// don't delete!
325// good example of overloading to reuse
326//
327// pub use syn::spanned::Spanned;
328//
329// /// Trait to implement method span() for those structures which [module::syn](https://docs.rs/syn/latest/syn/spanned/index.html) do not have it implemented.
330//
331// pub trait Spanned2
332// {
333//   /// Returns a Span covering the complete contents of this syntax tree node, or Span::call_site() if this node is empty.
334//   fn span2( &self ) -> proc_macro2::Span;
335// }
336//
337// //
338//
339// impl Spanned2 for syn::Data
340// {
341//   fn span2( &self ) -> proc_macro2::Span
342//   {
343//     // data_fields_of( &self ).span()
344//     match self
345//     {
346//       syn::Data::Struct( syn::DataStruct { ref fields, .. } ) => fields.span(),
347//       syn::Data::Enum( syn::DataEnum { ref variants, .. } ) => variants.span(),
348//       syn::Data::Union( syn::DataUnion { ref fields, .. } ) => fields.span(),
349//     }
350//   }
351// }
352//
353// impl< T : Spanned2 > Spanned2 for &T
354// {
355//   fn span2( &self ) -> proc_macro2::Span
356//   {
357//     ( *self ).span2()
358//   }
359// }
360//
361// //
362//
363// #[ doc( hidden ) ]
364// pub struct Data< 'a, T >( &'a T );
365//
366// #[ doc( hidden ) ]
367// pub trait Span1
368// {
369//   fn act( self ) -> proc_macro2::Span;
370// }
371//
372// impl< 'a, T > Span1
373// for Data< 'a, T >
374// where T : syn::spanned::Spanned,
375// {
376//   fn act( self ) -> proc_macro2::Span
377//   {
378//     self.0.span()
379//   }
380// }
381//
382//
383// #[ doc( hidden ) ]
384// pub trait Span2
385// {
386//   fn act( self ) -> proc_macro2::Span;
387// }
388//
389// impl< 'a, T > Span2
390// for Data< 'a, T >
391// where T : Spanned2,
392// {
393//   fn act( self ) -> proc_macro2::Span
394//   {
395//     self.0.span2()
396//   }
397// }
398//
399// #[ doc( hidden ) ]
400// pub fn _span_of< T : Sized >( src : &T ) -> Data< T >
401// {
402//   Data( src )
403// }
404//
405// // fn span2_of< T : Sized >( src : &T )
406// // {
407// //   _span_of( src ).act()
408// // }
409//
410// /// Returns a Span covering the complete contents of this syntax tree node, or Span::call_site() if this node is empty.
411//
412// #[ macro_export ]
413// macro_rules! span_of
414// {
415//   ( $src : expr ) =>
416//   {
417//     $crate::_span_of( &$src ).act()
418//   }
419// }
420//
421// /// Returns a Span covering the complete contents of this syntax tree node, or Span::call_site() if this node is empty.
422// ///
423// /// Works only for items for which span is not implemented in [module::syn](https://docs.rs/syn/latest/syn/spanned/index.html). For other use macro [`span_of!`](span_of!).
424//
425// pub fn span_of< Src : Spanned2 >( src : &Src ) -> proc_macro2::Span
426// {
427//   src.span2()
428// }